Odoc docs
1module SS = Set.Make (String)
2
3let mentions_post (cond : OpamTypes.condition) =
4 OpamFormula.fold_left
5 (fun acc (fc : OpamTypes.filter OpamTypes.filter_or_constraint) ->
6 acc
7 ||
8 match fc with
9 | Filter f ->
10 List.exists
11 (fun v -> OpamVariable.Full.to_string v = "post")
12 (OpamFilter.variables f)
13 | Constraint _ -> false)
14 false cond
15
16let names_of_formula (ff : OpamTypes.filtered_formula) =
17 OpamFormula.fold_left
18 (fun acc (name, cond) ->
19 if mentions_post cond then acc
20 else SS.add (OpamPackage.Name.to_string name) acc)
21 SS.empty ff
22
23let direct_deps sw ~name ~version =
24 let path = Fpath.(Switch.packages_dir sw / (name ^ "." ^ version) / "opam") in
25 match
26 OpamFile.OPAM.read (OpamFile.make (OpamFilename.raw (Fpath.to_string path)))
27 with
28 | exception _ -> SS.empty
29 | opam ->
30 SS.union
31 (names_of_formula (OpamFile.OPAM.depends opam))
32 (names_of_formula (OpamFile.OPAM.depopts opam))
33
34let order ?(warn = fun _ -> ()) sw names =
35 let installed = Switch.installed sw in
36 let version_of n =
37 List.find_map
38 (fun (n', v) -> if String.equal n n' then Some v else None)
39 installed
40 in
41 let targets = SS.filter (fun n -> version_of n <> None) (SS.of_list names) in
42 let state = Hashtbl.create 16 in
43 let out = ref [] in
44 let rec visit n =
45 match Hashtbl.find_opt state n with
46 | Some `Done -> ()
47 | Some `Visiting ->
48 warn (Printf.sprintf "dependency cycle through %s; breaking it" n)
49 | None ->
50 Hashtbl.replace state n `Visiting;
51 let version = Option.get (version_of n) in
52 SS.iter visit (SS.inter (direct_deps sw ~name:n ~version) targets);
53 Hashtbl.replace state n `Done;
54 out := n :: !out
55 in
56 (* SS.iter is in increasing element order, so the result is
57 deterministic. *)
58 SS.iter visit targets;
59 List.rev !out