Spec.satisfies accesses Spec.concrete as property (#2928)
* Spec.satisfies accesses Spec.concrete as property Fixes #2760 When copying a spec, _concrete is always set to False for each dependency. "Spec.satisfies" was accessing the member "_concrete" directly instead of using the property "concrete". This means that if you copy a spec, the dependencies will be considered equal, but did not necessarily satisfy one another. Spec.satisfies is a prerequisite for a package to be considered an extension; as a consequence, an extension with run-time dependencies that were also extensions did not activate those extensions. This updates Spec.satisfies to avoid checking the cached member "_concrete" directly. * Added test to check for activation of dependency extension * Added test to check for transitive satisfiability between a spec and its copy
This commit is contained in:
@@ -1560,10 +1560,9 @@ def do_activate(self, force=False):
|
||||
|
||||
# Activate any package dependencies that are also extensions.
|
||||
if not force:
|
||||
for spec in self.spec.traverse(root=False, deptype='run'):
|
||||
if spec.package.extends(self.extendee_spec):
|
||||
if not spec.package.activated:
|
||||
spec.package.do_activate(force=force)
|
||||
for spec in self.dependency_activations():
|
||||
if not spec.package.activated:
|
||||
spec.package.do_activate(force=force)
|
||||
|
||||
self.extendee_spec.package.activate(self, **self.extendee_args)
|
||||
|
||||
@@ -1571,6 +1570,10 @@ def do_activate(self, force=False):
|
||||
tty.msg("Activated extension %s for %s" %
|
||||
(self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@")))
|
||||
|
||||
def dependency_activations(self):
|
||||
return (spec for spec in self.spec.traverse(root=False, deptype='run')
|
||||
if spec.package.extends(self.extendee_spec))
|
||||
|
||||
def activate(self, extension, **kwargs):
|
||||
"""Symlinks all files from the extension into extendee's install dir.
|
||||
|
||||
|
||||
@@ -2011,8 +2011,8 @@ def satisfies(self, other, deps=True, strict=False, strict_deps=False):
|
||||
other = self._autospec(other)
|
||||
|
||||
# The only way to satisfy a concrete spec is to match its hash exactly.
|
||||
if other._concrete:
|
||||
return self._concrete and self.dag_hash() == other.dag_hash()
|
||||
if other.concrete:
|
||||
return self.concrete and self.dag_hash() == other.dag_hash()
|
||||
|
||||
# A concrete provider can satisfy a virtual dependency.
|
||||
if not self.virtual and other.virtual:
|
||||
|
||||
@@ -108,6 +108,13 @@ def test_inheritance_of_diretives():
|
||||
assert 'mpi' in s
|
||||
|
||||
|
||||
def test_dependency_extensions():
|
||||
s = Spec('extension2')
|
||||
s.concretize()
|
||||
deps = set(x.name for x in s.package.dependency_activations())
|
||||
assert deps == set(['extension1'])
|
||||
|
||||
|
||||
def test_import_class_from_package(builtin_mock):
|
||||
from spack.pkg.builtin.mock.mpich import Mpich # noqa
|
||||
|
||||
|
||||
@@ -287,6 +287,14 @@ def test_unsatisfiable_compiler_flag(self):
|
||||
# 'mpich' is concrete:
|
||||
check_unsatisfiable('mpich', 'mpich cppflags="-O3"', True)
|
||||
|
||||
def test_copy_satisfies_transitive(self):
|
||||
spec = Spec('dttop')
|
||||
spec.concretize()
|
||||
copy = spec.copy()
|
||||
for s in spec.traverse():
|
||||
assert s.satisfies(copy[s.name])
|
||||
assert copy[s.name].satisfies(s)
|
||||
|
||||
def test_unsatisfiable_compiler_flag_mismatch(self):
|
||||
# No matchi in specs
|
||||
check_unsatisfiable(
|
||||
|
||||
Reference in New Issue
Block a user