diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py index b103ac1caf..61f5e1d28c 100644 --- a/lib/spack/spack/repo.py +++ b/lib/spack/spack/repo.py @@ -918,8 +918,12 @@ def _read_config(self): @autospec def get(self, spec): """Returns the package associated with the supplied spec.""" - if not self.exists(spec.name): - raise UnknownPackageError(spec.name) + # NOTE: we only check whether the package is None here, not whether it + # actually exists, because we have to load it anyway, and that ends up + # checking for existence. We avoid constructing FastPackageChecker, + # which will stat all packages. + if spec.name is None: + raise UnknownPackageError(None, self) if spec.namespace and spec.namespace != self.namespace: raise UnknownPackageError(spec.name, self.namespace) @@ -1064,7 +1068,16 @@ def all_package_classes(self): def exists(self, pkg_name): """Whether a package with the supplied name exists.""" - return pkg_name in self._pkg_checker + if pkg_name is None: + return False + + # if the FastPackageChecker is already constructed, use it + if self._fast_package_checker: + return pkg_name in self._pkg_checker + + # if not, check for the package.py file + path = self.filename_for_package_name(pkg_name) + return os.path.exists(path) def last_mtime(self): """Time a package file in this repo was last updated.""" @@ -1331,7 +1344,7 @@ def __init__(self, name, repo=None): long_msg = None if name: if repo: - msg = "Package '{0}' not found in repository '{1}'" + msg = "Package '{0}' not found in repository '{1.root}'" msg = msg.format(name, repo) else: msg = "Package '{0}' not found.".format(name) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index aceceda081..609b20e238 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -3193,25 +3193,23 @@ def satisfies(self, other, deps=True, strict=False, strict_deps=False): 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: - try: - pkg = spack.repo.get(self.fullname) - except spack.repo.UnknownEntityError: - # If we can't get package info on this spec, don't treat - # it as a provider of this vdep. - return False - - if pkg.provides(other.name): - 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 - - # Otherwise, first thing we care about is whether the name matches + # If the names are different, we need to consider virtuals if self.name != other.name and self.name and other.name: + # A concrete provider can satisfy a virtual dependency. + if not self.virtual and other.virtual: + try: + pkg = spack.repo.get(self.fullname) + except spack.repo.UnknownEntityError: + # If we can't get package info on this spec, don't treat + # it as a provider of this vdep. + return False + + if pkg.provides(other.name): + for provided, when_specs in pkg.provided.items(): + if any(self.satisfies(when, deps=False, strict=strict) + for when in when_specs): + if provided.satisfies(other): + return True return False # namespaces either match, or other doesn't require one. @@ -4639,7 +4637,8 @@ def spec(self, name): break elif self.accept(HASH): - # Get spec by hash and confirm it matches what we already have + # Get spec by hash and confirm it matches any constraints we + # already read in hash_spec = self.spec_by_hash() if hash_spec.satisfies(spec): spec._dup(hash_spec) diff --git a/lib/spack/spack/test/cmd/pkg.py b/lib/spack/spack/test/cmd/pkg.py index 4f4293d004..f9311b14bc 100644 --- a/lib/spack/spack/test/cmd/pkg.py +++ b/lib/spack/spack/test/cmd/pkg.py @@ -129,7 +129,8 @@ def test_pkg_add(mock_pkg_git_repo): finally: shutil.rmtree('pkg-e') # Removing a package mid-run disrupts Spack's caching - spack.repo.path.repos[0]._fast_package_checker.invalidate() + if spack.repo.path.repos[0]._fast_package_checker: + spack.repo.path.repos[0]._fast_package_checker.invalidate() with pytest.raises(spack.main.SpackCommandError): pkg('add', 'does-not-exist')