Source file odoc_file.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# 1 "src/odoc/odoc_file.cppo.ml"
open Odoc_utils
open ResultMonad
open Odoc_model
type unit_content = Lang.Compilation_unit.t
type content =
| Page_content of Lang.Page.t
| Impl_content of Lang.Implementation.t
| Unit_content of unit_content
| Asset_content of Lang.Asset.t
type t = { content : content; warnings : Odoc_model.Error.t list }
(** Written at the top of the files. Checked when loading. *)
# 43 "src/odoc/odoc_file.cppo.ml"
let compression_supported = false
let output_value oc v = Marshal.to_channel oc v []
let input_value ic = Marshal.from_channel ic
# 48 "src/odoc/odoc_file.cppo.ml"
let magic = "ODOC"
let magic_version_uncompressed = "3.2.1-177-g63708bb"
let magic_version =
magic_version_uncompressed ^ if compression_supported then "-zstd" else ""
let readable_version version =
version = magic_version || version = magic_version_uncompressed
(** Exceptions while saving are allowed to leak. *)
let save_ file f =
let len = String.length magic_version in
if len > 255 then
failwith
(Printf.sprintf
"Magic version string %S is too long, must be <= 255 characters"
magic_version);
Fs.Directory.mkdir_p (Fs.File.dirname file);
Io_utils.with_open_out_bin (Fs.File.to_string file) (fun oc ->
output_string oc magic;
output_binary_int oc len;
output_string oc magic_version;
f oc)
let save_unit file (root : Root.t) (t : t) =
save_ file (fun oc ->
output_value oc root;
output_value oc t)
let save_page file ~warnings page =
let dir = Fs.File.dirname file in
let base = Fs.File.(to_string @@ basename file) in
let file =
if Astring.String.is_prefix ~affix:"page-" base then file
else Fs.File.create ~directory:dir ~name:("page-" ^ base)
in
save_unit file page.Lang.Page.root { content = Page_content page; warnings }
let save_impl file ~warnings impl =
let dir = Fs.File.dirname file in
let base = Fs.File.(to_string @@ basename file) in
let file =
if Astring.String.is_prefix ~affix:"impl-" base then file
else Fs.File.create ~directory:dir ~name:("impl-" ^ base)
in
save_unit file impl.Lang.Implementation.root
{ content = Impl_content impl; warnings }
let save_asset file ~warnings asset =
let dir = Fs.File.dirname file in
let base = Fs.File.(to_string @@ basename file) in
let file =
if Astring.String.is_prefix ~affix:"asset-" base then file
else Fs.File.create ~directory:dir ~name:("asset-" ^ base)
in
let t = { content = Asset_content asset; warnings } in
save_unit file asset.root t
let save_unit file ~warnings m =
save_unit file m.Lang.Compilation_unit.root
{ content = Unit_content m; warnings }
let load_ file f =
let file = Fs.File.to_string file in
let check_exists () =
if Sys.file_exists file then Ok ()
else Error (`Msg (Printf.sprintf "File %s does not exist" file))
in
let check_magic ic =
let actual_magic = really_input_string ic (String.length magic) in
if actual_magic = magic then Ok ()
else
Error
(`Msg
(Printf.sprintf "%s has invalid magic %S, expected %S\n%!" file
actual_magic magic))
in
let version_length ic () =
let len = input_binary_int ic in
if len > 0 && len <= 255 then Ok len
else Error (`Msg (Printf.sprintf "%s has invalid version length" file))
in
let check_version ic len =
let actual_magic = really_input_string ic len in
if readable_version actual_magic then Ok ()
else
let msg =
Printf.sprintf "%s has invalid version %S, expected %S\n%!" file
actual_magic magic_version
in
Error (`Msg msg)
in
check_exists () >>= fun () ->
Io_utils.with_open_in_bin file @@ fun ic ->
try
check_magic ic >>= version_length ic >>= check_version ic >>= fun () -> f ic
with exn ->
let msg =
Printf.sprintf "Error while unmarshalling %S: %s\n%!" file
(match exn with Failure s -> s | _ -> Printexc.to_string exn)
in
Error (`Msg msg)
let load file =
load_ file (fun ic ->
let _root = input_value ic in
Ok (input_value ic))
(** The root is saved separately in the files to support this function. *)
let load_root file =
load_ file (fun ic ->
let root = input_value ic in
Ok root)
let save_index dst idx = save_ dst (fun oc -> output_value oc idx)
let load_index file = load_ file (fun ic -> Ok (input_value ic))
let dst idx = save_ dst (fun oc -> output_value oc idx)
let file = load_ file (fun ic -> Ok (input_value ic))