package uniq
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A library which introspect and infer dependencies via codept, ocamlfind and opam
Install
dune-project
Dependency
Authors
Maintainers
Sources
uniq-0.1.0.tbz
sha256=998588f1053cf03161a4bded6d7f8068c88de497e77fc0bbca81a5234fa444d5
sha512=53d4ee5ad8c01e19a2e1fbda86266768d118f78566b82f0c736338ce2c12258185a5f4dbb90bf0da37a7528098266ec81861bdcfea29e55daa3122a4f3a1daca
doc/src/uniq.solver/uniq_solver.ml.html
Source file uniq_solver.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 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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167let src = Logs.Src.create "uniq.solver" module Log = (val Logs.src_log src : Logs.LOG) module MSet = Set.Make (Modname) module Info = Uniq_info module Digest = Uniq_digest let error_msgf fmt = Fmt.kstr (fun msg -> Error (`Msg msg)) fmt let somef fmt = Fmt.kstr Stdlib.Option.some fmt type cfg = { stdlib: bool ; recurse: bool ; exclude: Fpath.t list ; ignore: MSet.t ; forbid: MSet.t } type private_module = Modname.t * Uniq_digest.t option let absolute = (* NOTE(dinosaure): [Fpath.v] should be fine! *) let cwd = Fpath.v (Sys.getcwd ()) in fun path -> let path = if Fpath.is_rel path then Fpath.(cwd // path) else path in Fpath.normalize path let config ?(stdlib = true) ?(recurse = true) ?(exclude = []) ?(ignore = []) ?(forbid = []) () = let ignore = MSet.of_list ignore in let forbid = MSet.of_list forbid in let exclude = List.map absolute exclude in { stdlib; recurse; exclude; ignore; forbid } let to_ignore ~cfg modname = MSet.mem modname cfg.ignore type providers = ?crc:Digest.t -> Modname.t -> Info.t option type disambiguate = Modname.t -> Info.t list -> Info.t exception Multiple_solutions of Modname.t * Digest.t option * Info.t list let () = let dummy = String.make (Digest.length * 2) '-' in Printexc.register_printer @@ function | Multiple_solutions (modname, crc, infos) -> somef "Multiple solutions for %a (%a): @[<hov>%a@]" Modname.pp modname Fmt.(option ~none:(const string dummy) Digest.pp) crc Fmt.(list ~sep:(any ";@ ") Info.pp) infos | _ -> None (* NOTE(dinosaure): The purpose of this function is to reclassify dependencies based on what has just been injected. For example, adding [cmdliner.cmi] means that the [Cmd] module and the [Term] module can be resolved without requiring any further information. *) let prune ?disambiguate infos modules = let fn0 (m, crc) (p, crc') = match (crc, crc') with | Some crc, Some crc' when Digest.equal crc crc' -> let part = Info.Path.singleton m in Info.Path.is_a_part ~part p | Some _, Some _ -> false | Some _, None -> false | None, Some _ | None, None -> let part = Info.Path.singleton m in Info.Path.is_a_part ~part p in let fn1 (m, crc) info = let exports = Info.exports info in let found = List.exists (fn0 (m, crc)) exports in if found then Some info else None in let take (infos, _, rem) crc m solution = Log.debug (fun mf -> mf "take %a for %a" Info.pp solution Modname.pp m); let location = Info.location solution in let fn info = Info.qualify info ~location ?crc `Intf m in (List.map fn infos, true, rem) in let fn0 (infos, progress, rem) (m, crc) = match List.filter_map (fn1 (m, crc)) infos with | [ solution ] -> take (infos, progress, rem) crc m solution | _ :: _ as solutions -> ( (* The same module is exported by several collected interfaces (e.g. [Term] by both [cmdliner] and [mnotty]): defer to [disambiguate] when the caller provides one, otherwise report the ambiguity. *) match disambiguate with | Some choose -> take (infos, progress, rem) crc m (choose m solutions) | None -> raise (Multiple_solutions (m, crc, solutions))) | [] -> (infos, progress, (m, crc) :: rem) in let rec go infos modules = let infos, progress, modules = List.fold_left fn0 (infos, false, []) modules in if progress then go infos modules else (infos, modules) in go infos modules let missing_intfs infos = List.concat_map (fun info -> fst (Info.missing info)) infos let not_in_forbidden_modules cfg modules = match List.filter (fun (m, _) -> MSet.mem m cfg.forbid) modules with | [] -> Ok () | forbidden -> error_msgf "@[<hov>the project requires forbidden module(s): %a@]" Fmt.(list ~sep:(any ",@ ") Modname.pp) (List.map fst forbidden) let sort = List.sort_uniq (fun (a, _) (b, _) -> Modname.compare a b) let solve_intfs ?disambiguate ~cfg:({ recurse; exclude; stdlib; _ } as cfg) ~providers dirs = let ( let* ) = Result.bind in let fn = Uniq_resolve.Src.sources ~recurse ~exclude in let dirs = List.map absolute dirs in let dirs = List.map Fpath.to_dir_path dirs in let srcs = List.map fn dirs in let fn (infos, progress, rem) (m, crc) = begin match providers ?crc m with | None -> (infos, progress, (m, crc) :: rem) | Some solution when List.exists (Info.equal solution) infos = false -> let location = Info.location solution in (* NOTE(dinosaure): here, [crc] is still the one from what it miss but, with the solution, we can actually fix it with what [solution] gives to us. We can observe some requalification from [Location] to [Fully_qualified] which is fine but I suspect an override of the [crc] sometimes... *) let fn info = Info.qualify info ~location ?crc `Intf m in let infos = List.map fn infos in Log.debug (fun m -> m "add %a" Info.pp solution); (solution :: infos, true, rem) | Some _solution -> (* NOTE(dinosaure): The provider points at an artifact we already hold, yet the module is still unresolved (typically a digest mismatch). Leave it pending so it surfaces as a hole rather than aborting. *) (infos, progress, (m, crc) :: rem) end in let rec go infos = match missing_intfs infos |> sort with | [] -> Ok (infos, []) | modules -> let* () = not_in_forbidden_modules cfg modules in let infos, modules = prune ?disambiguate infos modules in let modules = sort modules in let infos, progress, modules = match modules with | [] -> (infos, true, []) | modules -> List.fold_left fn (infos, false, []) modules in if progress then go infos else Ok (infos, modules) in let* infos = Uniq_resolve.qualify ~stdlib srcs in let* infos, modules = try go infos with Multiple_solutions (m, _crc, solutions) -> error_msgf "@[<v>%a is provided by several incompatible interfaces:@,%a@]" Modname.pp m Fmt.(list ~sep:cut (any " " ++ Info.pp)) solutions in (* NOTE(dinosaure): delete modules that we can ignore. *) let fn (m, _) = not (MSet.mem m cfg.ignore) in let modules = List.filter fn modules in Ok (infos, modules)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>