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
open OpamTypes
open OpamStateTypes
open OpamFilename.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 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 check_locked ?subpath default =
match OpamStateConfig.(!r.locked) with
| None -> default
| Some ext ->
let flo =
match subpath with
| Some s -> OpamFilename.(Op.(Dir.of_string s // to_string default))
| None -> default
in
let fl = OpamFilename.add_extension flo ext in
if not (OpamFilename.exists fl) then default else
(log "Lock file found %s" (OpamFilename.to_string flo);
let base_depends =
OpamFile.make flo
|> OpamFile.OPAM.read
|> OpamFile.OPAM.depends
in
let lock_depends =
OpamFile.make fl
|> 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:false base_depends
in
let lock_formula =
OpamFilter.filter_deps ~build:true ~post:true ~test:false ~doc: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 fl)))
((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 "")));
OpamFilename.add_extension default ext)
let find_opam_file_in_source ?(locked=false) name dir =
let opt =
OpamStd.List.find_opt OpamFilename.exists
(possible_definition_filenames dir name)
in
(match opt with
| Some base when locked -> Some (check_locked base)
| _ -> opt)
|> OpamStd.Option.map OpamFile.make
let name_of_opam_filename dir file =
let open OpamStd.Option.Op in
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 OpamStateConfig.(!r.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 ?(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 sp b)
| Some b, _ | _, Some b -> Some b
| None, None -> None
in
Some (f, base)
else
None)
(OpamFilename.files d) @ acc
in
List.fold_left
(fun acc d ->
if OpamFilename.(basename_dir d = Base.of_string "opam") ||
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 =
(OpamStd.Option.map_default (fun sp -> OpamFilename.Op.(d / sp)) d subpath)
in
files d @ files (d / "opam") |>
List.map (fun (f,s) -> (check_locked ?subpath:s f), s) |>
OpamStd.List.filter_map
(fun (f, subpath) ->
try
if (Unix.stat (OpamFilename.to_string f)).Unix.st_size = 0 then None
else Some (name_of_opam_filename d f, OpamFile.make f, subpath)
with Unix.Unix_error _ ->
OpamConsole.error "Can not read %s, ignored."
(OpamFilename.to_string f);
None)
let orig_opam_file st name opam =
let open OpamStd.Option.Op in
OpamFile.OPAM.get_metadata_dir
~repos_roots:(OpamRepositoryState.get_root st.switch_repos)
opam >>= fun dir ->
OpamStd.List.find_opt OpamFilename.exists [
dir // (OpamPackage.Name.to_string name ^ ".opam");
dir // "opam"
] >>|
OpamFile.make