conditional deps: tests for Spec.satisfies and Spec.constrain

Signed-off-by: Gregory Becker <becker33@llnl.gov>
This commit is contained in:
Gregory Becker 2025-05-16 12:31:22 -07:00
parent 0d021717ec
commit a16d10edc9
No known key found for this signature in database
GPG Key ID: 2362541F6D14ED84
2 changed files with 43 additions and 4 deletions

View File

@ -1817,7 +1817,9 @@ def _add_dependency(
)
except StopIteration:
# Error if we have overlapping or incompatible deptypes
if any(not dt.compatible(dspec.depflag, depflag) for dspec in orig):
if any(not dt.compatible(dspec.depflag, depflag) for dspec in orig) and all(
dspec.when == when for dspec in orig
):
edge_attrs = f"deptypes={dt.flag_to_chars(depflag).strip()}"
required_dep_str = f"^[{edge_attrs}] {str(spec)}"
@ -3440,7 +3442,11 @@ def satisfies(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
mock_nodes_from_old_specfiles = set()
for rhs_edge in other.traverse_edges(root=False, cover="edges"):
# Skip checking any conditional edge that is not satisfied
if rhs_edge.when != Spec() and not rhs_edge.parent.satisfies(rhs_edge.when):
if (
rhs_edge.when != Spec()
and not rhs_edge.parent.satisfies(rhs_edge.when)
and not self.satisfies(rhs_edge.when)
):
continue
# If we are checking for ^mpi we need to verify if there is any edge
@ -3527,13 +3533,17 @@ def satisfies(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
for rhs in other.traverse(root=False):
# Possible lhs nodes to match this rhs node
lhss = [lhs for lhs in lhs_nodes if lhs.satisfies(rhs, deps=False)]
lhs_parents = [
lhs
for lhs in lhs_nodes
if any(lhs.satisfies(parent, deps=False) for parent in rhs.dependents())
]
# Check whether the node needs matching (not a conditional that isn't satisfied)
in_edges = [
e
for e in rhs.edges_from_dependents()
if e.parent.satisfies(e.when)
or (lhss and all(lhs.satisfies(e.when) for lhs in lhss))
if e.parent.satisfies(e.when) or any(lhp.satisfies(e.when) for lhp in lhs_parents)
]
if not in_edges:
continue
@ -3676,6 +3686,7 @@ def spid(spec):
depflag=edge.depflag,
virtuals=edge.virtuals,
direct=edge.direct,
when=edge.when,
)
def copy(self, deps: Union[bool, dt.DepTypes, dt.DepFlag] = True, **kwargs):

View File

@ -327,6 +327,26 @@ class TestSpecSemantics:
"ba5e334fe247335f3a116decfb5284100791dc302b5571ff5e664d8f9a6806c2"
),
),
(
"libelf",
"%[when='^c' virtuals=c]gcc ^[when='+mpi' virtuals=mpi]mpich",
"libelf %[when='^c' virtuals=c]gcc ^[when='+mpi' virtuals=mpi]mpich",
),
(
"libelf %[when='^c' virtuals=c]gcc",
"%[when='^c' virtuals=c]gcc@10.3.1",
"libelf%[when='^c' virtuals=c]gcc@10.3.1",
),
(
"libelf %[when='^c' virtuals=c]gcc",
"%[when='^c' virtuals=c]gcc@10.3.1 ^[when='+mpi'] mpich",
"libelf%[when='^c' virtuals=c]gcc@10.3.1 ^[when='+mpi']mpich",
),
(
"libelf %[when='^c' virtuals=c]gcc",
"%[when='^cxx' virtuals=cxx]gcc@10.3.1",
"libelf%[when='^c' virtuals=c]gcc %[when='^cxx' virtuals=cxx]gcc@10.3.1",
),
],
)
def test_abstract_specs_can_constrain_each_other(self, lhs, rhs, expected):
@ -573,6 +593,14 @@ def test_abstract_specs_with_propagation(self, lhs, rhs, expected, constrained):
c.constrain(lhs)
assert c == constrained
def test_satisfies_conditional_dep(self):
concrete = spack.concretize.concretize_one("mpileaks^mpich")
assert concrete.satisfies("^[when='^mpi' virtuals=mpi]mpich")
assert concrete.satisfies("^[when='^notapackage']zmpi")
assert not concrete.satisfies("^[virtuals=blas]mpich")
assert not concrete.satisfies("^[when='^mpi' virtuals=blas]mpich")
assert not concrete.satisfies("^[when='^mpi']zmpi")
def test_satisfies_single_valued_variant(self):
"""Tests that the case reported in
https://github.com/spack/spack/pull/2386#issuecomment-282147639