bugfix for matrices with dependencies by hash (#22991)
Dependencies specified by hash are unique in Spack in that the abstract specs are created with internal structure. In this case, the constraint generation for spec matrices fails due to flattening the structure. It turns out that the dep_difference method for Spec.constrain does not need to operate on transitive deps to ensure correctness. Removing transitive deps from this method resolves the bug. - [x] Includes regression test
This commit is contained in:
@@ -3568,7 +3568,9 @@ def _constrain_dependencies(self, other):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Update with additional constraints from other spec
|
# Update with additional constraints from other spec
|
||||||
for name in other.dep_difference(self):
|
# operate on direct dependencies only, because a concrete dep
|
||||||
|
# represented by hash may have structure that needs to be preserved
|
||||||
|
for name in other.direct_dep_difference(self):
|
||||||
dep_spec_copy = other._get_dependency(name)
|
dep_spec_copy = other._get_dependency(name)
|
||||||
dep_copy = dep_spec_copy.spec
|
dep_copy = dep_spec_copy.spec
|
||||||
deptypes = dep_spec_copy.deptypes
|
deptypes = dep_spec_copy.deptypes
|
||||||
@@ -3589,10 +3591,10 @@ def constrained(self, other, deps=True):
|
|||||||
clone.constrain(other, deps)
|
clone.constrain(other, deps)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
def dep_difference(self, other):
|
def direct_dep_difference(self, other):
|
||||||
"""Returns dependencies in self that are not in other."""
|
"""Returns dependencies in self that are not in other."""
|
||||||
mine = set(s.name for s in self.traverse(root=False))
|
mine = set(dname for dname in self._dependencies)
|
||||||
mine.difference_update(s.name for s in other.traverse(root=False))
|
mine.difference_update(dname for dname in other._dependencies)
|
||||||
return mine
|
return mine
|
||||||
|
|
||||||
def _autospec(self, spec_like):
|
def _autospec(self, spec_like):
|
||||||
@@ -4871,7 +4873,7 @@ def merge_abstract_anonymous_specs(*abstract_specs):
|
|||||||
merged_spec[name].constrain(current_spec_constraint[name], deps=False)
|
merged_spec[name].constrain(current_spec_constraint[name], deps=False)
|
||||||
|
|
||||||
# Update with additional constraints from other spec
|
# Update with additional constraints from other spec
|
||||||
for name in current_spec_constraint.dep_difference(merged_spec):
|
for name in current_spec_constraint.direct_dep_difference(merged_spec):
|
||||||
edge = next(iter(current_spec_constraint.edges_to_dependencies(name)))
|
edge = next(iter(current_spec_constraint.edges_to_dependencies(name)))
|
||||||
merged_spec._add_dependency(edge.spec.copy(), edge.deptypes)
|
merged_spec._add_dependency(edge.spec.copy(), edge.deptypes)
|
||||||
|
|
||||||
|
@@ -200,3 +200,22 @@ def test_spec_list_matrix_exclude(self, mock_packages):
|
|||||||
]
|
]
|
||||||
speclist = SpecList("specs", matrix)
|
speclist = SpecList("specs", matrix)
|
||||||
assert len(speclist.specs) == 1
|
assert len(speclist.specs) == 1
|
||||||
|
|
||||||
|
@pytest.mark.regression("22991")
|
||||||
|
def test_spec_list_constraints_with_structure(
|
||||||
|
self, mock_packages, mock_fetch, install_mockery
|
||||||
|
):
|
||||||
|
# Setup by getting hash and installing package with dep
|
||||||
|
libdwarf_spec = Spec("libdwarf").concretized()
|
||||||
|
libdwarf_spec.package.do_install()
|
||||||
|
|
||||||
|
# Create matrix
|
||||||
|
matrix = {
|
||||||
|
"matrix": [["mpileaks"], ["^callpath"], ["^libdwarf/%s" % libdwarf_spec.dag_hash()]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ensure the concrete spec was retained in the matrix entry of which
|
||||||
|
# it is a dependency
|
||||||
|
speclist = SpecList("specs", [matrix])
|
||||||
|
assert len(speclist.specs) == 1
|
||||||
|
assert libdwarf_spec in speclist.specs[0]
|
||||||
|
Reference in New Issue
Block a user