Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
EnvMods.ml1 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 150(* Vaguely like cmake's or opam's environment modifications. *) type t = { additions : (string * string) list; removals : string list; path_prepends : (string * string) list; } let empty = { additions = []; removals = []; path_prepends = [] } let additions { additions; _ } = additions let removals { removals; _ } = removals let path_prepends { path_prepends; _ } = List.rev path_prepends (** [cohere mods] removes all additions and path prepends that are in the removals list. *) let cohere t = { t with additions = List.fold_left (fun acc (name, value) -> if List.mem name t.removals then acc else (name, value) :: acc) [] t.additions; path_prepends = List.rev (* maintain order *) (List.fold_left (fun acc (name, value) -> if List.mem name t.removals then acc else (name, value) :: acc) [] t.path_prepends); } let list (type a) (pp_v : Format.formatter -> a -> unit) (ppf : Format.formatter) (l : a list) = let inner = Format.pp_print_list ~pp_sep:(fun ppf () -> Format.fprintf ppf ";@ ") pp_v in Format.fprintf ppf "@[[@ %a]@]" inner l let pp ppf t = let t' = cohere t in Format.fprintf ppf "@[@[<hov 2>additions@ %a@]@;\ @[<hov 2>removals@ %a@]@;\ @[<hov 2>prepends@ %a@]@]" (list (fun fmt (name, value) -> Format.fprintf fmt "+%s=%s" name value)) (additions t') (list (fun fmt name -> Format.fprintf fmt "-%s" name)) (removals t') (list (fun fmt (name, value) -> Format.fprintf fmt "<%s=%s" name value)) (path_prepends t') let show t = Format.asprintf "%a" pp t let add_one ~compare (name, value) additions = match List.find_opt (fun (name', _value) -> compare name' name = 0) additions with | Some _ -> additions | None -> (name, value) :: additions let add name value t = let a' = add_one ~compare:String.compare (name, value) t.additions in { t with additions = a' } let prepend_path name value t = { t with path_prepends = (name, value) :: t.path_prepends } let merge_removals a b = a @ b |> List.sort String.compare let remove_names names t = let r' = merge_removals names t.removals in { t with removals = r' } let union a b = { additions = List.fold_right (add_one ~compare:String.compare) a.additions b.additions; path_prepends = a.path_prepends @ b.path_prepends; removals = merge_removals a.removals b.removals; } module CaseSensitiveMap = Map.Make (String) let insensitive_compare a b = String.compare (String.uppercase_ascii a) (String.uppercase_ascii b) module CaseInsensitiveMap = Map.Make (struct type t = string let compare = insensitive_compare end) module type CasedMap = Map.S with type key = string let add_from_env_if_present ~win32 names env_bindings t = (* Construct a case-sensitive map for Unix or case-insensitive map for Windows *) let map_module, compare = if win32 then ((module CaseInsensitiveMap : CasedMap), insensitive_compare) else ((module CaseSensitiveMap : CasedMap), String.compare) in let module M = (val map_module) in let env = List.fold_left (fun map (name, value) -> M.add name value map) M.empty env_bindings in (* add *) let a' = List.fold_left (fun acc name -> match M.find_opt name env with | None -> acc | Some value -> add_one ~compare (name, value) acc) t.additions names in { t with additions = a' } let apply ~win32 t env_bindings = (* Construct a case-sensitive map for Unix or case-insensitive map for Windows *) let map_module = if win32 then (module CaseInsensitiveMap : CasedMap) else (module CaseSensitiveMap : CasedMap) in let module M = (val map_module) in let env = List.fold_left (fun map (name, value) -> M.add name value map) M.empty env_bindings in (* Do the apply *) let t' = cohere t in let pathsep = if win32 then ";" else ":" in let remove_from_env ~envnames env = List.fold_left (fun env' name -> M.remove name env') env envnames in let env_after_adds = List.fold_left (fun env' (name, value) -> M.add name value env') env t'.additions in let env_after_path_prepends = List.fold_right (* maintain order *) (fun (name, value) env' -> match M.find_opt name env' with | None -> M.add name value env' | Some value' -> M.add name (value ^ pathsep ^ value') env') t'.path_prepends env_after_adds in let env' = remove_from_env ~envnames:t'.removals env_after_path_prepends in M.bindings env'