package bistro

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file misc.ml

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
open Core

let digest x =
  Md5.to_hex (Md5.digest_string (Marshal.to_string x []))

let quote s = sprintf "'%s'" s

open Lwt

let exec_exn cmd =
  Lwt_process.exec ("", cmd) >>= function
  | WEXITED 0 -> Lwt.return ()
  | _ -> Lwt.fail_with (String.concat ~sep:" " @@ Array.to_list cmd)

let mv src dst =
  exec_exn [| "mv" ; src ; dst |]

let remove_if_exists fn =
  match Sys.file_exists fn with
  | `Yes ->
    exec_exn [| "rm" ; "-rf" ; fn |]
  | `No | `Unknown ->
    Lwt.return ()

let redirection filename =
  let flags = Unix.([O_APPEND ; O_CREAT ; O_WRONLY]) in
  Lwt_unix.openfile filename flags 0o640 >>= fun fd ->
  Lwt.return (`FD_move (Lwt_unix.unix_file_descr fd))

let touch dst =
  exec_exn [| "touch" ; dst |]

let docker_chown ~path ~uid =
  let cmd = Docker.chown_command ~path ~uid in
  Lwt_process.(exec (shell cmd)) >|= ignore

let absolutize p =
  if Filename.is_absolute p then p
  else Filename.concat (Sys.getcwd ()) p

let relativize ~from p =
  let open Path in
  make_relative ~from p
  |> to_string

let ln from _to_ =
  let cmd = [|
    "ln" ; "-s" ; absolutize from ; absolutize _to_ ;
  |]
  in
  exec_exn cmd

let cp from _to_ =
  let cmd = [|
    "cp" ; "-r" ; absolutize from ; absolutize _to_ ;
  |]
  in
  exec_exn cmd

let files_in_dir dir =
  Lwt_unix.files_of_directory dir
  |> Lwt_stream.to_list
  >|= List.filter ~f:(function
      | "." | ".." -> false
      | _ -> true
    )
  >|= List.sort ~compare:String.compare

let glob ~type_selection ~pattern root =
  let open Rresult.R.Infix in
  let elements = match type_selection with
    | None -> `Any
    | Some `File -> `Files
    | Some `Directory -> `Dirs
  in
  Bos.OS.Path.fold ~elements List.cons [] [Fpath.v root] >>= fun xs ->
  let xs = List.map ~f:Fpath.to_string xs in
  let res = match pattern with
    | None -> xs
    | Some pattern ->
      let re = Re.compile (Re.Glob.glob pattern) in
      List.filter xs ~f:(Re.execp re)
  in
  Ok res

let du fn =
  let open Bos in
  let open Rresult in
  let du_cmd = Cmd.(v "du" % "-sb" % p (Fpath.v fn)) in
  match OS.Cmd.(run_out du_cmd |> to_lines) with
  | Ok [ line ] -> (
      match String.lsplit2 line ~on:'\t' with
      | Some (size, _) ->
        (
          try Ok (Int.of_string size)
          with _ -> R.error_msg "not an integer"
        )
      | None -> R.error_msg "unexpected syntax"
    )
  | Ok _ -> R.error_msg "expected exactly one line"
  | Error _ as e -> e

let rm_rf fn =
  let open Bos in
  let rm_cmd = Cmd.(v "rm" % "-rf" % p (Fpath.v fn)) in
  OS.Cmd.run rm_cmd

let rec waitpid pid =
  try Lwt_unix.waitpid [] pid
  with Unix.Unix_error (Unix.EINTR, _, _) -> waitpid pid

let load_value fn =
  In_channel.with_file fn ~f:Marshal.from_channel

let save_value ~data fn =
  Out_channel.with_file fn ~f:(fun oc -> Marshal.to_channel oc data [])
OCaml

Innovation. Community. Security.