struct
  let (//) = Filename.concat

  let env s =
    try Some (Sys.getenv s) with _ -> None

  let failwithf fmt = ksprintf failwith fmt

  let succeed s =
    match Sys.command s with
    | 0 -> ()
    | other -> failwithf "Command %S did not succeed: %d" s other
  let succeedf fmt= ksprintf succeed fmt

  let all_files dir =
    Sys.readdir dir |> Array.to_list
    |> List.filter_map ~f:(fun d ->
        let p = dir // d in
        if Sys.is_directory p then None else Some p)

  let read_file f =
    let i = open_in f in
    let buf = Buffer.create 42 in
    let rec loop () =
      try Buffer.add_channel buf i 1; loop () with _ -> () in
    loop ();
    close_in i;
    Buffer.contents buf

  let write_file f ~content =
    let o = open_out f in
    output_string o content;
    close_out o

  let parse_list_of_substitutions s =
    let subs = String.split ~on:(`Character ',') s in
    List.filter_map subs ~f:(fun sub ->
        match String.split ~on:(`Character ':') (String.strip sub) with
        | [one; two] -> Some (one, two)
        | other -> None
      )

end