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

View File

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

View File

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