From d32d5e45fb898835343a8aa8853708f60e14bd9f Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 2 Jan 2017 18:40:57 -0800 Subject: 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 --- lib/spack/spack/cmd/info.py | 11 +++++-- lib/spack/spack/directives.py | 4 ++- lib/spack/spack/provider_index.py | 61 ++++++++++++++++++++------------------ lib/spack/spack/spec.py | 5 ++-- lib/spack/spack/test/concretize.py | 19 ++++++++++++ 5 files changed, 66 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/info.py b/lib/spack/spack/cmd/info.py index 5366ad4aa8..8e7df87a02 100644 --- a/lib/spack/spack/cmd/info.py +++ b/lib/spack/spack/cmd/info.py @@ -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" diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index d499e96513..72656684e0 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -313,7 +313,9 @@ def provides(*specs, **kwargs): 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 diff --git a/lib/spack/spack/provider_index.py b/lib/spack/spack/provider_index.py index 3911947e4a..0e771c6255 100644 --- a/lib/spack/spack/provider_index.py +++ b/lib/spack/spack/provider_index.py @@ -97,35 +97,38 @@ class ProviderIndex(object): 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() - - 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() - - 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) - - # 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) + 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 + + 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 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) + + 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 diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index c96ef1dc30..9ce50a54d3 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -2020,8 +2020,9 @@ class Spec(object): 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 diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 1f8eeaa29e..3cc5c70a5f 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -161,6 +161,25 @@ class TestConcretize(object): 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() -- cgit v1.2.3-70-g09d2