Record package repo origins in .spec files

This commit is contained in:
Matthew LeGendre 2015-04-20 13:27:03 -07:00 committed by Todd Gamblin
parent c7b8d09c7f
commit 7ea328659f
3 changed files with 46 additions and 20 deletions

View File

@ -73,12 +73,12 @@ def __init__(self, default_root):
dir1 = list(dups)[0][1]
dir2 = dict(s)[reponame]
tty.die("Package repo %s in directory %s has the same name as the "
"repo in directory %s" %
"repo in directory %s" %
(reponame, dir1, dir2))
# For each repo, create a RepoLoader
self.repo_loaders = dict([(r[0], RepoLoader(r[0], r[1])) for r in self.repos])
self.instances = {}
self.provider_index = None
@ -87,13 +87,13 @@ def _read_reponame_from_directory(self, dir):
"""For a packagerepo directory, read the repo name from the dir/reponame file"""
path = os.path.join(dir, 'reponame')
try:
try:
with closing(open(path, 'r')) as reponame_file:
name = reponame_file.read().lstrip().rstrip()
name = reponame_file.read().lstrip().rstrip()
if not re.match(r'[a-zA-Z][a-zA-Z0-9]+', name):
tty.die("Package repo name '%s', read from %s, is an invalid name. "
"Repo names must began with a letter and only contain letters "
"and numbers." % (name, path))
"and numbers." % (name, path))
return name
except exceptions.IOError, e:
tty.die("Could not read from package repo name file %s" % path)
@ -107,7 +107,7 @@ def _repo_list_from_config(self):
dir_string = config.get('packagerepo', 'directories')
return dir_string.split(':')
@_autospec
def get(self, spec, **kwargs):
if spec.virtual:
@ -118,7 +118,7 @@ def get(self, spec, **kwargs):
del self.instances[spec]
if not spec in self.instances:
package_class = self.get_class_for_package_name(spec.name)
package_class = self.get_class_for_package_name(spec.name, spec.repo)
try:
copy = spec.copy()
self.instances[copy] = package_class(copy)
@ -191,7 +191,7 @@ def repo_for_package_name(self, pkg_name, packagerepo_name=None):
path = join_path(pkgrepo[1], pkg_name)
if os.path.exists(path):
return (pkgrepo[0], path)
repo_to_add_to = roots[-1]
return (repo_to_add_to[0], join_path(repo_to_add_to[1], pkg_name))
@ -259,7 +259,7 @@ def all_package_names(self):
if os.path.isfile(pkg_file):
all_packages.add(pkg_name)
all_package_names = list(all_packages)
all_package_names.sort()
all_package_names.sort()
return all_package_names
@ -275,12 +275,12 @@ def exists(self, pkg_name):
@memoized
def get_class_for_package_name(self, pkg_name):
def get_class_for_package_name(self, pkg_name, reponame = None):
"""Get an instance of the class for a particular package."""
repo = self.repo_for_package_name(pkg_name)
module_name = imported_packages_module + '.' + repo[0] + '.' + pkg_name
(reponame, repodir) = self.repo_for_package_name(pkg_name, reponame)
module_name = imported_packages_module + '.' + reponame + '.' + pkg_name
module = self.repo_loaders[repo[0]].get_module(pkg_name)
module = self.repo_loaders[reponame].get_module(pkg_name)
class_name = mod_to_class(pkg_name)
cls = getattr(module, class_name)
@ -292,8 +292,13 @@ def get_class_for_package_name(self, pkg_name):
class UnknownPackageError(spack.error.SpackError):
"""Raised when we encounter a package spack doesn't have."""
def __init__(self, name):
super(UnknownPackageError, self).__init__("Package '%s' not found." % name)
def __init__(self, name, repo=None):
msg = None
if repo:
msg = "Package %s not found in packagerepo %s." % (name, repo)
else:
msg = "Package %s not found." % name
super(UnknownPackageError, self).__init__(msg)
self.name = name

View File

@ -100,7 +100,7 @@ def get_module(self, pkg_name):
if not os.access(file_path, os.R_OK):
tty.die("Cannot read '%s'!" % file_path)
else:
raise spack.packages.UnknownPackageError(pkg_name)
raise spack.packages.UnknownPackageError(pkg_name, self.reponame if self.reponame != 'original' else None)
try:
module_name = imported_packages_module + '.' + self.reponame + '.' + pkg_name

View File

@ -112,6 +112,7 @@
from spack.util.string import *
from spack.util.prefix import Prefix
from spack.virtual import ProviderIndex
from spack.repo_loader import imported_packages_module
# Valid pattern for an identifier in Spack
identifier_re = r'\w[\w-]*'
@ -412,6 +413,7 @@ def __init__(self, spec_like, *dep_like, **kwargs):
self.dependencies = other.dependencies
self.variants = other.variants
self.variants.spec = self
self.repo = other.repo
# Specs are by default not assumed to be normal, but in some
# cases we've read them from a file want to assume normal.
@ -1355,6 +1357,7 @@ def _dup(self, other, **kwargs):
self.dependencies = DependencyMap()
self.variants = other.variants.copy()
self.variants.spec = self
self.repo = other.repo
# If we copy dependencies, preserve DAG structure in the new spec
if kwargs.get('deps', True):
@ -1503,6 +1506,7 @@ def format(self, format_string='$_$@$%@$+$=', **kwargs):
in the format string. The format strings you can provide are::
$_ Package name
$. Long package name
$@ Version
$% Compiler
$%@ Compiler & compiler version
@ -1550,6 +1554,9 @@ def write(s, c):
if c == '_':
out.write(fmt % self.name)
elif c == '.':
longname = '%s.%s.%s' % (imported_packages_module, self.repo, self.name) if self.repo else self.name
out.write(fmt % longname)
elif c == '@':
if self.versions and self.versions != _any_version:
write(fmt % (c + str(self.versions)), c)
@ -1698,17 +1705,29 @@ def parse_compiler(self, text):
def spec(self):
"""Parse a spec out of the input. If a spec is supplied, then initialize
and return it instead of creating a new one."""
self.check_identifier()
spec_name = None
spec_repo = None
if self.token.value.startswith(imported_packages_module):
lst = self.token.value.split('.')
spec_name = lst[-1]
spec_repo = lst[-2]
else:
spec_name = self.token.value
(spec_repo, repodir) = spack.db.repo_for_package_name(spec_name)
self.check_identifier(spec_name)
# This will init the spec without calling __init__.
spec = Spec.__new__(Spec)
spec.name = self.token.value
spec.name = spec_name
spec.versions = VersionList()
spec.variants = VariantMap(spec)
spec.architecture = None
spec.compiler = None
spec.dependents = DependencyMap()
spec.dependencies = DependencyMap()
spec.repo = spec_repo
spec._normal = False
spec._concrete = False
@ -1802,12 +1821,14 @@ def compiler(self):
return compiler
def check_identifier(self):
def check_identifier(self, id=None):
"""The only identifiers that can contain '.' are versions, but version
ids are context-sensitive so we have to check on a case-by-case
basis. Call this if we detect a version id where it shouldn't be.
"""
if '.' in self.token.value:
if not id:
id = self.token.value
if '.' in id:
self.last_token_error("Identifier cannot contain '.'")