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.
This commit is contained in:
parent
6542c94cc1
commit
1bda594f70
@ -667,8 +667,8 @@ def _unknown_variants_in_directives(pkgs, error_cls):
|
|||||||
pkg_cls = spack.repo.PATH.get_pkg_class(pkg_name)
|
pkg_cls = spack.repo.PATH.get_pkg_class(pkg_name)
|
||||||
|
|
||||||
# Check "conflicts" directive
|
# Check "conflicts" directive
|
||||||
for conflict, triggers in pkg_cls.conflicts.items():
|
for trigger, conflicts in pkg_cls.conflicts.items():
|
||||||
for trigger, _ in triggers:
|
for conflict, _ in conflicts:
|
||||||
vrn = spack.spec.Spec(conflict)
|
vrn = spack.spec.Spec(conflict)
|
||||||
try:
|
try:
|
||||||
vrn.constrain(trigger)
|
vrn.constrain(trigger)
|
||||||
|
@ -525,7 +525,7 @@ def _depends_on(
|
|||||||
|
|
||||||
|
|
||||||
@directive("conflicts")
|
@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.
|
"""Allows a package to define a conflict.
|
||||||
|
|
||||||
Currently, a "conflict" is a concretized configuration that is known
|
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
|
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
|
# If when is not specified the conflict always holds
|
||||||
when_spec = make_when_spec(when)
|
when_spec = make_when_spec(when)
|
||||||
if not when_spec:
|
if not when_spec:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Save in a list the conflicts and the associated custom messages
|
# 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
|
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
|
return _execute_conflicts
|
||||||
|
|
||||||
|
@ -560,11 +560,8 @@ class PackageBase(WindowsRPath, PackageViewMixin, metaclass=PackageMeta):
|
|||||||
# Declare versions dictionary as placeholder for values.
|
# Declare versions dictionary as placeholder for values.
|
||||||
# This allows analysis tools to correctly interpret the class attributes.
|
# This allows analysis tools to correctly interpret the class attributes.
|
||||||
versions: dict
|
versions: dict
|
||||||
|
|
||||||
# Same for dependencies
|
|
||||||
dependencies: Dict["spack.spec.Spec", Dict[str, "spack.dependency.Dependency"]]
|
dependencies: Dict["spack.spec.Spec", Dict[str, "spack.dependency.Dependency"]]
|
||||||
|
conflicts: Dict["spack.spec.Spec", List[Tuple["spack.spec.Spec", Optional[str]]]]
|
||||||
# and patches
|
|
||||||
patches: Dict["spack.spec.Spec", List["spack.patch.Patch"]]
|
patches: Dict["spack.spec.Spec", List["spack.patch.Patch"]]
|
||||||
|
|
||||||
#: By default, packages are not virtual
|
#: By default, packages are not virtual
|
||||||
|
@ -1234,29 +1234,30 @@ def target_ranges(self, spec, single_target_fn):
|
|||||||
return [fn.attr("node_target_satisfies", spec.name, target)]
|
return [fn.attr("node_target_satisfies", spec.name, target)]
|
||||||
|
|
||||||
def conflict_rules(self, pkg):
|
def conflict_rules(self, pkg):
|
||||||
default_msg = "{0}: '{1}' conflicts with '{2}'"
|
for when_spec, conflict_specs in pkg.conflicts.items():
|
||||||
no_constraint_msg = "{0}: conflicts with '{1}'"
|
when_spec_msg = "conflict constraint %s" % str(when_spec)
|
||||||
for trigger, constraints in pkg.conflicts.items():
|
when_spec_id = self.condition(when_spec, name=pkg.name, msg=when_spec_msg)
|
||||||
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 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 conflict_msg is None:
|
||||||
if constraint == spack.spec.Spec():
|
conflict_msg = f"{pkg.name}: "
|
||||||
conflict_msg = no_constraint_msg.format(pkg.name, trigger)
|
if when_spec == spack.spec.Spec():
|
||||||
|
conflict_msg += f"conflicts with '{conflict_spec}'"
|
||||||
else:
|
else:
|
||||||
conflict_msg = default_msg.format(pkg.name, trigger, constraint)
|
conflict_msg += f"'{conflict_spec}' conflicts with '{when_spec}'"
|
||||||
|
|
||||||
spec_for_msg = (
|
spec_for_msg = conflict_spec
|
||||||
spack.spec.Spec(pkg.name) if constraint == spack.spec.Spec() else constraint
|
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(
|
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()
|
self.gen.newline()
|
||||||
|
|
||||||
|
@ -2823,10 +2823,11 @@ def _old_concretize(self, tests=False, deprecation_warning=True):
|
|||||||
# external specs are already built, don't worry about whether
|
# external specs are already built, don't worry about whether
|
||||||
# it's possible to build that configuration with Spack
|
# it's possible to build that configuration with Spack
|
||||||
continue
|
continue
|
||||||
for conflict_spec, when_list in x.package_class.conflicts.items():
|
|
||||||
if x.satisfies(conflict_spec):
|
for when_spec, conflict_list in x.package_class.conflicts.items():
|
||||||
for when_spec, msg in when_list:
|
if x.satisfies(when_spec):
|
||||||
if x.satisfies(when_spec):
|
for conflict_spec, msg in conflict_list:
|
||||||
|
if x.satisfies(conflict_spec):
|
||||||
when = when_spec.copy()
|
when = when_spec.copy()
|
||||||
when.name = x.name
|
when.name = x.name
|
||||||
matches.append((x, conflict_spec, when, msg))
|
matches.append((x, conflict_spec, when, msg))
|
||||||
|
@ -1905,7 +1905,7 @@ def test_installed_specs_disregard_conflicts(self, mutable_database, monkeypatch
|
|||||||
"""
|
"""
|
||||||
# Add a conflict to "mpich" that match an already installed "mpich~debug"
|
# Add a conflict to "mpich" that match an already installed "mpich~debug"
|
||||||
pkg_cls = spack.repo.PATH.get_pkg_class("mpich")
|
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
|
# If we concretize with --fresh the conflict is taken into account
|
||||||
with spack.config.override("concretizer:reuse", False):
|
with spack.config.override("concretizer:reuse", False):
|
||||||
|
@ -46,7 +46,7 @@ def test_constraints_from_context(mock_packages):
|
|||||||
assert "b" in pkg_cls.dependencies[spack.spec.Spec("@1.0")]
|
assert "b" in pkg_cls.dependencies[spack.spec.Spec("@1.0")]
|
||||||
|
|
||||||
assert pkg_cls.conflicts
|
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")
|
@pytest.mark.regression("26656")
|
||||||
|
Loading…
Reference in New Issue
Block a user