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
open! Stdlib
let expand_path exts real virt =
let rec loop realfile virtfile acc =
if try Sys.is_directory realfile with _ -> false
then
let l = Array.to_list (Sys.readdir realfile) |> List.sort ~cmp:String.compare in
List.fold_left l ~init:acc ~f:(fun acc s ->
loop (Filename.concat realfile s) (Filename.concat virtfile s) acc)
else
try
let exmatch =
try
let b = Filename.basename realfile in
let i = String.rindex b '.' in
let e = String.sub b ~pos:(i + 1) ~len:(String.length b - i - 1) in
List.mem e ~set:exts
with Not_found -> List.mem "" ~set:exts
in
if List.is_empty exts || exmatch then (virtfile, realfile) :: acc else acc
with exc ->
warn "ignoring %s: %s@." realfile (Printexc.to_string exc);
acc
in
loop real virt []
let list_files name paths =
let name, virtname =
match String.lsplit2 name ~on:':' with
| Some (src, dest) ->
if String.length dest > 0 && not (Char.equal dest.[0] '/')
then failwith (Printf.sprintf "path '%s' for file '%s' must be absolute" dest src);
let virtname =
if Char.equal dest.[String.length dest - 1] '/'
then dest ^ Filename.basename src
else dest
in
src, virtname
| None ->
name, "/static/" ^ Filename.basename name
in
let name, exts =
match String.lsplit2 name ~on:'=' with
| Some (name, exts) -> name, String.split_char ~sep:',' exts
| None -> name, []
in
let file =
match Findlib.find paths name with
| None -> failwith (Printf.sprintf "file '%s' not found" name)
| Some file -> file
in
expand_path exts file virtname
let find_cmi paths base =
match
List.find_map
[ String.uncapitalize_ascii base ^ ".cmi"; String.capitalize_ascii base ^ ".cmi" ]
~f:(fun name ->
match Fs.find_in_path paths name with
| Some cmi -> Some (name, cmi)
| None -> None)
with
| Some (name, filename) -> Some (Filename.concat "/static/cmis" name, filename)
| None -> None
let instr_of_name_content prim ~name ~content =
let open Code in
let prim =
match prim with
| `create_file -> "jsoo_create_file"
| `create_file_extern -> "jsoo_create_file_extern"
in
Let
( Var.fresh ()
, Prim (Extern prim, [ Pc (NativeString name); Pc (NativeString content) ]) )
let embed_file ~name ~filename =
instr_of_name_content `create_file_extern ~name ~content:(Fs.read_file filename)
let init () = Code.(Let (Var.fresh (), Prim (Extern "caml_fs_init", [])))
let f ~prim ~cmis ~files ~paths =
let cmi_files, missing_cmis =
StringSet.fold
(fun s (acc, missing) ->
match find_cmi paths s with
| Some (name, filename) -> (name, Fs.read_file filename) :: acc, missing
| None -> acc, s :: missing)
cmis
([], [])
in
if not (List.is_empty missing_cmis)
then (
warn "Some OCaml interface files were not found.@.";
warn "Use [-I dir_of_cmis] option to bring them into scope@.";
List.iter missing_cmis ~f:(fun nm -> warn " %s@." nm));
let other_files =
List.map files ~f:(fun f ->
List.map (list_files f paths) ~f:(fun (name, filename) ->
name, Fs.read_file filename))
|> List.concat
in
List.map (other_files @ cmi_files) ~f:(fun (name, content) ->
instr_of_name_content prim ~name ~content)