Fix issues when a package provides the same vdep twice. (#2710)

* Fix issues when a package provides the same vdep twice.

- provides() now adds to a set of provided vdeps instead of a single one.

* flake8
This commit is contained in:
Todd Gamblin
2017-01-02 18:40:57 -08:00
committed by GitHub
parent 34d23c617c
commit d32d5e45fb
6 changed files with 111 additions and 28 deletions

View File

@@ -106,8 +106,15 @@ def print_text_info(pkg):
print
print "Virtual Packages: "
if pkg.provided:
for spec, when in pkg.provided.items():
print " %s provides %s" % (when, spec)
inverse_map = {}
for spec, whens in pkg.provided.items():
for when in whens:
if when not in inverse_map:
inverse_map[when] = set()
inverse_map[when].add(spec)
for when, specs in reversed(sorted(inverse_map.items())):
print " %s provides %s" % (
when, ', '.join(str(s) for s in specs))
else:
print " None"

View File

@@ -313,7 +313,9 @@ def _execute(pkg):
for provided_spec in spack.spec.parse(string):
if pkg.name == provided_spec.name:
raise CircularReferenceError('depends_on', pkg.name)
pkg.provided[provided_spec] = provider_spec
if provided_spec not in pkg.provided:
pkg.provided[provided_spec] = set()
pkg.provided[provided_spec].add(provider_spec)
return _execute

View File

@@ -97,35 +97,38 @@ def update(self, spec):
assert(not spec.virtual)
pkg = spec.package
for provided_spec, provider_spec in pkg.provided.iteritems():
# We want satisfaction other than flags
provider_spec.compiler_flags = spec.compiler_flags.copy()
for provided_spec, provider_specs in pkg.provided.iteritems():
for provider_spec in provider_specs:
# TODO: fix this comment.
# We want satisfaction other than flags
provider_spec.compiler_flags = spec.compiler_flags.copy()
if spec.satisfies(provider_spec, deps=False):
provided_name = provided_spec.name
if spec.satisfies(provider_spec, deps=False):
provided_name = provided_spec.name
provider_map = self.providers.setdefault(provided_name, {})
if provided_spec not in provider_map:
provider_map[provided_spec] = set()
provider_map = self.providers.setdefault(provided_name, {})
if provided_spec not in provider_map:
provider_map[provided_spec] = set()
if self.restrict:
provider_set = provider_map[provided_spec]
if self.restrict:
provider_set = provider_map[provided_spec]
# If this package existed in the index before,
# need to take the old versions out, as they're
# now more constrained.
old = set([s for s in provider_set if s.name == spec.name])
provider_set.difference_update(old)
# If this package existed in the index before,
# need to take the old versions out, as they're
# now more constrained.
old = set(
[s for s in provider_set if s.name == spec.name])
provider_set.difference_update(old)
# Now add the new version.
provider_set.add(spec)
# Now add the new version.
provider_set.add(spec)
else:
# Before putting the spec in the map, constrain it so that
# it provides what was asked for.
constrained = spec.copy()
constrained.constrain(provider_spec)
provider_map[provided_spec].add(constrained)
else:
# Before putting the spec in the map, constrain
# it so that it provides what was asked for.
constrained = spec.copy()
constrained.constrain(provider_spec)
provider_map[provided_spec].add(constrained)
def providers_for(self, *vpkg_specs):
"""Gives specs of all packages that provide virtual packages

View File

@@ -2020,8 +2020,9 @@ def satisfies(self, other, deps=True, strict=False):
if not self.virtual and other.virtual:
pkg = spack.repo.get(self.fullname)
if pkg.provides(other.name):
for provided, when_spec in pkg.provided.items():
if self.satisfies(when_spec, deps=False, strict=strict):
for provided, when_specs in pkg.provided.items():
if any(self.satisfies(when_spec, deps=False, strict=strict)
for when_spec in when_specs):
if provided.satisfies(other):
return True
return False

View File

@@ -161,6 +161,25 @@ def test_concretize_with_provides_when(self):
s.satisfies('mpich2') for s in repo.providers_for('mpi@3')
)
def test_provides_handles_multiple_providers_of_same_vesrion(self):
"""
"""
providers = spack.repo.providers_for('mpi@3.0')
# Note that providers are repo-specific, so we don't misinterpret
# providers, but vdeps are not namespace-specific, so we can
# associate vdeps across repos.
assert Spec('builtin.mock.multi-provider-mpi@1.10.3') in providers
assert Spec('builtin.mock.multi-provider-mpi@1.10.2') in providers
assert Spec('builtin.mock.multi-provider-mpi@1.10.1') in providers
assert Spec('builtin.mock.multi-provider-mpi@1.10.0') in providers
assert Spec('builtin.mock.multi-provider-mpi@1.8.8') in providers
def concretize_multi_provider(self):
s = Spec('mpileaks ^multi-provider-mpi@3.0')
s.concretize()
assert s['mpi'].version == ver('1.10.3')
def test_concretize_two_virtuals(self):
"""Test a package with multiple virtual dependencies."""
Spec('hypre').concretize()