summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2023-06-20 17:16:42 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2024-01-09 00:26:22 -0800
commit1bda594f70d611d52ef9bc372fef6418266c9a5e (patch)
tree4e10fd985003177bce72cf10425e10dd4a1b10cb /lib
parent6542c94cc1e0cdb5f8c61936c78b74c46d7b6c01 (diff)
downloadspack-1bda594f70d611d52ef9bc372fef6418266c9a5e.tar.gz
spack-1bda594f70d611d52ef9bc372fef6418266c9a5e.tar.bz2
spack-1bda594f70d611d52ef9bc372fef6418266c9a5e.tar.xz
spack-1bda594f70d611d52ef9bc372fef6418266c9a5e.zip
refactor: Index conflicts by `when` spec
Part 2 of reworking all package metadata to key by `when` conditions. Changes conflict dictionary structure from this: { conflict_spec: [(when_spec, msg), ...] } to this: { when_spec: [(conflict_spec, msg), ...] } Also attempts to consistently name the variables used to iterate over conflict dictionaries.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/audit.py4
-rw-r--r--lib/spack/spack/directives.py8
-rw-r--r--lib/spack/spack/package_base.py5
-rw-r--r--lib/spack/spack/solver/asp.py37
-rw-r--r--lib/spack/spack/spec.py9
-rw-r--r--lib/spack/spack/test/concretize.py2
-rw-r--r--lib/spack/spack/test/directives.py2
7 files changed, 33 insertions, 34 deletions
diff --git a/lib/spack/spack/audit.py b/lib/spack/spack/audit.py
index d9b2610267..40bd04e9bc 100644
--- a/lib/spack/spack/audit.py
+++ b/lib/spack/spack/audit.py
@@ -667,8 +667,8 @@ def _unknown_variants_in_directives(pkgs, error_cls):
pkg_cls = spack.repo.PATH.get_pkg_class(pkg_name)
# Check "conflicts" directive
- for conflict, triggers in pkg_cls.conflicts.items():
- for trigger, _ in triggers:
+ for trigger, conflicts in pkg_cls.conflicts.items():
+ for conflict, _ in conflicts:
vrn = spack.spec.Spec(conflict)
try:
vrn.constrain(trigger)
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py
index e837f497af..75cda9f90b 100644
--- a/lib/spack/spack/directives.py
+++ b/lib/spack/spack/directives.py
@@ -525,7 +525,7 @@ def _depends_on(
@directive("conflicts")
-def conflicts(conflict_spec, when=None, msg=None):
+def conflicts(conflict_spec: SpecType, when: WhenType = None, msg: Optional[str] = None):
"""Allows a package to define a conflict.
Currently, a "conflict" is a concretized configuration that is known
@@ -545,16 +545,16 @@ def conflicts(conflict_spec, when=None, msg=None):
msg (str): optional user defined message
"""
- def _execute_conflicts(pkg):
+ def _execute_conflicts(pkg: "spack.package_base.PackageBase"):
# If when is not specified the conflict always holds
when_spec = make_when_spec(when)
if not when_spec:
return
# Save in a list the conflicts and the associated custom messages
- when_spec_list = pkg.conflicts.setdefault(conflict_spec, [])
+ conflict_spec_list = pkg.conflicts.setdefault(when_spec, [])
msg_with_name = f"{pkg.name}: {msg}" if msg is not None else msg
- when_spec_list.append((when_spec, msg_with_name))
+ conflict_spec_list.append((spack.spec.Spec(conflict_spec), msg_with_name))
return _execute_conflicts
diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py
index 926df89181..9b1b1c17c8 100644
--- a/lib/spack/spack/package_base.py
+++ b/lib/spack/spack/package_base.py
@@ -560,11 +560,8 @@ class PackageBase(WindowsRPath, PackageViewMixin, metaclass=PackageMeta):
# Declare versions dictionary as placeholder for values.
# This allows analysis tools to correctly interpret the class attributes.
versions: dict
-
- # Same for dependencies
dependencies: Dict["spack.spec.Spec", Dict[str, "spack.dependency.Dependency"]]
-
- # and patches
+ conflicts: Dict["spack.spec.Spec", List[Tuple["spack.spec.Spec", Optional[str]]]]
patches: Dict["spack.spec.Spec", List["spack.patch.Patch"]]
#: By default, packages are not virtual
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index aa00600d0b..3a0267a50c 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -1234,29 +1234,30 @@ class SpackSolverSetup:
return [fn.attr("node_target_satisfies", spec.name, target)]
def conflict_rules(self, pkg):
- default_msg = "{0}: '{1}' conflicts with '{2}'"
- no_constraint_msg = "{0}: conflicts with '{1}'"
- for trigger, constraints in pkg.conflicts.items():
- trigger_msg = f"conflict is triggered when {str(trigger)}"
- trigger_spec = spack.spec.Spec(trigger)
- trigger_id = self.condition(
- trigger_spec, name=trigger_spec.name or pkg.name, msg=trigger_msg
- )
+ for when_spec, conflict_specs in pkg.conflicts.items():
+ when_spec_msg = "conflict constraint %s" % str(when_spec)
+ when_spec_id = self.condition(when_spec, name=pkg.name, msg=when_spec_msg)
- for constraint, conflict_msg in constraints:
+ for conflict_spec, conflict_msg in conflict_specs:
+ conflict_spec = spack.spec.Spec(conflict_spec)
if conflict_msg is None:
- if constraint == spack.spec.Spec():
- conflict_msg = no_constraint_msg.format(pkg.name, trigger)
+ conflict_msg = f"{pkg.name}: "
+ if when_spec == spack.spec.Spec():
+ conflict_msg += f"conflicts with '{conflict_spec}'"
else:
- conflict_msg = default_msg.format(pkg.name, trigger, constraint)
-
- spec_for_msg = (
- spack.spec.Spec(pkg.name) if constraint == spack.spec.Spec() else constraint
+ conflict_msg += f"'{conflict_spec}' conflicts with '{when_spec}'"
+
+ spec_for_msg = conflict_spec
+ if conflict_spec == spack.spec.Spec():
+ spec_for_msg = spack.spec.Spec(pkg.name)
+ conflict_spec_msg = f"conflict is triggered when {str(spec_for_msg)}"
+ conflict_spec_id = self.condition(
+ conflict_spec, name=conflict_spec.name or pkg.name, msg=conflict_spec_msg
)
- constraint_msg = f"conflict applies to spec {str(spec_for_msg)}"
- constraint_id = self.condition(constraint, name=pkg.name, msg=constraint_msg)
self.gen.fact(
- fn.pkg_fact(pkg.name, fn.conflict(trigger_id, constraint_id, conflict_msg))
+ fn.pkg_fact(
+ pkg.name, fn.conflict(conflict_spec_id, when_spec_id, conflict_msg)
+ )
)
self.gen.newline()
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index a11e8ab915..b27272e8e1 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -2823,10 +2823,11 @@ class Spec:
# external specs are already built, don't worry about whether
# it's possible to build that configuration with Spack
continue
- for conflict_spec, when_list in x.package_class.conflicts.items():
- if x.satisfies(conflict_spec):
- for when_spec, msg in when_list:
- if x.satisfies(when_spec):
+
+ for when_spec, conflict_list in x.package_class.conflicts.items():
+ if x.satisfies(when_spec):
+ for conflict_spec, msg in conflict_list:
+ if x.satisfies(conflict_spec):
when = when_spec.copy()
when.name = x.name
matches.append((x, conflict_spec, when, msg))
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index c53dc0dd36..b6ddf6c4dd 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -1905,7 +1905,7 @@ class TestConcretize:
"""
# Add a conflict to "mpich" that match an already installed "mpich~debug"
pkg_cls = spack.repo.PATH.get_pkg_class("mpich")
- monkeypatch.setitem(pkg_cls.conflicts, "~debug", [(Spec(), None)])
+ monkeypatch.setitem(pkg_cls.conflicts, Spec(), [("~debug", None)])
# If we concretize with --fresh the conflict is taken into account
with spack.config.override("concretizer:reuse", False):
diff --git a/lib/spack/spack/test/directives.py b/lib/spack/spack/test/directives.py
index 73d40365b9..5b34e40793 100644
--- a/lib/spack/spack/test/directives.py
+++ b/lib/spack/spack/test/directives.py
@@ -46,7 +46,7 @@ def test_constraints_from_context(mock_packages):
assert "b" in pkg_cls.dependencies[spack.spec.Spec("@1.0")]
assert pkg_cls.conflicts
- assert (spack.spec.Spec("+foo@1.0"), None) in pkg_cls.conflicts["%gcc"]
+ assert (spack.spec.Spec("%gcc"), None) in pkg_cls.conflicts[spack.spec.Spec("+foo@1.0")]
@pytest.mark.regression("26656")