Add packagerepos to spack, allowing for creating multiple package repositories.
This commit is contained in:
parent
c8f65c1530
commit
c7b8d09c7f
7 changed files with 343 additions and 48 deletions
|
@ -62,6 +62,12 @@
|
||||||
mock_site_config = join_path(mock_config_path, "site_spackconfig")
|
mock_site_config = join_path(mock_config_path, "site_spackconfig")
|
||||||
mock_user_config = join_path(mock_config_path, "user_spackconfig")
|
mock_user_config = join_path(mock_config_path, "user_spackconfig")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Setup the spack.repos namespace
|
||||||
|
#
|
||||||
|
from spack.repo_loader import RepoNamespace
|
||||||
|
repos = RepoNamespace()
|
||||||
|
|
||||||
#
|
#
|
||||||
# This controls how spack lays out install prefixes and
|
# This controls how spack lays out install prefixes and
|
||||||
# stage directories.
|
# stage directories.
|
||||||
|
|
|
@ -157,7 +157,7 @@ def set_build_environment_variables(pkg):
|
||||||
path_set("PKG_CONFIG_PATH", pkg_config_dirs)
|
path_set("PKG_CONFIG_PATH", pkg_config_dirs)
|
||||||
|
|
||||||
|
|
||||||
def set_module_variables_for_package(pkg):
|
def set_module_variables_for_package(pkg, m):
|
||||||
"""Populate the module scope of install() with some useful functions.
|
"""Populate the module scope of install() with some useful functions.
|
||||||
This makes things easier for package writers.
|
This makes things easier for package writers.
|
||||||
"""
|
"""
|
||||||
|
@ -228,11 +228,32 @@ def get_rpaths(pkg):
|
||||||
return rpaths
|
return rpaths
|
||||||
|
|
||||||
|
|
||||||
|
def parent_class_modules(cls):
|
||||||
|
"""Get list of super class modules that are all descend from spack.Package"""
|
||||||
|
if not issubclass(cls, spack.Package) or issubclass(spack.Package, cls):
|
||||||
|
return []
|
||||||
|
result = []
|
||||||
|
module = sys.modules.get(cls.__module__)
|
||||||
|
if module:
|
||||||
|
result = [ module ]
|
||||||
|
for c in cls.__bases__:
|
||||||
|
result.extend(parent_class_modules(c))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def setup_package(pkg):
|
def setup_package(pkg):
|
||||||
"""Execute all environment setup routines."""
|
"""Execute all environment setup routines."""
|
||||||
set_compiler_environment_variables(pkg)
|
set_compiler_environment_variables(pkg)
|
||||||
set_build_environment_variables(pkg)
|
set_build_environment_variables(pkg)
|
||||||
set_module_variables_for_package(pkg)
|
|
||||||
|
# If a user makes their own package repo, e.g.
|
||||||
|
# spack.repos.mystuff.libelf.Libelf, and they inherit from
|
||||||
|
# an existing class like spack.repos.original.libelf.Libelf,
|
||||||
|
# then set the module variables for both classes so the
|
||||||
|
# parent class can still use them if it gets called.
|
||||||
|
modules = parent_class_modules(pkg.__class__)
|
||||||
|
for mod in modules:
|
||||||
|
set_module_variables_for_package(pkg, mod)
|
||||||
|
|
||||||
# Allow dependencies to set up environment as well.
|
# Allow dependencies to set up environment as well.
|
||||||
for dep_spec in pkg.spec.traverse(root=False):
|
for dep_spec in pkg.spec.traverse(root=False):
|
||||||
|
|
|
@ -93,6 +93,9 @@ def setup_parser(subparser):
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-n', '--name', dest='alternate_name', default=None,
|
'-n', '--name', dest='alternate_name', default=None,
|
||||||
help="Override the autodetected name for the created package.")
|
help="Override the autodetected name for the created package.")
|
||||||
|
subparser.add_argument(
|
||||||
|
'-p', '--package-repo', dest='package_repo', default=None,
|
||||||
|
help="Create the package in the specified packagerepo.")
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-f', '--force', action='store_true', dest='force',
|
'-f', '--force', action='store_true', dest='force',
|
||||||
help="Overwrite any existing package file with the same name.")
|
help="Overwrite any existing package file with the same name.")
|
||||||
|
@ -160,12 +163,21 @@ def create(parser, args):
|
||||||
tty.die("Couldn't guess a name for this package. Try running:", "",
|
tty.die("Couldn't guess a name for this package. Try running:", "",
|
||||||
"spack create --name <name> <url>")
|
"spack create --name <name> <url>")
|
||||||
|
|
||||||
|
package_repo = args.package_repo
|
||||||
|
|
||||||
if not valid_module_name(name):
|
if not valid_module_name(name):
|
||||||
tty.die("Package name can only contain A-Z, a-z, 0-9, '_' and '-'")
|
tty.die("Package name can only contain A-Z, a-z, 0-9, '_' and '-'")
|
||||||
|
|
||||||
tty.msg("This looks like a URL for %s version %s." % (name, version))
|
tty.msg("This looks like a URL for %s version %s." % (name, version))
|
||||||
tty.msg("Creating template for package %s" % name)
|
tty.msg("Creating template for package %s" % name)
|
||||||
|
|
||||||
|
# Create a directory for the new package.
|
||||||
|
pkg_path = spack.db.filename_for_package_name(name, package_repo)
|
||||||
|
if os.path.exists(pkg_path) and not args.force:
|
||||||
|
tty.die("%s already exists." % pkg_path)
|
||||||
|
else:
|
||||||
|
mkdirp(os.path.dirname(pkg_path))
|
||||||
|
|
||||||
versions = spack.package.find_versions_of_archive(url)
|
versions = spack.package.find_versions_of_archive(url)
|
||||||
rkeys = sorted(versions.keys(), reverse=True)
|
rkeys = sorted(versions.keys(), reverse=True)
|
||||||
versions = OrderedDict(zip(rkeys, (versions[v] for v in rkeys)))
|
versions = OrderedDict(zip(rkeys, (versions[v] for v in rkeys)))
|
||||||
|
|
85
lib/spack/spack/cmd/packagerepo.py
Normal file
85
lib/spack/spack/cmd/packagerepo.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://scalability-llnl.github.io/spack
|
||||||
|
# Please also see the LICENSE file 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 General Public License (as published by
|
||||||
|
# the Free Software Foundation) version 2.1 dated 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 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
|
||||||
|
##############################################################################
|
||||||
|
from external import argparse
|
||||||
|
|
||||||
|
import llnl.util.tty as tty
|
||||||
|
from llnl.util.tty.color import colorize
|
||||||
|
from llnl.util.tty.colify import colify
|
||||||
|
from llnl.util.lang import index_by
|
||||||
|
|
||||||
|
import spack.spec
|
||||||
|
import spack.config
|
||||||
|
from spack.util.environment import get_path
|
||||||
|
|
||||||
|
description = "Manage package sources"
|
||||||
|
|
||||||
|
def setup_parser(subparser):
|
||||||
|
sp = subparser.add_subparsers(
|
||||||
|
metavar='SUBCOMMAND', dest='packagerepo_command')
|
||||||
|
|
||||||
|
add_parser = sp.add_parser('add', help=packagerepo_add.__doc__)
|
||||||
|
add_parser.add_argument('directory', help="Directory containing the packages.")
|
||||||
|
|
||||||
|
remove_parser = sp.add_parser('remove', help=packagerepo_remove.__doc__)
|
||||||
|
remove_parser.add_argument('name')
|
||||||
|
|
||||||
|
list_parser = sp.add_parser('list', help=packagerepo_list.__doc__)
|
||||||
|
|
||||||
|
|
||||||
|
def packagerepo_add(args):
|
||||||
|
"""Add package sources to the Spack configuration."""
|
||||||
|
config = spack.config.get_config()
|
||||||
|
user_config = spack.config.get_config('user')
|
||||||
|
orig = None
|
||||||
|
if config.has_value('packagerepo', '', 'directories'):
|
||||||
|
orig = config.get_value('packagerepo', '', 'directories')
|
||||||
|
if orig and args.directory in orig.split(':'):
|
||||||
|
tty.die('Repo directory %s already exists in the repo list' % args.directory)
|
||||||
|
|
||||||
|
newsetting = orig + ':' + args.directory if orig else args.directory
|
||||||
|
user_config.set_value('packagerepo', '', 'directories', newsetting)
|
||||||
|
user_config.write()
|
||||||
|
|
||||||
|
|
||||||
|
def packagerepo_remove(args):
|
||||||
|
"""Remove a package source from the Spack configuration"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def packagerepo_list(args):
|
||||||
|
"""List package sources and their mnemoics"""
|
||||||
|
root_names = spack.db.repos
|
||||||
|
max_len = max(len(s[0]) for s in root_names)
|
||||||
|
fmt = "%%-%ds%%s" % (max_len + 4)
|
||||||
|
for root in root_names:
|
||||||
|
print fmt % (root[0], root[1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def packagerepo(parser, args):
|
||||||
|
action = { 'add' : packagerepo_add,
|
||||||
|
'remove' : packagerepo_remove,
|
||||||
|
'list' : packagerepo_list }
|
||||||
|
action[args.packagerepo_command](args)
|
|
@ -23,10 +23,14 @@
|
||||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import os
|
import os
|
||||||
|
import exceptions
|
||||||
import sys
|
import sys
|
||||||
import inspect
|
import inspect
|
||||||
import glob
|
import glob
|
||||||
import imp
|
import imp
|
||||||
|
import spack.config
|
||||||
|
import re
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.filesystem import join_path
|
from llnl.util.filesystem import join_path
|
||||||
|
@ -36,13 +40,11 @@
|
||||||
import spack.spec
|
import spack.spec
|
||||||
from spack.virtual import ProviderIndex
|
from spack.virtual import ProviderIndex
|
||||||
from spack.util.naming import mod_to_class, validate_module_name
|
from spack.util.naming import mod_to_class, validate_module_name
|
||||||
|
from sets import Set
|
||||||
|
from spack.repo_loader import RepoLoader, imported_packages_module, package_file_name
|
||||||
|
|
||||||
# Name of module under which packages are imported
|
# Filename for package repo names
|
||||||
_imported_packages_module = 'spack.packages'
|
_packagerepo_filename = 'reponame'
|
||||||
|
|
||||||
# Name of the package file inside a package directory
|
|
||||||
_package_file_name = 'package.py'
|
|
||||||
|
|
||||||
|
|
||||||
def _autospec(function):
|
def _autospec(function):
|
||||||
"""Decorator that automatically converts the argument of a single-arg
|
"""Decorator that automatically converts the argument of a single-arg
|
||||||
|
@ -55,13 +57,57 @@ def converter(self, spec_like, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
class PackageDB(object):
|
class PackageDB(object):
|
||||||
def __init__(self, root):
|
def __init__(self, default_root):
|
||||||
"""Construct a new package database from a root directory."""
|
"""Construct a new package database from a root directory."""
|
||||||
self.root = root
|
|
||||||
|
#Collect the repos from the config file and read their names from the file system
|
||||||
|
repo_dirs = self._repo_list_from_config()
|
||||||
|
repo_dirs.append(default_root)
|
||||||
|
self.repos = [(self._read_reponame_from_directory(dir), dir) for dir in repo_dirs]
|
||||||
|
|
||||||
|
# Check for duplicate repo names
|
||||||
|
s = set()
|
||||||
|
dups = set(r for r in self.repos if r[0] in s or s.add(r[0]))
|
||||||
|
if dups:
|
||||||
|
reponame = list(dups)[0][0]
|
||||||
|
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" %
|
||||||
|
(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.instances = {}
|
||||||
self.provider_index = None
|
self.provider_index = None
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
with closing(open(path, 'r')) as reponame_file:
|
||||||
|
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))
|
||||||
|
return name
|
||||||
|
except exceptions.IOError, e:
|
||||||
|
tty.die("Could not read from package repo name file %s" % path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _repo_list_from_config(self):
|
||||||
|
"""Read through the spackconfig and return the list of packagerepo directories"""
|
||||||
|
config = spack.config.get_config()
|
||||||
|
if not config.has_option('packagerepo', 'directories'): return []
|
||||||
|
dir_string = config.get('packagerepo', 'directories')
|
||||||
|
return dir_string.split(':')
|
||||||
|
|
||||||
|
|
||||||
@_autospec
|
@_autospec
|
||||||
def get(self, spec, **kwargs):
|
def get(self, spec, **kwargs):
|
||||||
if spec.virtual:
|
if spec.virtual:
|
||||||
|
@ -130,13 +176,33 @@ def installed_extensions_for(self, extendee_spec):
|
||||||
# catching exceptions.
|
# catching exceptions.
|
||||||
|
|
||||||
|
|
||||||
def dirname_for_package_name(self, pkg_name):
|
def repo_for_package_name(self, pkg_name, packagerepo_name=None):
|
||||||
|
"""Find the dirname for a package and the packagerepo it came from
|
||||||
|
if packagerepo_name is not None, then search for the package in the
|
||||||
|
specified packagerepo"""
|
||||||
|
#Look for an existing package under any matching packagerepos
|
||||||
|
roots = [pkgrepo for pkgrepo in self.repos
|
||||||
|
if not packagerepo_name or packagerepo_name == pkgrepo[0]]
|
||||||
|
|
||||||
|
if not roots:
|
||||||
|
tty.die("Package repo %s does not exist" % packagerepo_name)
|
||||||
|
|
||||||
|
for pkgrepo in roots:
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
def dirname_for_package_name(self, pkg_name, packagerepo_name=None):
|
||||||
"""Get the directory name for a particular package. This is the
|
"""Get the directory name for a particular package. This is the
|
||||||
directory that contains its package.py file."""
|
directory that contains its package.py file."""
|
||||||
return join_path(self.root, pkg_name)
|
return self.repo_for_package_name(pkg_name, packagerepo_name)[1]
|
||||||
|
|
||||||
|
|
||||||
def filename_for_package_name(self, pkg_name):
|
def filename_for_package_name(self, pkg_name, packagerepo_name=None):
|
||||||
"""Get the filename for the module we should load for a particular
|
"""Get the filename for the module we should load for a particular
|
||||||
package. Packages for a pacakge DB live in
|
package. Packages for a pacakge DB live in
|
||||||
``$root/<package_name>/package.py``
|
``$root/<package_name>/package.py``
|
||||||
|
@ -144,10 +210,15 @@ def filename_for_package_name(self, pkg_name):
|
||||||
This will return a proper package.py path even if the
|
This will return a proper package.py path even if the
|
||||||
package doesn't exist yet, so callers will need to ensure
|
package doesn't exist yet, so callers will need to ensure
|
||||||
the package exists before importing.
|
the package exists before importing.
|
||||||
|
|
||||||
|
If a packagerepo is specified, then return existing
|
||||||
|
or new paths in the specified packagerepo directory. If no
|
||||||
|
package repo is supplied, return an existing path from any
|
||||||
|
package repo, and new paths in the default package repo.
|
||||||
"""
|
"""
|
||||||
validate_module_name(pkg_name)
|
validate_module_name(pkg_name)
|
||||||
pkg_dir = self.dirname_for_package_name(pkg_name)
|
pkg_dir = self.dirname_for_package_name(pkg_name, packagerepo_name)
|
||||||
return join_path(pkg_dir, _package_file_name)
|
return join_path(pkg_dir, package_file_name)
|
||||||
|
|
||||||
|
|
||||||
def installed_package_specs(self):
|
def installed_package_specs(self):
|
||||||
|
@ -176,13 +247,18 @@ def installed_known_package_specs(self):
|
||||||
@memoized
|
@memoized
|
||||||
def all_package_names(self):
|
def all_package_names(self):
|
||||||
"""Generator function for all packages. This looks for
|
"""Generator function for all packages. This looks for
|
||||||
``<pkg_name>/package.py`` files within the root direcotry"""
|
``<pkg_name>/package.py`` files within the repo direcotories"""
|
||||||
all_package_names = []
|
all_packages = Set()
|
||||||
for pkg_name in os.listdir(self.root):
|
for repo in self.repos:
|
||||||
pkg_dir = join_path(self.root, pkg_name)
|
dir = repo[1]
|
||||||
pkg_file = join_path(pkg_dir, _package_file_name)
|
if not os.path.isdir(dir):
|
||||||
|
continue
|
||||||
|
for pkg_name in os.listdir(dir):
|
||||||
|
pkg_dir = join_path(dir, pkg_name)
|
||||||
|
pkg_file = join_path(pkg_dir, package_file_name)
|
||||||
if os.path.isfile(pkg_file):
|
if os.path.isfile(pkg_file):
|
||||||
all_package_names.append(pkg_name)
|
all_packages.add(pkg_name)
|
||||||
|
all_package_names = list(all_packages)
|
||||||
all_package_names.sort()
|
all_package_names.sort()
|
||||||
return all_package_names
|
return all_package_names
|
||||||
|
|
||||||
|
@ -200,34 +276,13 @@ 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):
|
||||||
"""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)
|
||||||
|
module_name = imported_packages_module + '.' + repo[0] + '.' + pkg_name
|
||||||
|
|
||||||
This method uses Python's ``imp`` package to load python
|
module = self.repo_loaders[repo[0]].get_module(pkg_name)
|
||||||
source from a Spack package's ``package.py`` file. A
|
|
||||||
normal python import would only load each package once, but
|
|
||||||
because we do this dynamically, the method needs to be
|
|
||||||
memoized to ensure there is only ONE package class
|
|
||||||
instance, per package, per database.
|
|
||||||
"""
|
|
||||||
file_path = self.filename_for_package_name(pkg_name)
|
|
||||||
|
|
||||||
if os.path.exists(file_path):
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
tty.die("Something's wrong. '%s' is not a file!" % file_path)
|
|
||||||
if not os.access(file_path, os.R_OK):
|
|
||||||
tty.die("Cannot read '%s'!" % file_path)
|
|
||||||
else:
|
|
||||||
raise UnknownPackageError(pkg_name)
|
|
||||||
|
|
||||||
class_name = mod_to_class(pkg_name)
|
class_name = mod_to_class(pkg_name)
|
||||||
try:
|
|
||||||
module_name = _imported_packages_module + '.' + pkg_name
|
|
||||||
module = imp.load_source(module_name, file_path)
|
|
||||||
|
|
||||||
except ImportError, e:
|
|
||||||
tty.die("Error while importing %s from %s:\n%s" % (
|
|
||||||
pkg_name, file_path, e.message))
|
|
||||||
|
|
||||||
cls = getattr(module, class_name)
|
cls = getattr(module, class_name)
|
||||||
if not inspect.isclass(cls):
|
if not inspect.isclass(cls):
|
||||||
tty.die("%s.%s is not a class" % (pkg_name, class_name))
|
tty.die("%s.%s is not a class" % (pkg_name, class_name))
|
||||||
|
|
115
lib/spack/spack/repo_loader.py
Normal file
115
lib/spack/spack/repo_loader.py
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import spack
|
||||||
|
import spack.repos
|
||||||
|
import re
|
||||||
|
import types
|
||||||
|
from llnl.util.lang import *
|
||||||
|
|
||||||
|
# Name of module under which packages are imported
|
||||||
|
imported_packages_module = 'spack.repos'
|
||||||
|
|
||||||
|
# Name of the package file inside a package directory
|
||||||
|
package_file_name = 'package.py'
|
||||||
|
|
||||||
|
import sys
|
||||||
|
class LazyLoader:
|
||||||
|
"""The LazyLoader handles cases when repo modules or classes
|
||||||
|
are imported. It watches for 'spack.repos.*' loads, then
|
||||||
|
redirects the load to the appropriate module."""
|
||||||
|
def find_module(self, fullname, pathname):
|
||||||
|
if not fullname.startswith(imported_packages_module):
|
||||||
|
return None
|
||||||
|
partial_name = fullname[len(imported_packages_module)+1:]
|
||||||
|
repo = partial_name.split('.')[0]
|
||||||
|
module = partial_name.split('.')[1]
|
||||||
|
repo_loader = spack.db.repo_loaders.get(repo)
|
||||||
|
if repo_loader:
|
||||||
|
try:
|
||||||
|
self.mod = repo_loader.get_module(module)
|
||||||
|
return self
|
||||||
|
except (ImportError, spack.packages.UnknownPackageError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load_module(self, fullname):
|
||||||
|
return self.mod
|
||||||
|
|
||||||
|
sys.meta_path.append(LazyLoader())
|
||||||
|
|
||||||
|
_reponames = {}
|
||||||
|
class RepoNamespace(types.ModuleType):
|
||||||
|
"""The RepoNamespace holds the repository namespaces under
|
||||||
|
spack.repos. For example, when accessing spack.repos.original
|
||||||
|
this class will use __getattr__ to translate the 'original'
|
||||||
|
into one of spack's known repositories"""
|
||||||
|
def __init__(self):
|
||||||
|
import sys
|
||||||
|
sys.modules[imported_packages_module] = self
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name in _reponames:
|
||||||
|
return _reponames[name]
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def __file__(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def __path__(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class RepoLoader(types.ModuleType):
|
||||||
|
"""Each RepoLoader is associated with a repository, and the RepoLoader is
|
||||||
|
responsible for loading packages out of that repository. For example,
|
||||||
|
a RepoLoader may be responsible for spack.repos.original, and when someone
|
||||||
|
references spack.repos.original.libelf that RepoLoader will load the
|
||||||
|
libelf package."""
|
||||||
|
def __init__(self, reponame, repopath):
|
||||||
|
self.path = repopath
|
||||||
|
self.reponame = reponame
|
||||||
|
self.module_name = imported_packages_module + '.' + reponame
|
||||||
|
if not reponame in _reponames:
|
||||||
|
_reponames[reponame] = self
|
||||||
|
spack.repos.add_repo(reponame, self)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.modules[self.module_name] = self
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def __path__(self):
|
||||||
|
return [ self.path ]
|
||||||
|
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name[0] == '_':
|
||||||
|
raise AttributeError
|
||||||
|
return self.get_module(name)
|
||||||
|
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def get_module(self, pkg_name):
|
||||||
|
import os
|
||||||
|
import imp
|
||||||
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
|
file_path = os.path.join(self.path, pkg_name, package_file_name)
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
tty.die("Something's wrong. '%s' is not a file!" % file_path)
|
||||||
|
if not os.access(file_path, os.R_OK):
|
||||||
|
tty.die("Cannot read '%s'!" % file_path)
|
||||||
|
else:
|
||||||
|
raise spack.packages.UnknownPackageError(pkg_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module_name = imported_packages_module + '.' + self.reponame + '.' + pkg_name
|
||||||
|
module = imp.load_source(module_name, file_path)
|
||||||
|
|
||||||
|
except ImportError, e:
|
||||||
|
tty.die("Error while importing %s from %s:\n%s" % (
|
||||||
|
pkg_name, file_path, e.message))
|
||||||
|
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
1
var/spack/packages/reponame
Normal file
1
var/spack/packages/reponame
Normal file
|
@ -0,0 +1 @@
|
||||||
|
original
|
Loading…
Reference in a new issue