Source file opamPinned.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
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
open OpamTypes
open OpamStateTypes
open OpamFilename.Op
open OpamStd.Option.Op
let log fmt = OpamConsole.log "PIN" fmt
let package st name = OpamPackage.package_of_name st.pinned name
let package_opt st name = try Some (package st name) with Not_found -> None
let version st name = (package st name).version
let version_opt st name = try Some (version st name) with Not_found -> None
let packages st = st.pinned
let possible_definition_filenames dir name = [
dir / (OpamPackage.Name.to_string name ^ ".opam") // "opam";
dir // (OpamPackage.Name.to_string name ^ ".opam");
dir / "opam" / (OpamPackage.Name.to_string name ^ ".opam") // "opam";
dir / "opam" // (OpamPackage.Name.to_string name ^ ".opam");
dir / "opam" // "opam";
dir // "opam"
]
let lock_filename ?locked file =
locked
>>+ (fun () -> OpamStateConfig.(!r.locked))
>>| (fun e -> OpamFilename.add_extension file e, e)
let check_locked ?locked default =
match lock_filename ?locked default with
| None -> default, None
| Some (locked, ext) ->
if not (OpamFilename.exists locked) then default, None else
(log "Lock file found %s" (OpamFilename.to_string default);
let base_depends =
OpamFile.make default
|> OpamFile.OPAM.read
|> OpamFile.OPAM.depends
in
let lock_depends =
OpamFile.make locked
|> OpamFile.OPAM.read
|> OpamFile.OPAM.depends
in
let ldep_names =
OpamFormula.fold_left
(fun acc (n,_) -> OpamPackage.Name.Set.add n acc)
OpamPackage.Name.Set.empty lock_depends
in
let base_formula =
OpamFilter.filter_deps ~build:true ~post:true ~test:false ~doc:false
~dev_setup:false ~dev:false base_depends
in
let lock_formula =
OpamFilter.filter_deps ~build:true ~post:true ~test:false ~doc:false
~dev_setup:false ~dev:false lock_depends
in
let lpkg_f =
lock_formula
|> OpamFormula.atoms
|> OpamPackage.Name.Map.of_list
in
let (@) = List.rev_append in
let rec fold formula =
List.fold_left cross ([],[]) (OpamFormula.ands_to_list formula)
and cross (cont,cons) formula =
match formula with
| Atom (bn, bvf) ->
( let cont =
if OpamPackage.Name.Set.mem bn ldep_names then cont
else bn::cont
in
let cons =
match OpamPackage.Name.Map.find_opt bn lpkg_f with
| Some (Some (`Eq, lv)) ->
if OpamFormula.check_version_formula bvf lv then cons
else (bn, lv, bvf)::cons
| _ -> cons
in
(cont,cons))
| Or (or1, or2) ->
let or1_cont, or1_cons = fold or1 in
let or2_cont, or2_cons = fold or2 in
let cont =
if or1_cont = [] || or2_cont = [] then cont
else or1_cont @ or2_cont @ cont
in
let cons =
if or1_cons = [] || or2_cons = [] then cons
else or1_cons @ or2_cons @ cons
in
(cont,cons)
| And (and1, and2) ->
let and1_cont, and1_cons = fold and1 in
let and2_cont, and2_cons = fold and2 in
((and1_cont @ and2_cont @ cont), (and1_cons @ and2_cons @ cons))
| Block f -> cross (cont,cons) f
| Empty -> (cont,cons)
in
let contains, consistent = fold base_formula in
if contains <> [] || consistent <> [] then
(OpamConsole.warning "Lock file %s is outdated, you may want to re-run opam lock:\n%s"
(OpamConsole.colorise `underline (OpamFilename.Base.to_string (OpamFilename.basename locked)))
((if contains <> [] then
Printf.sprintf "Dependencies present in opam file not in lock file:\n%s"
(OpamStd.Format.itemize OpamPackage.Name.to_string contains)
else "")
^
(if consistent <> [] then
Printf.sprintf "Dependencies in lock file not consistent wit opam file filter:\n%s"
(OpamStd.Format.itemize (fun (n,lv,(bv: OpamFormula.version_formula)) ->
Printf.sprintf "%s: %s in not contained in {%s}"
(OpamPackage.Name.to_string n)
(OpamPackage.Version.to_string lv)
(OpamFormula.string_of_formula
(fun (op, vc) ->
Printf.sprintf "%s %s"
(OpamPrinter.FullPos.relop_kind op) (OpamPackage.Version.to_string vc))
bv))
consistent)
else "")));
locked, Some ext)
let find_opam_file_in_source ?locked name dir =
let opt =
OpamStd.List.find_opt OpamFilename.exists
(possible_definition_filenames dir name)
in
opt
>>| check_locked ?locked
>>| (fun (o,l) -> OpamFile.make o, l)
let name_of_opam_filename ?locked dir file =
let suffix= ".opam" in
let get_name s =
if Filename.check_suffix s suffix
then Some Filename.(chop_suffix (basename s) suffix)
else None
in
let rel = OpamFilename.remove_prefix dir file in
let rel =
match locked with
| None -> rel
| Some suf ->
let ext = "."^suf in
if OpamStd.String.ends_with ~suffix:(suffix^ext) rel then
OpamStd.String.remove_suffix ~suffix:ext rel
else rel
in
(get_name (Filename.basename rel) >>+ fun () ->
get_name (Filename.dirname rel)) >>= fun name ->
try Some (OpamPackage.Name.of_string name)
with Failure _ -> None
let files_in_source ?locked ?(recurse=false) ?subpath d =
let baseopam = OpamFilename.Base.of_string "opam" in
let files =
let rec files_aux acc base d =
let acc =
OpamStd.List.filter_map (fun f ->
if OpamFilename.basename f = baseopam ||
OpamFilename.check_suffix f ".opam" then
let base =
match base, subpath with
| Some b, Some sp ->
Some (Filename.concat (OpamFilename.SubPath.to_string sp) b)
| Some b, _ -> Some b
| _, Some sp -> Some (OpamFilename.SubPath.to_string sp)
| None, None -> None
in
Some (f, base)
else
None)
(OpamFilename.files d) @ acc
in
List.fold_left
(fun acc d ->
if OpamStd.String.ends_with ~suffix:".opam"
(OpamFilename.Dir.to_string d)
then
match OpamFilename.opt_file OpamFilename.Op.(d//"opam") with
| None -> acc
| Some f -> (f, base) :: acc
else
let base_dir = OpamFilename.basename_dir d in
let basename = OpamFilename.Base.to_string base_dir in
if recurse &&
not (base_dir = OpamFilename.Base.of_string OpamSwitch.external_dirname ||
base_dir = OpamFilename.Base.of_string "_build" ||
OpamStd.String.starts_with ~prefix:"." basename)
then
let base = match base with
| None -> Some basename
| Some base -> Some (Filename.concat base basename) in
files_aux acc base d
else
acc)
acc (OpamFilename.dirs d)
in
files_aux [] None
in
let d = OpamFilename.SubPath.(d /? subpath) in
files d @ files (d / "opam") |>
List.map (fun (f,s) -> (check_locked ?locked f), s) |>
OpamStd.List.filter_map
(fun ((f, locked), subpath) ->
try
if (Unix.stat (OpamFilename.to_string f)).Unix.st_size = 0 then None
else
Some { pin_name = name_of_opam_filename ?locked d f;
pin = {
pin_file = OpamFile.make f;
pin_locked = locked;
pin_subpath =
OpamStd.Option.map OpamFilename.SubPath.of_string subpath;
pin_url = ();
}}
with Unix.Unix_error _ ->
OpamConsole.error "Can not read %s, ignored."
(OpamFilename.to_string f);
None)
let files_in_source_w_target ?locked ?recurse ?subpath
?(same_kind=fun _ -> true) url dir =
OpamStd.List.filter_map (fun name_and_file ->
let pin_url =
match url.OpamUrl.backend with
| #OpamUrl.version_control as vc ->
let module VCS =
(val match vc with
| `git -> (module OpamGit.VCS: OpamVCS.VCS)
| `hg -> (module OpamHg.VCS: OpamVCS.VCS)
| `darcs -> (module OpamDarcs.VCS: OpamVCS.VCS)
: OpamVCS.VCS)
in
let open OpamProcess.Job.Op in
let versioned_files =
OpamProcess.Job.run @@
VCS.versioned_files dir @@| fun files -> files
in
let opamfile =
OpamFilename.remove_prefix dir
(OpamFile.filename name_and_file.pin.pin_file)
in
if List.mem opamfile versioned_files
|| not (OpamStd.String.contains opamfile ~sub:Filename.dir_sep) then
url
else
{ url with
transport = "file";
hash = None;
backend = `rsync }
| _ -> url
in
if same_kind pin_url then
Some { name_and_file with pin = { name_and_file.pin with pin_url }}
else None)
(files_in_source ?locked ?recurse ?subpath dir)
let orig_opam_file st name opam =
OpamFile.OPAM.get_metadata_dir
~repos_roots:(OpamRepositoryState.get_root st.switch_repos)
opam >>= fun dir ->
let opam_files = [
dir // (OpamPackage.Name.to_string name ^ ".opam");
dir // "opam"
] in
let locked_files =
match OpamFile.OPAM.locked opam with
| Some locked ->
List.map (fun f -> OpamFilename.add_extension f locked) opam_files
| None -> []
in
OpamStd.List.find_opt OpamFilename.exists locked_files
++ OpamStd.List.find_opt OpamFilename.exists opam_files
>>| OpamFile.make