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:
Greg Becker
2022-11-06 16:49:35 -08:00
committed by GitHub
parent fce7bf179f
commit 4b84cd8af5
2 changed files with 26 additions and 5 deletions

View File

@@ -3568,7 +3568,9 @@ def _constrain_dependencies(self, other):
)
# 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_copy = dep_spec_copy.spec
deptypes = dep_spec_copy.deptypes
@@ -3589,10 +3591,10 @@ def constrained(self, other, deps=True):
clone.constrain(other, deps)
return clone
def dep_difference(self, other):
def direct_dep_difference(self, other):
"""Returns dependencies in self that are not in other."""
mine = set(s.name for s in self.traverse(root=False))
mine.difference_update(s.name for s in other.traverse(root=False))
mine = set(dname for dname in self._dependencies)
mine.difference_update(dname for dname in other._dependencies)
return mine
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)
# 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)))
merged_spec._add_dependency(edge.spec.copy(), edge.deptypes)

View File

@@ -200,3 +200,22 @@ def test_spec_list_matrix_exclude(self, mock_packages):
]
speclist = SpecList("specs", matrix)
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]