[1] | 1 | module Validation = struct
|
---|
| 2 | let empty = []
|
---|
| 3 |
|
---|
| 4 | let (&>) report = function None -> report | Some msg -> msg :: report
|
---|
| 5 | let (&&>) report = function [] -> report | msgs -> msgs @ report
|
---|
| 6 |
|
---|
| 7 | let check ok msg = if ok then None else Some msg
|
---|
| 8 |
|
---|
| 9 | let file_exists ?(msg=(fun s -> (s ^ " is not a file"))) ?(parent_dir=Fpath.v ".") file =
|
---|
| 10 | let str = Fpath.(to_string (parent_dir // file)) in
|
---|
| 11 | check (Sys.file_exists str) (msg str)
|
---|
| 12 |
|
---|
| 13 | let is_directory ?(msg=(fun s -> (s ^ " is not a directory"))) dir =
|
---|
| 14 | let str = Fpath.to_string dir in
|
---|
| 15 | check (Sys.file_exists str && Sys.is_directory str) (msg str)
|
---|
| 16 |
|
---|
| 17 | let files_exist ?(msg=(fun s -> (s ^ " is not a file"))) ?(parent_dir=Fpath.v ".") files =
|
---|
| 18 | let f report file = report &> file_exists ~msg ~parent_dir file in
|
---|
| 19 | List.fold_left f empty files
|
---|
| 20 |
|
---|
| 21 | let terminate_when_invalid ?(print_error=true) =
|
---|
| 22 | let error i msg = prerr_endline ("Error " ^ string_of_int i ^ ": " ^ msg) in
|
---|
| 23 | function
|
---|
| 24 | | [] -> ()
|
---|
| 25 | | msgs -> if print_error then List.iteri error (List.rev msgs); exit 1
|
---|
| 26 | end
|
---|
| 27 |
|
---|
| 28 | module Path = struct
|
---|
| 29 | let of_string str =
|
---|
| 30 | if Sys.file_exists str then
|
---|
| 31 | match Fpath.v str with
|
---|
| 32 | | path -> Ok path
|
---|
| 33 | | exception (Invalid_argument msg) -> Error ("Invalid path " ^ msg)
|
---|
| 34 | else Error (str ^ " not found")
|
---|
| 35 |
|
---|
| 36 | let path_exists x = Fpath.to_string x |> Sys.file_exists
|
---|
| 37 |
|
---|
| 38 | let conventional_paths =
|
---|
| 39 | let paths =
|
---|
| 40 | try [ ".logarion"; Sys.getenv "HOME" ^ "/.config/logarion"; "/etc/logarion" ]
|
---|
| 41 | with Not_found -> [ ".logarion"; "/etc/logarion" ]
|
---|
| 42 | in
|
---|
| 43 | List.map Fpath.v paths
|
---|
| 44 |
|
---|
| 45 | let with_file ?(conventional_paths=conventional_paths) config_file =
|
---|
| 46 | let (//) = Fpath.(//) in
|
---|
| 47 | let basepath = Fpath.v config_file in
|
---|
| 48 | let existing dir = path_exists (dir // basepath) in
|
---|
| 49 | try Ok (List.find existing conventional_paths // basepath)
|
---|
| 50 | with Not_found -> Error (config_file ^ " not found in: " ^ String.concat ", " (List.map Fpath.to_string conventional_paths))
|
---|
| 51 | end
|
---|
| 52 |
|
---|
| 53 | let with_default default = function Some x -> x | None -> default
|
---|
| 54 |
|
---|
| 55 | let with_default_paths default =
|
---|
| 56 | function Some ss -> List.map Fpath.v ss | None -> default
|
---|
| 57 |
|
---|
| 58 | let mandatory = function Some x -> x | None -> failwith "undefined mandatory setting"
|
---|
| 59 |
|
---|
| 60 | let (&>) a b = match a with Ok x -> b x | Error e -> Error e
|
---|
| 61 |
|
---|
| 62 | module type Store = sig
|
---|
| 63 | type t
|
---|
| 64 | val from_path : Fpath.t -> (t, string) result
|
---|
| 65 | end
|
---|
| 66 |
|
---|
| 67 | module Make (S : Store) = struct
|
---|
| 68 | include S
|
---|
| 69 |
|
---|
| 70 | let of_path path = S.from_path path
|
---|
| 71 |
|
---|
| 72 | let (&>) = (&>)
|
---|
| 73 |
|
---|
| 74 | let to_record converter = function
|
---|
| 75 | | Ok store -> converter store
|
---|
| 76 | | Error s -> Error s
|
---|
| 77 |
|
---|
| 78 | let to_record_or_exit ?(print_error=true) ?(validator=(fun _cfg -> [])) converter store_result =
|
---|
| 79 | match to_record converter store_result with
|
---|
| 80 | | Ok cfg -> Validation.terminate_when_invalid (validator cfg); cfg
|
---|
| 81 | | Error s -> if print_error then prerr_endline s; exit 1
|
---|
| 82 | end
|
---|