From cf2f902b82a3080243eae58ca728b55189108c10 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 28 May 2016 20:13:13 -0500 Subject: [PATCH] Make ProviderIndexes mergeable, so we can cache them per-repo. --- lib/spack/spack/repository.py | 31 +++++++++++++++++++++++-------- lib/spack/spack/test/virtual.py | 6 ++++++ lib/spack/spack/virtual.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/lib/spack/spack/repository.py b/lib/spack/spack/repository.py index bf0dac6a22..6e7e95b8bc 100644 --- a/lib/spack/spack/repository.py +++ b/lib/spack/spack/repository.py @@ -224,12 +224,20 @@ def all_packages(self): yield self.get(name) + @property + def provider_index(self): + """Merged ProviderIndex from all Repos in the RepoPath.""" + if self._provider_index is None: + self._provider_index = ProviderIndex() + for repo in reversed(self.repos): + self._provider_index.merge(repo.provider_index) + + return self._provider_index + + @_autospec def providers_for(self, vpkg_spec): - if self._provider_index is None: - self._provider_index = ProviderIndex(self.all_package_names()) - - providers = self._provider_index.providers_for(vpkg_spec) + providers = self.provider_index.providers_for(vpkg_spec) if not providers: raise UnknownPackageError(vpkg_spec.name) return providers @@ -603,12 +611,19 @@ def purge(self): self._instances.clear() + @property + def provider_index(self): + """A provider index with names *specific* to this repo.""" + if self._provider_index is None: + namespaced_names = ['%s.%s' % (self.namespace, n) + for n in self.all_package_names()] + self._provider_index = ProviderIndex(namespaced_names) + return self._provider_index + + @_autospec def providers_for(self, vpkg_spec): - if self._provider_index is None: - self._provider_index = ProviderIndex(self.all_package_names()) - - providers = self._provider_index.providers_for(vpkg_spec) + providers = self.provider_index.providers_for(vpkg_spec) if not providers: raise UnknownPackageError(vpkg_spec.name) return providers diff --git a/lib/spack/spack/test/virtual.py b/lib/spack/spack/test/virtual.py index 7699165554..1923e7006f 100644 --- a/lib/spack/spack/test/virtual.py +++ b/lib/spack/spack/test/virtual.py @@ -41,3 +41,9 @@ def test_write_and_read(self): q = ProviderIndex.from_yaml(istream) self.assertTrue(p == q) + + + def test_copy(self): + p = ProviderIndex(spack.repo.all_package_names()) + q = p.copy() + self.assertTrue(p == q) diff --git a/lib/spack/spack/virtual.py b/lib/spack/spack/virtual.py index bf6d8227a4..2c47921a3f 100644 --- a/lib/spack/spack/virtual.py +++ b/lib/spack/spack/virtual.py @@ -209,5 +209,33 @@ def from_yaml(stream): return index + def merge(self, other): + """Merge `other` ProviderIndex into this one.""" + other = other.copy() # defensive copy. + + for pkg in other.providers: + if pkg not in self.providers: + self.providers[pkg] = other.providers[pkg] + continue + + spdict, opdict = self.providers[pkg], other.providers[pkg] + for provided_spec in opdict: + if provided_spec not in spdict: + spdict[provided_spec] = opdict[provided_spec] + continue + + spdict[provided_spec] += opdict[provided_spec] + + + def copy(self): + """Deep copy of this ProviderIndex.""" + clone = ProviderIndex() + clone.providers = dict( + (name, dict((vpkg, set((p.copy() for p in pset))) + for vpkg, pset in pdict.items())) + for name, pdict in self.providers.items()) + return clone + + def __eq__(self, other): return self.providers == other.providers