From dcdd16b35e128c5cdc22ea12324dcd5a619db4f7 Mon Sep 17 00:00:00 2001 From: scheibelp Date: Wed, 25 Oct 2017 12:08:03 -0700 Subject: Check for namespace-qualified packages in repo_for_pkg (#5787) * Fixes #5754 Previously when RepoPath.repo_for_pkg was invoked with a string, it did not check if the string included a namespace. Any namespace-qualified package provided as a string would not be found (at which point the behavior was to return the highest-precedence repository). * handle nested namespaces for packages specified as strings in repo_for_pkg * add preliminary repository tests * add test which replicates #5754 * refactor repo tests with fixtures * define repo_path equivalent at test-level scope for repo tests * add tests for unknown namespace/package * rename fixture function (no longer prefixed with 'test_') --- lib/spack/spack/repository.py | 22 +++++++------ lib/spack/spack/test/repo.py | 76 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 lib/spack/spack/test/repo.py (limited to 'lib') diff --git a/lib/spack/spack/repository.py b/lib/spack/spack/repository.py index dedab9f51c..474dd4127e 100644 --- a/lib/spack/spack/repository.py +++ b/lib/spack/spack/repository.py @@ -542,19 +542,21 @@ class RepoPath(object): """Given a spec, get the repository for its package.""" # We don't @_autospec this function b/c it's called very frequently # and we want to avoid parsing str's into Specs unnecessarily. + namespace = None if isinstance(spec, spack.spec.Spec): - # If the spec already has a namespace, then return the - # corresponding repo if we know about it. - if spec.namespace: - fullspace = '%s.%s' % (self.super_namespace, spec.namespace) - if fullspace not in self.by_namespace: - raise UnknownNamespaceError(spec.namespace) - return self.by_namespace[fullspace] + namespace = spec.namespace name = spec.name - else: # handle strings directly for speed instead of @_autospec'ing - name = spec + namespace, _, name = spec.rpartition('.') + + # If the spec already has a namespace, then return the + # corresponding repo if we know about it. + if namespace: + fullspace = '%s.%s' % (self.super_namespace, namespace) + if fullspace not in self.by_namespace: + raise UnknownNamespaceError(spec.namespace) + return self.by_namespace[fullspace] # If there's no namespace, search in the RepoPath. for repo in self.repos: @@ -818,7 +820,7 @@ class Repo(object): @_autospec def get(self, spec, new=False): - if spec.virtual: + if not self.exists(spec.name): raise UnknownPackageError(spec.name) if spec.namespace and spec.namespace != self.namespace: diff --git a/lib/spack/spack/test/repo.py b/lib/spack/spack/test/repo.py new file mode 100644 index 0000000000..8e1af931f0 --- /dev/null +++ b/lib/spack/spack/test/repo.py @@ -0,0 +1,76 @@ +############################################################################## +# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/spack +# Please also see the NOTICE and LICENSE files for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## +import spack + +import pytest + + +# Unlike the repo_path fixture defined in conftest, this has a test-level +# scope rather than a session level scope, since we want to edit the +# given RepoPath +@pytest.fixture() +def repo_for_test(): + return spack.repository.RepoPath(spack.mock_packages_path) + + +@pytest.fixture() +def extra_repo(tmpdir_factory): + repo_namespace = 'extra_test_repo' + repo_dir = tmpdir_factory.mktemp(repo_namespace) + repo_dir.ensure('packages', dir=True) + + with open(str(repo_dir.join('repo.yaml')), 'w') as F: + F.write(""" +repo: + namespace: extra_test_repo +""") + return spack.repository.Repo(str(repo_dir)) + + +def test_repo_getpkg(repo_for_test): + repo_for_test.get('a') + repo_for_test.get('builtin.mock.a') + + +def test_repo_multi_getpkg(repo_for_test, extra_repo): + repo_for_test.put_first(extra_repo) + repo_for_test.get('a') + repo_for_test.get('builtin.mock.a') + + +def test_repo_multi_getpkgclass(repo_for_test, extra_repo): + repo_for_test.put_first(extra_repo) + repo_for_test.get_pkg_class('a') + repo_for_test.get_pkg_class('builtin.mock.a') + + +def test_repo_pkg_with_unknown_namespace(repo_for_test): + with pytest.raises(spack.repository.UnknownNamespaceError): + repo_for_test.get('unknown.a') + + +def test_repo_unknown_pkg(repo_for_test): + with pytest.raises(spack.repository.UnknownPackageError): + repo_for_test.get('builtin.mock.nonexistentpackage') -- cgit v1.2.3-60-g2f50