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
open Odoc_model
open Or_error
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. *)
let magic = "odoc-%%VERSION%%"
(** Exceptions while saving are allowed to leak. *)
let save_ file f =
Fs.Directory.mkdir_p (Fs.File.dirname file);
let oc = open_out_bin (Fs.File.to_string file) in
output_string oc magic;
f oc;
close_out oc
let save_unit file (root : Root.t) (t : t) =
save_ file (fun oc ->
Marshal.to_channel oc root [];
Marshal.to_channel 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
(if Sys.file_exists file then Ok file
else Error (`Msg (Printf.sprintf "File does not exist")))
>>= fun file ->
let ic = open_in_bin file in
let res =
try
let actual_magic = really_input_string ic (String.length magic) in
if actual_magic = magic then f ic
else
let msg =
Printf.sprintf "%s: invalid magic number %S, expected %S\n%!" file
actual_magic magic
in
Error (`Msg msg)
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)
in
close_in ic;
res
let load file =
load_ file (fun ic ->
let _root = Marshal.from_channel ic in
Ok (Marshal.from_channel ic))
(** The root is saved separately in the files to support this function. *)
let load_root file =
load_ file (fun ic ->
let root = Marshal.from_channel ic in
Ok root)
let save_index dst idx = save_ dst (fun oc -> Marshal.to_channel oc idx [])
let load_index file = load_ file (fun ic -> Ok (Marshal.from_channel ic))
let dst idx = save_ dst (fun oc -> Marshal.to_channel oc idx [])
let file = load_ file (fun ic -> Ok (Marshal.from_channel ic))