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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
type wix = {
wix_files : string list;
wix_exts : string list;
wix_out : string
}
type makeself = {
tar_extra : string list;
archive_dir : OpamFilename.Dir.t;
installer : OpamFilename.t;
description : string;
startup_script : string;
}
type cygpath_out = [ `Win | `WinAbs | `Cyg | `CygAbs ]
type install_name_tool_args = {
change_from : string;
change_to : string;
binary : OpamFilename.t;
}
type codesign_args = {
binary : OpamFilename.t;
identity : string;
force : bool;
timestamp : bool;
entitlements : string option;
}
type codesign_verify_args = {
binary : OpamFilename.t;
verbose : bool;
}
type pkgbuild_args = {
root : OpamFilename.Dir.t;
identifier : string;
version : string;
install_location : string;
scripts : OpamFilename.Dir.t option;
output : OpamFilename.t;
}
type productbuild_args = {
package : OpamFilename.t;
output : OpamFilename.t;
}
type touch_args = {
mtime : string;
file : string;
}
type patchelf_args =
| Set_rpath of {rpath: string; binary: OpamFilename.t}
type _ command =
| Which : string command
| Ldd : string command
| Otool : string command
| Cygpath : (cygpath_out * string) command
| Wix : wix command
| Makeself : makeself command
| Chmod : (int * OpamFilename.t) command
| InstallNameTool : install_name_tool_args command
| Codesign : codesign_args command
| CodesignVerify : codesign_verify_args command
| Pkgbuild : pkgbuild_args command
| Productbuild : productbuild_args command
| Patchelf : patchelf_args command
| Touch : touch_args command
exception System_error of string
let call_inner : type a. a command -> a -> string * string list =
fun command args -> match command, args with
| Which, (path : string) ->
"which", [ path ]
| Ldd, path ->
"ldd", [ path ]
| Otool, path ->
"otool", [ "-L"; path ]
| Chmod, (perm, file) ->
"chmod", [ string_of_int perm; OpamFilename.to_string file ]
| Cygpath, (out, path) ->
let opts = match out with
| `Win -> "-w"
| `WinAbs -> "-wa"
| `Cyg -> "-u"
| `CygAbs -> "-ua"
in
"cygpath", [ opts; path ]
| Wix, { wix_files; wix_exts; wix_out } ->
let wix = "wix.exe" in
let args = "build" ::
List.flatten (List.map (fun e -> ["-ext"; e]) wix_exts)
@ wix_files @ ["-o"; wix_out; "-pdbtype"; "none"]
in
wix, args
| Makeself
, { ; archive_dir; installer; description; startup_script } ->
let makeself = "makeself" in
let args =
[
"--tar-extra";
String.concat " " tar_extra;
OpamFilename.Dir.to_string archive_dir;
OpamFilename.to_string installer;
Printf.sprintf "%S" description;
startup_script;
]
in
makeself, args
| InstallNameTool, { change_from; change_to; binary } ->
let path = OpamFilename.to_string binary in
"install_name_tool", [ "-change"; change_from; change_to; path ]
| Codesign, { binary; identity; force; timestamp; entitlements } ->
let path = OpamFilename.to_string binary in
let args = [ "-s"; identity ] in
let args = if force then args @ [ "-f" ] else args in
let args = if timestamp then args @ [ "--timestamp" ] else args in
let args = match entitlements with
| Some ent_path -> args @ [ "--entitlements"; ent_path ]
| None -> args
in
"codesign", args @ [ path ]
| CodesignVerify, { binary; verbose } ->
let path = OpamFilename.to_string binary in
let args = [ "--verify" ] @ (if verbose then [ "--verbose" ] else []) @ [ path ] in
"codesign", args
| Pkgbuild, { root; identifier; version; install_location; scripts; output } ->
let args = [
"--root"; OpamFilename.Dir.to_string root;
"--identifier"; identifier;
"--version"; version;
"--install-location"; install_location;
] in
let args = match scripts with
| Some dir -> args @ [ "--scripts"; OpamFilename.Dir.to_string dir ]
| None -> args
in
"pkgbuild", args @ [ OpamFilename.to_string output ]
| Productbuild, { package; output } ->
"productbuild", [
"--package"; OpamFilename.to_string package;
OpamFilename.to_string output
]
| Patchelf, (Set_rpath {rpath; binary}) ->
"patchelf", ["--set-rpath"; rpath; OpamFilename.to_string binary]
| Touch, { mtime; file } ->
"touch", [ "-t"; mtime; file ]
let gen_command_tmp_dir cmd =
Printf.sprintf "%s-%06x" (Filename.basename cmd) (Random.int 0xFFFFFF)
let print_result_and_error cmd result =
Printf.eprintf "%s\n%!" (OpamProcess.string_of_result result);
raise (System_error (Printf.sprintf "Error during: %s" cmd))
let call : type a. a command -> a -> string list =
fun command arguments ->
let cmd, args = call_inner command arguments in
let name = gen_command_tmp_dir cmd in
let result = OpamProcess.run @@ OpamSystem.make_command ~name cmd args in
let out = if OpamProcess.is_failure result then
print_result_and_error cmd result
else
result.OpamProcess.r_stdout
in
OpamProcess.cleanup result;
out
let call_unit : type a. a command -> a -> unit =
fun command arguments ->
let cmd, args = call_inner command arguments in
let name = gen_command_tmp_dir cmd in
let result = OpamProcess.run @@ OpamSystem.make_command ~name cmd args in
(if OpamProcess.is_failure result then
print_result_and_error cmd result);
OpamProcess.cleanup result
let call_list : type a. (a command * a) list -> unit =
fun commands ->
let cmds = List.map (fun (cmd,args) ->
let cmd, args = call_inner cmd args in
let name = gen_command_tmp_dir cmd in
OpamSystem.make_command ~name cmd args) commands
in
match OpamProcess.Job.(run @@ of_list cmds) with
| Some (cmd,result) ->
print_result_and_error cmd.cmd result
| _ -> ()
let cyg_win_path out path =
match call Cygpath (out,path) with
| line :: _ -> String.trim line
| _ -> raise @@ System_error "cygpath raised an error. \
You probably chose a file with invalid format as your binary."
let normalize_path path =
match Sys.os_type with
| "Unix" -> path
| "Win32" -> cyg_win_path `WinAbs path
| "Cygwin" -> cyg_win_path `CygAbs path
| _ ->
let msg = Printf.sprintf "Unsupported os type %s" Sys.os_type in
raise (System_error msg)
let path_dir_str path =
if Sys.cygwin
then OpamFilename.Dir.to_string path
else
let path = OpamFilename.Dir.to_string path in
String.split_on_char ':' path
|> List.tl |> String.concat ":" |> String.split_on_char '\\'
|> String.concat "/"
let path_str path =
if Sys.win32 then
let path = OpamFilename.to_string path in
String.split_on_char ':' path
|> List.tl |> String.concat ":" |> String.split_on_char '\\'
|> String.concat "/"
else
OpamFilename.to_string path
open OpamTypes
module type FILE_INTF = sig
type t
val name : string
val to_string : t -> string
val of_string : string -> t
val (/) : dirname -> string -> t
val copy : src:t -> dst:t -> unit
val exists : t -> bool
val basename : t -> basename
end
module DIR_IMPL : FILE_INTF
with type t = OpamFilename.Dir.t = struct
include OpamFilename.Dir
let name = "directory"
let (/) = OpamFilename.Op.(/)
let copy = OpamFilename.copy_dir
let exists = OpamFilename.exists_dir
let basename = OpamFilename.basename_dir
end
module FILE_IMPL : FILE_INTF
with type t = OpamFilename.t = struct
include OpamFilename
let name = "file"
let (/) = OpamFilename.Op.(//)
let copy = OpamFilename.copy
let exists = OpamFilename.exists
let basename = OpamFilename.basename
end
let resolve_path_aux env path =
let expanded_path = OpamFilter.expand_string env path in
if not @@ Filename.is_relative expanded_path
then expanded_path
else begin
OpamConsole.warning
"Specified in config path %s is relative. Searching in current directory..."
(OpamConsole.colorise `bold path);
Filename.concat (Sys.getcwd ()) expanded_path
end
let resolve_path (type a) env
(module F : FILE_INTF with type t = a) path =
F.of_string @@ resolve_path_aux env path
let resolve_file_path env path =
resolve_path env (module FILE_IMPL) path
let maybe_exe =
match OpamStd.Sys.os () with
| OpamStd.Sys.Win32
| OpamStd.Sys.Cygwin ->
fun ~dir ~path ->
let path_exe = path ^ ".exe" in
let fexe = OpamFilename.Op.(dir // path_exe) in
if OpamFilename.exists fexe then path_exe else path
| _ ->
fun ~dir:_ ~path -> path