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
|
(* febootstrap 3
* Copyright (C) 2009-2010 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
open Unix
open Printf
let (//) = Filename.concat
let file_exists name =
try access name [F_OK]; true
with Unix_error _ -> false
let dir_exists name =
try (stat name).st_kind = S_DIR
with Unix_error _ -> false
let rec uniq ?(cmp = Pervasives.compare) = function
| [] -> []
| [x] -> [x]
| x :: y :: xs when cmp x y = 0 ->
uniq ~cmp (x :: xs)
| x :: y :: xs ->
x :: uniq ~cmp (y :: xs)
let sort_uniq ?(cmp = Pervasives.compare) xs =
let xs = List.sort cmp xs in
let xs = uniq ~cmp xs in
xs
let rec input_all_lines chan =
try let line = input_line chan in line :: input_all_lines chan
with End_of_file -> []
let run_command_get_lines cmd =
let chan = open_process_in cmd in
let lines = input_all_lines chan in
let stat = close_process_in chan in
(match stat with
| WEXITED 0 -> ()
| WEXITED i ->
eprintf "febootstrap: command '%s' failed (returned %d), see earlier error messages\n" cmd i;
exit i
| WSIGNALED i ->
eprintf "febootstrap: command '%s' killed by signal %d" cmd i;
exit 1
| WSTOPPED i ->
eprintf "febootstrap: command '%s' stopped by signal %d" cmd i;
exit 1
);
lines
let run_command cmd =
if Sys.command cmd <> 0 then (
eprintf "febootstrap: %s: command failed, see earlier errors\n" cmd;
exit 1
)
let run_python code args =
let cmd = sprintf "python -c %s %s"
(Filename.quote code)
(String.concat " " (List.map Filename.quote args)) in
if Sys.command cmd <> 0 then (
eprintf "febootstrap: external python program failed, see earlier error messages\n";
exit 1
)
let tmpdir () =
let chan = open_in "/dev/urandom" in
let data = String.create 16 in
really_input chan data 0 (String.length data);
close_in chan;
let data = Digest.to_hex (Digest.string data) in
(* Note this is secure, because if the name already exists, even as a
* symlink, mkdir(2) will fail.
*)
let tmpdir = Filename.temp_dir_name // sprintf "febootstrap%s.tmp" data in
Unix.mkdir tmpdir 0o700;
at_exit
(fun () ->
let cmd = sprintf "rm -rf %s" (Filename.quote tmpdir) in
ignore (Sys.command cmd));
tmpdir
let rec find s sub =
let len = String.length s in
let sublen = String.length sub in
let rec loop i =
if i <= len-sublen then (
let rec loop2 j =
if j < sublen then (
if s.[i+j] = sub.[j] then loop2 (j+1)
else -1
) else
i (* found *)
in
let r = loop2 0 in
if r = -1 then loop (i+1) else r
) else
-1 (* not found *)
in
loop 0
let rec string_split sep str =
let len = String.length str in
let seplen = String.length sep in
let i = find str sep in
if i = -1 then [str]
else (
let s' = String.sub str 0 i in
let s'' = String.sub str (i+seplen) (len-i-seplen) in
s' :: string_split sep s''
)
let string_prefix p str =
let len = String.length str in
let plen = String.length p in
len >= plen && String.sub str 0 plen = p
let path_prefix p path =
let len = String.length path in
let plen = String.length p in
path = p || (len > plen && String.sub path 0 (plen+1) = (p ^ "/"))
let rec filter_map f = function
| [] -> []
| x :: xs ->
let x = f x in
match x with
| None -> filter_map f xs
| Some x -> x :: filter_map f xs
|