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
open Eio
open Forester_prelude
open Forester_core
let path_of_dir ~env dir =
try
let path = Path.(Eio.Stdenv.fs env / (Unix.realpath dir)) in
assert (Path.is_directory path);
path
with
| Unix.Unix_error (e, _, m) ->
Reporter.fatal
IO_error
~extra_remarks: [
Asai.Diagnostic.loctextf "%s: %s" (Unix.error_message e) m
]
| Assert_failure (_, _, _) ->
Reporter.fatal
Configuration_error
~extra_remarks: [Asai.Diagnostic.loctextf "%s is not a directory" dir]
let path_of_file ~env file =
try
let path = Path.(Eio.Stdenv.fs env / (Unix.realpath file)) in
assert (Path.is_file path);
path
with
| Unix.Unix_error (e, _, m) ->
Reporter.fatal Configuration_error ~extra_remarks: [Asai.Diagnostic.loctextf "%s: %s" (Unix.error_message e) m]
let paths_of_dirs ~env =
List.map (path_of_dir ~env)
let paths_of_files ~env =
List.map (path_of_file ~env)
module NullSink : Flow.Pi.SINK with type t = unit = struct
type t = unit
let single_write _ _ = 0
let copy _ ~src: _ = ()
end
let null_sink () : Flow.sink_ty Resource.t =
let ops = Eio.Flow.Pi.sink (module NullSink) in
Eio.Resource.T ((), ops)
let ensure_context_of_path ~perm (path : _ Path.t) =
let@ path', _ = Option.iter @~ Path.split path in
Path.mkdirs ~exists_ok: true ~perm path'
let ensure_remove_file path =
try
Eio.Path.unlink path
with
| Eio.Exn.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> ()
let with_open_tmp_dir ~env kont =
let dir_name = string_of_int @@ Oo.id (object end) in
let cwd = Eio.Stdenv.cwd env in
let tmp = "_tmp" in
let tmp_path = Eio.Path.(cwd / tmp / dir_name) in
Path.mkdirs ~exists_ok: true ~perm: 0o755 tmp_path;
let@ p = Eio.Path.with_open_dir tmp_path in
let result = kont p in
Path.rmtree ~missing_ok: true tmp_path;
result
let run_process ?(quiet = false) ~env ~cwd cmd =
let mgr = Eio.Stdenv.process_mgr env in
let outbuf = Buffer.create 100 in
let errbuf = Buffer.create 100 in
let errsink = Eio.Flow.buffer_sink errbuf in
let outsink = Eio.Flow.buffer_sink outbuf in
if not quiet then
Eio.traceln "Running %s" (String.concat " " cmd);
try
Eio.Process.run ~cwd ~stdout: outsink ~stderr: errsink mgr cmd
with
| exn ->
Eio.traceln "Error: %s" (Buffer.contents errbuf);
Eio.traceln "Output: %s" (Buffer.contents outbuf);
raise exn
let file_exists path =
try
let@ _ = Eio.Path.with_open_in path in
true
with
| Eio.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> false
let try_create_dir ~cwd dname =
let (/) = Path.(/) in
if Eio.Path.is_directory (cwd / dname) then
Reporter.emit
Initialization_warning
~extra_remarks: [Asai.Diagnostic.loctextf "`%s` already exists" dname]
else
try
Eio.Path.mkdir ~perm: 0o755 (cwd / dname)
with
| exn ->
Forester_core.Reporter.emit Initialization_warning ~extra_remarks: [Asai.Diagnostic.loctextf "Failed to create directory `%s`: %a" dname Eio.Exn.pp exn]
let try_create_file ~cwd ?(content = "") fname =
let (/) = Path.(/) in
if Eio.Path.is_file (cwd / fname) then
Forester_core.Reporter.emit Initialization_warning ~extra_remarks: [Asai.Diagnostic.loctextf "`%s` already exists" fname]
else
try
Eio.Path.save ~create: (`Exclusive 0o644) (cwd / fname) content
with
| exn ->
Forester_core.Reporter.emit Initialization_warning ~extra_remarks: [Asai.Diagnostic.loctextf "Failed to create file `%s`: %a" fname Eio.Exn.pp exn]
let copy_to_dir ~env ~cwd ~source ~dest_dir =
let path = Path.(cwd / dest_dir) in
Path.mkdirs ~exists_ok: true ~perm: 0o755 path;
if Sys.unix then
run_process ~quiet: true ~env ~cwd ["cp"; "-R"; source; dest_dir]
else
run_process ~quiet: true ~env ~cwd ["xcopy"; source; dest_dir ^ "/"]