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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
let fop : Cudf_types.relop -> int -> int -> bool = function
| `Eq -> (=)
| `Neq -> (<>)
| `Geq -> (>=)
| `Gt -> (>)
| `Leq -> (<=)
| `Lt -> (<)
module Make (Context : S.CONTEXT) = struct
type restriction = {
kind : [ `Ensure | `Prevent ];
expr : (Cudf_types.relop * Cudf_types.version) list;
}
type real_role = {
context : Context.t;
name : Cudf_types.pkgname;
}
type role =
| Real of real_role
| Virtual of int * impl list
and real_impl = {
pkg : Cudf.package;
requires : dependency list;
}
and dependency = {
drole : role;
importance : [ `Essential | `Recommended | `Restricts ];
restrictions : restriction list;
}
and impl =
| RealImpl of real_impl
| VirtualImpl of int * dependency list
| Reject of (Cudf_types.pkgname * Cudf_types.version)
| Dummy
let rec pp_version f = function
| RealImpl impl -> Format.pp_print_int f impl.pkg.Cudf.version
| Reject pkg -> Format.pp_print_int f (snd pkg)
| VirtualImpl (_i, deps) ->
Format.pp_print_string f
(String.concat "&" (List.map (fun d -> Format.asprintf "%a" pp_role d.drole) deps))
| Dummy -> Format.pp_print_string f "(no version)"
and pp_impl f = function
| RealImpl impl -> Format.fprintf f "%s.%d" impl.pkg.Cudf.package impl.pkg.Cudf.version
| Reject pkg -> Format.fprintf f "%s.%d" (fst pkg) (snd pkg)
| VirtualImpl _ as x -> pp_version f x
| Dummy -> Format.pp_print_string f "(no solution found)"
and pp_role f = function
| Real t -> Format.pp_print_string f t.name
| Virtual (_, impls) ->
Format.pp_print_string f
(String.concat "|" (List.map (Format.asprintf "%a" pp_impl) impls))
let pp_impl_long = pp_impl
module Role = struct
type t = role
let pp = pp_role
let compare a b =
match a, b with
| Real a, Real b -> String.compare a.name b.name
| Virtual (a, _), Virtual (b, _) -> compare (a : int) b
| Real _, Virtual _ -> -1
| Virtual _, Real _ -> 1
end
let role context name = Real { context; name }
let virtual_impl ~context ~depends () =
let depends = depends |> List.map (fun (name, importance) ->
let drole = role context name in
let importance = (importance :> [ `Essential | `Recommended | `Restricts ]) in
{ drole; importance; restrictions = []}
) in
VirtualImpl (Context.fresh_id context, depends)
let virtual_role ~context impls =
Virtual (Context.fresh_id context, impls)
type command = |
type command_name = private string
let pp_command _ = function (_:command) -> .
let command_requires _role = function (_:command) -> .
let get_command _impl _command_name = None
type dep_info = {
dep_role : Role.t;
dep_importance : [ `Essential | `Recommended | `Restricts ];
dep_required_commands : command_name list;
}
type requirements = {
role : Role.t;
command : command_name option;
}
let dummy_impl = Dummy
let list_deps ~context ~importance ~kind ~pname ~pver deps =
let rec aux = function
| [] -> []
| [[(name, _)]] when String.equal name pname -> []
| [[(name, c)]] ->
let drole = role context name in
let restrictions =
match kind, c with
| `Prevent, None -> [{ kind; expr = [] }]
| `Ensure, None -> []
| kind, Some c -> [{ kind; expr = [c] }]
in
[{ drole; restrictions; importance }]
| x::(_::_ as y) -> aux [x] @ aux y
| [o] ->
let impls = group_ors o in
let drole = virtual_role ~context impls in
[{ drole; restrictions = []; importance = `Essential }]
and group_ors = function
| x::(_::_ as y) -> group_ors [x] @ group_ors y
| [expr] -> [VirtualImpl (Context.fresh_id context, aux [[expr]])]
| [] -> [Reject (pname, pver)]
in
aux deps
let requires _ = function
| Dummy | Reject _ -> [], []
| VirtualImpl (_, deps) -> deps, []
| RealImpl impl -> impl.requires, []
let dep_info { drole; importance; restrictions = _ } =
{ dep_role = drole; dep_importance = importance; dep_required_commands = [] }
type role_information = {
replacement : Role.t option;
impls : impl list;
}
type machine_group = private string
let machine_group _impl = None
type conflict_class = string
let conflict_class _impl = []
let prevent f =
List.map (fun x -> [x]) f
let ensure =
Fun.id
let implementations = function
| Virtual (_, impls) -> { impls; replacement = None }
| Real role ->
let context = role.context in
let impls =
Context.candidates context role.name
|> List.filter_map (function
| _, Error _rejection -> None
| version, Ok pkg ->
let requires =
let make_deps importance kind xform deps =
xform deps
|> list_deps ~context ~importance ~kind ~pname:role.name ~pver:version
in
make_deps `Essential `Ensure ensure pkg.Cudf.depends @
make_deps `Restricts `Prevent prevent pkg.Cudf.conflicts
in
Some (RealImpl { pkg; requires })
)
in
{ impls; replacement = None }
let restrictions dependency = dependency.restrictions
let meets_restriction impl { kind; expr } =
match impl with
| Dummy -> true
| VirtualImpl _ -> assert false
| Reject _ -> false
| RealImpl impl ->
let result = match expr with [] -> true | _ -> List.exists (fun (c, v) -> fop c impl.pkg.Cudf.version v) expr in
match kind with
| `Ensure -> result
| `Prevent -> not result
type rejection = Context.rejection
let rejects role =
match role with
| Virtual _ -> [], []
| Real role ->
let context = role.context in
let rejects =
Context.candidates context role.name
|> List.filter_map (function
| _, Ok _ -> None
| version, Error reason ->
let pkg = (role.name, version) in
Some (Reject pkg, reason)
)
in
let notes = [] in
rejects, notes
let compare_version a b =
match a, b with
| RealImpl a, RealImpl b -> compare (a.pkg.Cudf.version : int) b.pkg.Cudf.version
| VirtualImpl (ia, _), VirtualImpl (ib, _) -> compare (ia : int) ib
| Reject a, Reject b -> compare (snd a : int) (snd b)
| (RealImpl _ | Reject _ | VirtualImpl _ | Dummy),
(RealImpl _ | Reject _ | VirtualImpl _ | Dummy)
-> compare b a
let user_restrictions = function
| Virtual _ -> None
| Real role ->
match Context.user_restrictions role.context role.name with
| [] -> None
| f -> Some { kind = `Ensure; expr = f }
let format_machine _impl = "(src)"
let string_of_op = function
| `Eq -> "="
| `Geq -> ">="
| `Gt -> ">"
| `Leq -> "<="
| `Lt -> "<"
| `Neq -> "<>"
let string_of_version_formula f = String.concat " & " (List.map (fun (rel, v) ->
Printf.sprintf "%s %s" (string_of_op rel) (string_of_int v)
) f)
let string_of_restriction = function
| { kind = `Prevent; expr = [] } -> "conflict with all versions"
| { kind = `Prevent; expr } -> Format.asprintf "not(%s)" (string_of_version_formula expr)
| { kind = `Ensure; expr } -> string_of_version_formula expr
let describe_problem _impl = Format.asprintf "%a" Context.pp_rejection
let version = function
| RealImpl impl -> Some (impl.pkg.Cudf.package, impl.pkg.Cudf.version)
| Reject pkg -> Some pkg
| VirtualImpl _ -> None
| Dummy -> None
end