Source file opam_0install_cudf.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
let tagged_with_avoid_version pkg =
List.exists (function
| "avoid-version", (`Int 1 | `Bool true) -> true
| _ -> false
) pkg.Cudf.pkg_extra
let version_rev_compare ~prefer_oldest ~handle_avoid_version ~prefer_installed =
let cmp =
if prefer_oldest then
fun pkg1 pkg2 -> Int.compare pkg1.Cudf.version pkg2.Cudf.version
else
fun pkg1 pkg2 -> Int.compare pkg2.Cudf.version pkg1.Cudf.version
in
let cmp =
if handle_avoid_version then
fun pkg1 pkg2 ->
match tagged_with_avoid_version pkg1, tagged_with_avoid_version pkg2 with
| true, true | false, false -> cmp pkg1 pkg2
| true, false when pkg1.Cudf.installed -> cmp pkg1 pkg2
| false, true when pkg2.Cudf.installed -> cmp pkg1 pkg2
| true, false -> 1
| false, true -> -1
else
cmp
in
let cmp =
if prefer_installed then
fun pkg1 pkg2 ->
match pkg1.Cudf.installed, pkg2.Cudf.installed with
| true, true | false, false -> cmp pkg1 pkg2
| true, false -> -1
| false, true -> 1
else
cmp
in
cmp
module Context = struct
type rejection = UserConstraint of Cudf_types.vpkg
type t = {
universe : Cudf.universe;
constraints : (Cudf_types.pkgname * (Cudf_types.relop * Cudf_types.version)) list;
fresh_id : int ref;
version_rev_compare : Cudf.package -> Cudf.package -> int;
}
let user_restrictions t name =
List.fold_left (fun acc (name', c) ->
if String.equal name name' then
c :: acc
else
acc
) [] t.constraints
let candidates t name =
let user_constraints = user_restrictions t name in
match Cudf.lookup_packages t.universe name with
| [] ->
[]
| versions ->
List.fast_sort t.version_rev_compare versions
|> List.map (fun pkg ->
let rec check_constr = function
| [] -> (pkg.Cudf.version, Ok pkg)
| ((op, v)::c) ->
if Model.fop op pkg.Cudf.version v then
check_constr c
else
(pkg.Cudf.version, Error (UserConstraint (name, Some (op, v))))
in
check_constr user_constraints
)
let print_constr = function
| None -> ""
| Some (`Eq, v) -> "="^string_of_int v
| Some (`Neq, v) -> "!="^string_of_int v
| Some (`Geq, v) -> ">="^string_of_int v
| Some (`Gt, v) -> ">"^string_of_int v
| Some (`Leq, v) -> "<="^string_of_int v
| Some (`Lt, v) -> "<"^string_of_int v
let pp_rejection f = function
| UserConstraint (name, c) -> Format.fprintf f "Rejected by user-specified constraint %s%s" name (print_constr c)
let fresh_id {fresh_id; _} =
incr fresh_id;
!fresh_id
end
module Input = Model.Make(Context)
let requirements ~context pkgs =
let role =
let impl = Input.virtual_impl ~context ~depends:pkgs () in
Input.virtual_role ~context [impl]
in
{ Input.role; command = None }
module Solver = Zeroinstall_solver.Make(Input)
module Diagnostics = Zeroinstall_solver.Diagnostics(Solver.Output)
type t = Context.t
type selections = Solver.Output.t
type diagnostics = Input.requirements
let create ?(prefer_oldest=false) ?(handle_avoid_version=true) ?(prefer_installed=false) ~constraints universe =
{
Context.universe;
constraints;
fresh_id = ref 0;
version_rev_compare = version_rev_compare ~prefer_oldest ~handle_avoid_version ~prefer_installed;
}
let solve context pkgs =
let req = requirements ~context pkgs in
match Solver.do_solve ~closest_match:false req with
| Some sels -> Ok sels
| None -> Error req
let diagnostics ?verbose req =
Solver.do_solve req ~closest_match:true
|> Option.get
|> Diagnostics.get_failure_reason ?verbose
let packages_of_result sels =
sels
|> Solver.Output.to_map |> Solver.Output.RoleMap.to_seq |> List.of_seq
|> List.filter_map (fun (_role, sel) -> Input.version (Solver.Output.unwrap sel))