Skip to content

Commit 21305bb

Browse files
authored
Merge pull request #5927 from dra27/relax-warning-41
Relax warning 41 for package variables guarded by a :installed filter
2 parents 33081e5 + 889a45b commit 21305bb

File tree

6 files changed

+165
-17
lines changed

6 files changed

+165
-17
lines changed

master_changes.md

+3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ users)
5959
* Fix extraction of tarballs on Windows which contain symlinks both when those symlinks can't be created or if they point to files which don't exist [#5953 @dra27]
6060

6161
## Lint
62+
* W41: Relax warning 41 not to trigger on uses of package variables which are guarded by a package:installed filter [#5927 @dra27]
63+
* W41: Tighten w.r.t depends & depopts [#5927 @dra27]
6264

6365
## Repository
6466
* Fix download URLs containing invalid characters on Windows (e.g. the ? character in `?full_index=1`) [#5921 @dra27]
@@ -135,6 +137,7 @@ users)
135137
* env.win32: add regression test for reverting additions to PATH-like variables [#5935 @dra27]
136138
* env tests: add regression test for append/prepend operators to empty environment variables [#5925, #5935 @dra27]
137139
* env.win32: add regression test for handling the empty entry in PATH-like variables [#5926, #5935 @dra27]
140+
* lint: add W41 examples [#5927 @dra27]
138141

139142
### Engine
140143
* Add `sort` command [#5935 @dra27]

src/format/opamFilter.mli

+3
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ val commands: env -> command list -> string list list
155155
(** Process a simpler command, without filters *)
156156
val single_command: env -> arg list -> string list
157157

158+
(** Extracts the list of variables from an argument *)
159+
val simple_arg_variables: simple_arg -> full_variable list
160+
158161
(** Extracts variables appearing in a list of commands *)
159162
val commands_variables: command list -> full_variable list
160163

src/format/opamFormula.ml

+6-5
Original file line numberDiff line numberDiff line change
@@ -379,12 +379,13 @@ let verifies f nv =
379379
check_version_formula cstr (OpamPackage.version nv))
380380
name_formula
381381

382+
let all_names f =
383+
fold_left (fun acc (name, _) ->
384+
OpamPackage.Name.Set.add name acc)
385+
OpamPackage.Name.Set.empty f
386+
382387
let packages pkgset f =
383-
let names =
384-
fold_left (fun acc (name, _) ->
385-
OpamPackage.Name.Set.add name acc)
386-
OpamPackage.Name.Set.empty f
387-
in
388+
let names = all_names f in
388389
(* dnf allows us to transform the formula into a union of intervals, where
389390
ignoring atoms for different package names works. *)
390391
let dnf = dnf_of_formula f in

src/format/opamFormula.mli

+3
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ val verifies: t -> OpamPackage.t -> bool
161161
(** Checks if a given set of (installed) packages satisfies a formula *)
162162
val satisfies_depends: OpamPackage.Set.t -> t -> bool
163163

164+
(** Returns the set of names referred to in a formula *)
165+
val all_names: (OpamPackage.Name.t * 'a) formula -> OpamPackage.Name.Set.t
166+
164167
(** Returns the subset of packages possibly matching the formula (i.e. including
165168
all disjunction cases) *)
166169
val packages: OpamPackage.Set.t -> t -> OpamPackage.Set.t

src/state/opamFileTools.ml

+123-12
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,91 @@ let map_all_filters f t =
119119
with_deprecated_build_test (map_commands t.deprecated_build_test) |>
120120
with_deprecated_build_doc (map_commands t.deprecated_build_doc)
121121

122+
(* unguarded_commands_variables is an alternative implementation of
123+
OpamFilter.commands_variables which excludes package variables which are
124+
guarded by an unambiguous {package:installed} filter. That is, at each level,
125+
if assuming !package:installed reduces the filter to false, then the uses of
126+
package:variable are not returned. This allows expressions like:
127+
["--with-foo=%{foo:share}%" {foo:installed}] or even
128+
["--with-foo"] {foo:installed & foo:bar != "baz"} not to trigger warning 41
129+
if the package is not explicitly depended on. *)
130+
131+
let unguarded_commands_variables commands =
132+
let is_installed_variable filter guarded_packages v =
133+
match OpamVariable.Full.package v with
134+
| None -> guarded_packages
135+
| (Some name) as package ->
136+
let is_installed var =
137+
String.equal "installed"
138+
(OpamVariable.to_string (OpamVariable.Full.variable var))
139+
in
140+
let env var =
141+
if Option.equal OpamPackage.Name.equal
142+
(OpamVariable.Full.package var) package &&
143+
is_installed var then
144+
Some (B false)
145+
else
146+
None
147+
in
148+
if is_installed v &&
149+
OpamFilter.partial_eval env filter = FBool false then
150+
OpamPackage.Name.Set.add name guarded_packages
151+
else
152+
guarded_packages
153+
in
154+
let filter_guarded variables guarded_packages =
155+
let is_unguarded v =
156+
match OpamVariable.Full.package v with
157+
| Some package ->
158+
not (OpamPackage.Name.Set.mem package guarded_packages)
159+
| None -> true
160+
in
161+
List.filter is_unguarded variables
162+
in
163+
let unguarded_packages_from_filter guarded_packages = function
164+
| None -> guarded_packages, []
165+
| Some f ->
166+
let filter_variables = OpamFilter.variables f in
167+
let guarded_packages =
168+
List.fold_left (is_installed_variable f)
169+
guarded_packages filter_variables
170+
in
171+
guarded_packages, filter_guarded filter_variables guarded_packages
172+
in
173+
let unguarded_argument_variables guarded_packages (argument, filter) =
174+
let guarded_packages, filter_variables =
175+
unguarded_packages_from_filter guarded_packages filter
176+
in
177+
let variables_from_arguments =
178+
filter_guarded (OpamFilter.simple_arg_variables argument) guarded_packages
179+
in
180+
guarded_packages, variables_from_arguments @ filter_variables
181+
in
182+
let unguarded_command_variables guarded_packages (command, filter) =
183+
let filter_guarded_packages, filter_variables =
184+
unguarded_packages_from_filter OpamPackage.Name.Set.empty filter
185+
in
186+
let add_argument (guarded_packages, acc) argument =
187+
let guarded_packages, unguarded_variables =
188+
unguarded_argument_variables guarded_packages argument
189+
in
190+
guarded_packages, unguarded_variables @ acc
191+
in
192+
let command_guarded_packages, unguarded_variables =
193+
List.fold_left add_argument (filter_guarded_packages, filter_variables)
194+
command
195+
in
196+
OpamPackage.Name.Set.union guarded_packages command_guarded_packages,
197+
unguarded_variables
198+
in
199+
let f (guarded_packages, acc) c =
200+
let guarded_packages, unguarded_variables =
201+
unguarded_command_variables guarded_packages c
202+
in
203+
guarded_packages, (unguarded_variables @ acc)
204+
in
205+
List.fold_left f (OpamPackage.Name.Set.empty, []) commands
206+
122207
(* Returns all variables from all commands (or on given [command]) and all filters *)
123208
let all_variables ?exclude_post ?command t =
124209
let commands =
@@ -130,6 +215,18 @@ let all_variables ?exclude_post ?command t =
130215
List.fold_left (fun acc f -> OpamFilter.variables f @ acc)
131216
[] (all_filters ?exclude_post t)
132217

218+
(* As all_variables, but any commands or arguments which are fully guarded by
219+
package:installed are excluded; used for Warning 41 so that
220+
["%{foo:share}%" {foo:installed}] doesn't trigger a warning on foo *)
221+
let all_unguarded_variables ?exclude_post t =
222+
let guarded_packages, unguarded_commands_variables =
223+
unguarded_commands_variables (all_commands t)
224+
in
225+
guarded_packages,
226+
unguarded_commands_variables @
227+
List.fold_left (fun acc f -> OpamFilter.variables f @ acc)
228+
[] (all_filters ?exclude_post t)
229+
133230
let map_all_variables f t =
134231
let map_fld (x, flt) = x, OpamFilter.map_variables f flt in
135232
let map_optfld = function
@@ -456,18 +553,32 @@ let t_lint ?check_extra_files ?(check_upstream=false) ?(all=false) t =
456553
~detail:alpha_flags
457554
(alpha_flags <> []));
458555
*)
459-
(let undep_pkgs =
460-
List.fold_left
461-
(fun acc v ->
462-
match OpamVariable.Full.package v with
463-
| Some n when
464-
t.OpamFile.OPAM.name <> Some n &&
465-
not (OpamPackage.Name.Set.mem n all_depends) &&
466-
OpamVariable.(Full.variable v <> of_string "installed")
467-
->
468-
OpamPackage.Name.Set.add n acc
469-
| _ -> acc)
470-
OpamPackage.Name.Set.empty (all_variables ~exclude_post:true t)
556+
(let all_mentioned_packages =
557+
OpamPackage.Name.Set.union
558+
(OpamFormula.all_names t.depends)
559+
(OpamFormula.all_names t.depopts)
560+
in
561+
let undep_pkgs =
562+
let guarded_packages, all_unguarded_variables =
563+
all_unguarded_variables ~exclude_post:true t
564+
in
565+
let first_lot =
566+
List.fold_left
567+
(fun acc v ->
568+
match OpamVariable.Full.package v with
569+
| Some n when
570+
t.OpamFile.OPAM.name <> Some n &&
571+
not (OpamPackage.Name.Set.mem n all_depends) &&
572+
OpamVariable.(Full.variable v <> of_string "installed")
573+
->
574+
OpamPackage.Name.Set.add n acc
575+
| _ -> acc)
576+
OpamPackage.Name.Set.empty all_unguarded_variables
577+
in
578+
let second_lot =
579+
OpamPackage.Name.Set.diff guarded_packages all_mentioned_packages
580+
in
581+
OpamPackage.Name.Set.union first_lot second_lot
471582
in
472583
cond 41 `Warning
473584
"Some packages are mentioned in package scripts or features, but \

tests/reftests/lint.test

+27
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,33 @@ bug-reports: "https://nobug"
400400
messages: "foo" { bar:installed }
401401
### opam lint ./lint.opam
402402
${BASEDIR}/lint.opam: Passed.
403+
### <lint.opam>
404+
opam-version: "2.0"
405+
synopsis: "A word"
406+
description: "Two words."
407+
authors: "the testing team"
408+
homepage: "egapemoh"
409+
maintainer: "maint@tain.er"
410+
license: "ISC"
411+
dev-repo: "hg+https://to@li.nt"
412+
bug-reports: "https://nobug"
413+
depends: [
414+
"dependency"
415+
"guarded-dependency" {os = ""}
416+
]
417+
build: [
418+
["false"] {no-dependency-installed-only:installed}
419+
["true"] {dependency:installed}
420+
["%{guarded-dependency:share}%"] {guarded-dependency:installed}
421+
["%{guarded-dependency:share}%"] {guarded-dependency:installed & guarded-dependency:share != ""}
422+
["%{no-dependency-unguarded:share}%"] {no-dependency-unguarded:installed | no-dependency-unguarded:share != ""}
423+
["%{guarded-dependency:share}%" {guarded-dependency:installed}]
424+
["%{guarded-dependency:share}%%{no-dependency-guarded:share}%" {no-dependency-guarded:installed}] {guarded-dependency:installed}
425+
["%{guarded-dependency:share}%%{no-dependency-unguarded:share}%%{no-dependency-guarded:share}%" {no-dependency-guarded:installed}] {guarded-dependency:installed}
426+
]
427+
### opam lint ./lint.opam
428+
${BASEDIR}/lint.opam: Warnings.
429+
warning 41: Some packages are mentioned in package scripts or features, but there is no dependency or depopt toward them: "no-dependency-guarded", "no-dependency-installed-only", "no-dependency-unguarded"
403430
### : E42: The 'dev-repo:' field doesn't use version control. You should use URLs of the form "git://", "git+https://", "hg+https://"...
404431
### <lint.opam>
405432
opam-version: "2.0"

0 commit comments

Comments
 (0)