summaryrefslogtreecommitdiffstats
path: root/febootstrap_utils.ml
blob: 22657534b036919a7f98467acb39c45502ddbcb1 (plain)
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
(* 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;

  (* Only remove the directory if --save-temps was *not* specified. *)
  if not Febootstrap_cmdline.save_temps then
    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