diff options
-rw-r--r-- | etc/spack/install.yaml | 8 | ||||
-rw-r--r-- | lib/spack/spack/__init__.py | 14 | ||||
-rw-r--r-- | lib/spack/spack/build_environment.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/cmd/__init__.py | 10 | ||||
-rw-r--r-- | lib/spack/spack/cmd/common/arguments.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/cmd/deactivate.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/cmd/extensions.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/cmd/find.py | 5 | ||||
-rw-r--r-- | lib/spack/spack/cmd/reindex.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/cmd/uninstall.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/config.py | 6 | ||||
-rw-r--r-- | lib/spack/spack/database.py | 20 | ||||
-rw-r--r-- | lib/spack/spack/directory_layout.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/install_area.py | 36 | ||||
-rw-r--r-- | lib/spack/spack/package.py | 59 | ||||
-rw-r--r-- | lib/spack/spack/repository.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/schema/install.py | 43 | ||||
-rw-r--r-- | lib/spack/spack/spec.py | 7 | ||||
-rw-r--r-- | lib/spack/spack/test/cmd/uninstall.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/test/database.py | 129 | ||||
-rw-r--r-- | lib/spack/spack/test/install.py | 15 | ||||
-rw-r--r-- | lib/spack/spack/test/mock_database.py | 29 |
22 files changed, 254 insertions, 161 deletions
diff --git a/etc/spack/install.yaml b/etc/spack/install.yaml new file mode 100644 index 0000000000..553d09f13e --- /dev/null +++ b/etc/spack/install.yaml @@ -0,0 +1,8 @@ +# ------------------------------------------------------------------------- +# This is the default spack install setup configuration. +# +# Changes to this file will affect all users of this spack install +# ------------------------------------------------------------------------- +install: + path: $spack/opt/spack + layout : YamlDirectoryLayout
\ No newline at end of file diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index cadfa95426..8a0733871f 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -63,7 +63,6 @@ user_cache = FileCache(user_cache_path) prefix = spack_root opt_path = join_path(prefix, "opt") -install_path = join_path(opt_path, "spack") etc_path = join_path(prefix, "etc") # @@ -77,25 +76,12 @@ except spack.error.SpackError, e: tty.die('while initializing Spack RepoPath:', e.message) # -# Set up the installed packages database -# -from spack.database import Database -installed_db = Database(install_path) - -# # Paths to built-in Spack repositories. # packages_path = join_path(repos_path, "builtin") mock_packages_path = join_path(repos_path, "builtin.mock") # -# This controls how spack lays out install prefixes and -# stage directories. -# -from spack.directory_layout import YamlDirectoryLayout -install_layout = YamlDirectoryLayout(install_path) - -# # This controls how packages are sorted when trying to choose # the most preferred package. More preferred packages are sorted # first. diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index abbc385a39..942b525bf6 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -58,6 +58,7 @@ import sys import llnl.util.tty as tty import spack +import spack.install_area from llnl.util.filesystem import * from spack.environment import EnvironmentModifications, validate from spack.util.environment import * @@ -276,7 +277,7 @@ def set_build_environment_variables(pkg, env, dirty=False): env.set(SPACK_PREFIX, pkg.prefix) # Install root prefix - env.set(SPACK_INSTALL, spack.install_path) + env.set(SPACK_INSTALL, spack.install_area.path) # Stuff in here sanitizes the build environemnt to eliminate # anything the user has set that may interfere. diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py index 6b1561b7fc..0da542e930 100644 --- a/lib/spack/spack/cmd/__init__.py +++ b/lib/spack/spack/cmd/__init__.py @@ -27,13 +27,15 @@ import re import sys import llnl.util.tty as tty -import spack -import spack.config -import spack.spec from llnl.util.lang import * from llnl.util.tty.colify import * from llnl.util.tty.color import * +import spack +import spack.config +import spack.spec +import spack.install_area + # # Settings for commands that modify configuration # @@ -135,7 +137,7 @@ def elide_list(line_list, max_num=10): def disambiguate_spec(spec): - matching_specs = spack.installed_db.query(spec) + matching_specs = spack.install_area.db.query(spec) if not matching_specs: tty.die("Spec '%s' matches no installed packages." % spec) diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py index afcba33714..d7d2f9770c 100644 --- a/lib/spack/spack/cmd/common/arguments.py +++ b/lib/spack/spack/cmd/common/arguments.py @@ -25,6 +25,7 @@ import argparse +import spack.install_area import spack.modules from spack.util.pattern import Bunch __all__ = ['add_common_arguments'] @@ -53,7 +54,7 @@ class ConstraintAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): # Query specs from command line d = self.qualifiers.get(namespace.subparser_name, {}) - specs = [s for s in spack.installed_db.query(**d)] + specs = [s for s in spack.install_area.db.query(**d)] values = ' '.join(values) if values: specs = [x for x in specs if x.satisfies(values, strict=True)] diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py index 2b15a0331e..859025034a 100644 --- a/lib/spack/spack/cmd/deactivate.py +++ b/lib/spack/spack/cmd/deactivate.py @@ -27,6 +27,7 @@ import llnl.util.tty as tty import spack import spack.cmd +import spack.install_area from spack.graph import topological_sort description = "Deactivate a package extension." @@ -56,7 +57,7 @@ def deactivate(parser, args): if args.all: if pkg.extendable: tty.msg("Deactivating all extensions of %s" % pkg.spec.short_spec) - ext_pkgs = spack.installed_db.installed_extensions_for(spec) + ext_pkgs = spack.install_area.db.installed_extensions_for(spec) for ext_pkg in ext_pkgs: ext_pkg.spec.normalize() diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py index b5c484305f..49572263c5 100644 --- a/lib/spack/spack/cmd/extensions.py +++ b/lib/spack/spack/cmd/extensions.py @@ -30,6 +30,7 @@ from llnl.util.tty.colify import colify import spack import spack.cmd import spack.cmd.find +import spack.install_area description = "List extensions for package." @@ -86,8 +87,9 @@ def extensions(parser, args): # # List specs of installed extensions. # - installed = [ - s.spec for s in spack.installed_db.installed_extensions_for(spec)] + installed = [s.spec + for s in spack.install_area.db.installed_extensions_for(spec)] + print if not installed: tty.msg("None installed.") @@ -98,7 +100,7 @@ def extensions(parser, args): # # List specs of activated extensions. # - activated = spack.install_layout.extension_map(spec) + activated = spack.install_area.layout.extension_map(spec) print if not activated: tty.msg("None activated.") diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py index d3ea38c573..9e631d6e24 100644 --- a/lib/spack/spack/cmd/find.py +++ b/lib/spack/spack/cmd/find.py @@ -28,6 +28,7 @@ import sys import llnl.util.tty as tty import spack import spack.spec +import spack.install_area from llnl.util.lang import * from llnl.util.tty.colify import * from llnl.util.tty.color import * @@ -145,9 +146,9 @@ def find(parser, args): # Get all the specs the user asked for if not query_specs: - specs = set(spack.installed_db.query(**q_args)) + specs = set(spack.install_area.db.query(**q_args)) else: - results = [set(spack.installed_db.query(qs, **q_args)) + results = [set(spack.install_area.db.query(qs, **q_args)) for qs in query_specs] specs = set.union(*results) diff --git a/lib/spack/spack/cmd/reindex.py b/lib/spack/spack/cmd/reindex.py index e37eebbd92..10c5ea4c05 100644 --- a/lib/spack/spack/cmd/reindex.py +++ b/lib/spack/spack/cmd/reindex.py @@ -23,9 +23,9 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## import spack - +import spack.install_area description = "Rebuild Spack's package database." def reindex(parser, args): - spack.installed_db.reindex(spack.install_layout) + spack.install_area.db.reindex(spack.install_area.layout) diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index bbcd2e787c..26d6080ffb 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -29,6 +29,7 @@ import argparse import llnl.util.tty as tty import spack import spack.cmd +import spack.install_area import spack.repository description = "Remove an installed package" @@ -89,7 +90,7 @@ def concretize_specs(specs, allow_multiple_matches=False, force=False): specs_from_cli = [] has_errors = False for spec in specs: - matching = spack.installed_db.query(spec) + matching = spack.install_area.db.query(spec) # For each spec provided, make sure it refers to only one package. # Fail and ask user to be unambiguous if it doesn't if not allow_multiple_matches and len(matching) > 1: diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py index de5f55775c..89e02e33df 100644 --- a/lib/spack/spack/config.py +++ b/lib/spack/spack/config.py @@ -171,7 +171,7 @@ import spack.schema # Hacked yaml for configuration files preserves line numbers. import spack.util.spack_yaml as syaml -from spack.build_environment import get_path_from_module + """Dict from section names -> schema for that section.""" section_schemas = { @@ -180,6 +180,7 @@ section_schemas = { 'repos': spack.schema.repos.schema, 'packages': spack.schema.packages.schema, 'modules': spack.schema.modules.schema, + 'install': spack.schema.install.schema, } """OrderedDict of config scopes keyed by name. @@ -510,6 +511,9 @@ def print_section(section): def spec_externals(spec): """Return a list of external specs (with external directory path filled in), one for each known external installation.""" + # break circular import. + from spack.build_environment import get_path_from_module + allpkgs = get_config('packages') name = spec.name diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index 80ebf6a2cf..e0db8c3167 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -48,14 +48,15 @@ import llnl.util.tty as tty from llnl.util.filesystem import * from llnl.util.lock import * -import spack.spec +import spack.install_area +import spack.repository from spack.directory_layout import DirectoryLayoutError from spack.version import Version -from spack.spec import * +import spack.spec from spack.error import SpackError -from spack.repository import UnknownPackageError import spack.util.spack_yaml as syaml + # DB goes in this directory underneath the root _db_dirname = '.spack-db' @@ -66,7 +67,7 @@ _db_version = Version('0.9.2') _db_lock_timeout = 60 # Types of dependencies tracked by the database -_tracked_deps = nobuild +_tracked_deps = 'nobuild' def _autospec(function): @@ -218,7 +219,7 @@ class Database(object): spec_dict[name]['hash'] = hash_key # Build spec from dict first. - spec = Spec.from_node_dict(spec_dict) + spec = spack.spec.Spec.from_node_dict(spec_dict) return spec def _assign_dependencies(self, hash_key, installs, data): @@ -229,7 +230,8 @@ class Database(object): if 'dependencies' in spec_dict[spec.name]: yaml_deps = spec_dict[spec.name]['dependencies'] - for dname, dhash, dtypes in Spec.read_yaml_dep_specs(yaml_deps): + for dname, dhash, dtypes in spack.spec.Spec.read_yaml_dep_specs( + yaml_deps): if dhash not in data: tty.warn("Missing dependency not in database: ", "%s needs %s-%s" % ( @@ -278,7 +280,7 @@ class Database(object): if version > _db_version: raise InvalidDatabaseVersionError(_db_version, version) elif version < _db_version: - self.reindex(spack.install_layout) + self.reindex(spack.install_area.layout) installs = dict((k, v.to_dict()) for k, v in self._data.items()) def invalid_record(hash_key, error): @@ -444,7 +446,7 @@ class Database(object): else: # The file doesn't exist, try to traverse the directory. # reindex() takes its own write lock, so no lock here. - self.reindex(spack.install_layout) + self.reindex(spack.install_area.layout) def _add(self, spec, directory_layout=None, explicit=False): """Add an install record for this spec to the database. @@ -587,7 +589,7 @@ class Database(object): try: if s.package.extends(extendee_spec): yield s.package - except UnknownPackageError: + except spack.repository.UnknownPackageError: continue # skips unknown packages # TODO: conditional way to do this instead of catching exceptions diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py index 8ef7d3c480..28e6584fb2 100644 --- a/lib/spack/spack/directory_layout.py +++ b/lib/spack/spack/directory_layout.py @@ -32,7 +32,7 @@ import yaml from llnl.util.filesystem import join_path, mkdirp import spack -from spack.spec import Spec +import spack.spec from spack.error import SpackError @@ -210,7 +210,7 @@ class YamlDirectoryLayout(DirectoryLayout): """Read the contents of a file and parse them as a spec""" try: with open(path) as f: - spec = Spec.from_yaml(f) + spec = spack.spec.Spec.from_yaml(f) except Exception as e: if spack.debug: raise diff --git a/lib/spack/spack/install_area.py b/lib/spack/spack/install_area.py new file mode 100644 index 0000000000..b99df4c570 --- /dev/null +++ b/lib/spack/spack/install_area.py @@ -0,0 +1,36 @@ +__author__ = "Benedikt Hegner (CERN)" + +import re + +import llnl.util.tty as tty +from llnl.util.filesystem import * + +# +# Read in the config +# +import spack.config +config = spack.config.get_config("install") + +# +# Set up the install path +# +path = re.sub(r'^\$spack', spack.prefix, config['path']) + +# +# Set up the installed packages database +# +from spack.database import Database +db = Database(path) + +# +# This controls how spack lays out install prefixes and +# stage directories. +# +import spack.directory_layout + +try: + layout_name = config["layout"] + layout_class = getattr(spack.directory_layout,layout_name) + layout = layout_class(path) +except: + tty.die("Invalid install directory layout %s chosen." %layout_name) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 3a3028885f..d9145508e3 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -47,6 +47,7 @@ from StringIO import StringIO import llnl.util.lock import llnl.util.tty as tty import spack +import spack.install_area import spack.compilers import spack.directives import spack.error @@ -831,7 +832,7 @@ class PackageBase(object): if not self.is_extension: raise ValueError( "is_extension called on package that is not an extension.") - exts = spack.install_layout.extension_map(self.extendee_spec) + exts = spack.install_area.layout.extension_map(self.extendee_spec) return (self.name in exts) and (exts[self.name] == self.spec) def provides(self, vpkg_name): @@ -852,7 +853,7 @@ class PackageBase(object): TODO: move this method to database.py? """ dependents = [] - for spec in spack.installed_db.query(): + for spec in spack.install_area.db.query(): if self.name == spec.name: continue # XXX(deptype): Should build dependencies not count here? @@ -866,7 +867,7 @@ class PackageBase(object): def prefix_lock(self): """Prefix lock is a byte range lock on the nth byte of a file. - The lock file is ``spack.installed_db.prefix_lock`` -- the DB + The lock file is ``spack.install_area.db.prefix_lock`` -- the DB tells us what to call it and it lives alongside the install DB. n is the sys.maxsize-bit prefix of the DAG hash. This makes @@ -878,7 +879,7 @@ class PackageBase(object): prefix = self.spec.prefix if prefix not in Package.prefix_locks: Package.prefix_locks[prefix] = llnl.util.lock.Lock( - spack.installed_db.prefix_lock_path, + spack.install_area.db.prefix_lock_path, self.spec.dag_hash_bit_prefix(bit_length(sys.maxsize)), 1) self._prefix_lock = Package.prefix_locks[prefix] @@ -915,7 +916,7 @@ class PackageBase(object): Removes the prefix for a package along with any empty parent directories """ - spack.install_layout.remove_install_directory(self.spec) + spack.install_area.layout.remove_install_directory(self.spec) def do_fetch(self, mirror_only=False): """ @@ -1152,15 +1153,15 @@ class PackageBase(object): return # Ensure package is not already installed - layout = spack.install_layout + layout = spack.install_area.layout with self._prefix_read_lock(): if layout.check_installed(self.spec): tty.msg( "%s is already installed in %s" % (self.name, self.prefix)) - rec = spack.installed_db.get_record(self.spec) + rec = spack.install_area.db.get_record(self.spec) if (not rec.explicit) and explicit: - with spack.installed_db.write_transaction(): - rec = spack.installed_db.get_record(self.spec) + with spack.install_area.db.write_transaction(): + rec = spack.install_area.db.get_record(self.spec) rec.explicit = True return @@ -1265,15 +1266,15 @@ class PackageBase(object): try: # Create the install prefix and fork the build process. - spack.install_layout.create_install_directory(self.spec) + spack.install_area.layout.create_install_directory(self.spec) # Fork a child to do the actual installation spack.build_environment.fork(self, build_process, dirty=dirty) # If we installed then we should keep the prefix keep_prefix = True if self.last_phase is None else keep_prefix # note: PARENT of the build process adds the new package to # the database, so that we don't need to re-read from file. - spack.installed_db.add( - self.spec, spack.install_layout, explicit=explicit + spack.install_area.db.add( + self.spec, spack.install_area.layout, explicit=explicit ) except directory_layout.InstallDirectoryAlreadyExistsError: # Abort install if install directory exists. @@ -1306,11 +1307,11 @@ class PackageBase(object): def log(self): # Copy provenance into the install directory on success - log_install_path = spack.install_layout.build_log_path( + log_install_path = spack.install_area.layout.build_log_path( self.spec) - env_install_path = spack.install_layout.build_env_path( + env_install_path = spack.install_area.layout.build_env_path( self.spec) - packages_dir = spack.install_layout.build_packages_path( + packages_dir = spack.install_area.layout.build_packages_path( self.spec) # Remove first if we're overwriting another build @@ -1344,7 +1345,7 @@ class PackageBase(object): check_paths(self.sanity_check_is_dir, 'directory', os.path.isdir) installed = set(os.listdir(self.prefix)) - installed.difference_update(spack.install_layout.hidden_file_paths) + installed.difference_update(spack.install_area.layout.hidden_file_paths) if not installed: raise InstallError( "Install failed for %s. Nothing was installed!" % self.name) @@ -1352,7 +1353,7 @@ class PackageBase(object): @property def build_log_path(self): if self.installed: - return spack.install_layout.build_log_path(self.spec) + return spack.install_area.layout.build_log_path(self.spec) else: return join_path(self.stage.source_path, 'spack-build.out') @@ -1482,9 +1483,9 @@ class PackageBase(object): if not self.installed: # prefix may not exist, but DB may be inconsistent. Try to fix by # removing, but omit hooks. - specs = spack.installed_db.query(self.spec, installed=True) + specs = spack.install_area.db.query(self.spec, installed=True) if specs: - spack.installed_db.remove(specs[0]) + spack.install_area.db.remove(specs[0]) tty.msg("Removed stale DB entry for %s" % self.spec.short_spec) return else: @@ -1501,7 +1502,7 @@ class PackageBase(object): # Uninstalling in Spack only requires removing the prefix. self.remove_prefix() # - spack.installed_db.remove(self.spec) + spack.install_area.db.remove(self.spec) tty.msg("Successfully uninstalled %s" % self.spec.short_spec) # Once everything else is done, run post install hooks @@ -1535,7 +1536,7 @@ class PackageBase(object): """ self._sanity_check_extension() - spack.install_layout.check_extension_conflict(self.extendee_spec, + spack.install_area.layout.check_extension_conflict(self.extendee_spec, self.spec) # Activate any package dependencies that are also extensions. @@ -1547,7 +1548,7 @@ class PackageBase(object): self.extendee_spec.package.activate(self, **self.extendee_args) - spack.install_layout.add_extension(self.extendee_spec, self.spec) + spack.install_area.layout.add_extension(self.extendee_spec, self.spec) tty.msg("Activated extension %s for %s" % (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@"))) @@ -1562,7 +1563,7 @@ class PackageBase(object): """ def ignore(filename): - return (filename in spack.install_layout.hidden_file_paths or + return (filename in spack.install_area.layout.hidden_file_paths or kwargs.get('ignore', lambda f: False)(filename)) tree = LinkTree(extension.prefix) @@ -1580,9 +1581,9 @@ class PackageBase(object): # Allow a force deactivate to happen. This can unlink # spurious files if something was corrupted. if not force: - spack.install_layout.check_activated(self.extendee_spec, self.spec) + spack.install_area.layout.check_activated(self.extendee_spec, self.spec) - activated = spack.install_layout.extension_map(self.extendee_spec) + activated = spack.install_area.layout.extension_map(self.extendee_spec) for name, aspec in activated.items(): if aspec == self.spec: continue @@ -1598,7 +1599,7 @@ class PackageBase(object): # redundant activation check -- makes SURE the spec is not # still activated even if something was wrong above. if self.activated: - spack.install_layout.remove_extension(self.extendee_spec, + spack.install_area.layout.remove_extension(self.extendee_spec, self.spec) tty.msg("Deactivated extension %s for %s" % @@ -1615,7 +1616,7 @@ class PackageBase(object): """ def ignore(filename): - return (filename in spack.install_layout.hidden_file_paths or + return (filename in spack.install_area.layout.hidden_file_paths or kwargs.get('ignore', lambda f: False)(filename)) tree = LinkTree(extension.prefix) @@ -1716,7 +1717,7 @@ def flatten_dependencies(spec, flat_dir): for dep in spec.traverse(root=False): name = dep.name - dep_path = spack.install_layout.path_for_spec(dep) + dep_path = spack.install_area.layout.path_for_spec(dep) dep_files = LinkTree(dep_path) os.mkdir(flat_dir + '/' + name) @@ -1745,7 +1746,7 @@ def dump_packages(spec, path): if node is not spec: # Locate the dependency package in the install tree and find # its provenance information. - source = spack.install_layout.build_packages_path(node) + source = spack.install_area.layout.build_packages_path(node) source_repo_root = join_path(source, node.namespace) # There's no provenance installed for the source package. Skip it. diff --git a/lib/spack/spack/repository.py b/lib/spack/spack/repository.py index 1d4cddaa0f..4696d1d5bc 100644 --- a/lib/spack/spack/repository.py +++ b/lib/spack/spack/repository.py @@ -42,7 +42,6 @@ from llnl.util.filesystem import * import spack import spack.error -import spack.config import spack.spec from spack.provider_index import ProviderIndex from spack.util.naming import * @@ -128,6 +127,7 @@ class RepoPath(object): # If repo_dirs is empty, just use the configuration if not repo_dirs: + import spack.config repo_dirs = spack.config.get_config('repos') if not repo_dirs: raise NoRepoConfiguredError( diff --git a/lib/spack/spack/schema/install.py b/lib/spack/spack/schema/install.py new file mode 100644 index 0000000000..2c43ad1adf --- /dev/null +++ b/lib/spack/spack/schema/install.py @@ -0,0 +1,43 @@ +############################################################################## +# Copyright (c) 2013-2016, 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 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 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 +############################################################################## +"""Schema for packages.yaml configuration files.""" + +schema = { + '$schema': 'http://json-schema.org/schema#', + 'title': 'Spack module file configuration file schema', + 'type': 'object', + 'additionalProperties': False, + 'patternProperties': { + 'install': { + 'type': 'object', + 'default' : {}, + 'additionalProperties': False, + 'properties': { + 'path' : { 'type': 'string' }, + 'layout' : { 'type': 'string' } + } + }, + }, +} diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index b1e3e2ed67..1d9fd8d97a 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -111,6 +111,7 @@ from llnl.util.tty.color import * import spack import spack.architecture +import spack.install_area import spack.compilers as compilers import spack.error import spack.parse @@ -964,7 +965,7 @@ class Spec(object): @property def prefix(self): - return Prefix(spack.install_layout.path_for_spec(self)) + return Prefix(spack.install_area.layout.path_for_spec(self)) def dag_hash(self, length=None): """Return a hash of the entire spec DAG, including connectivity.""" @@ -2328,7 +2329,7 @@ class Spec(object): elif named_str == 'SPACK_ROOT': out.write(fmt % spack.prefix) elif named_str == 'SPACK_INSTALL': - out.write(fmt % spack.install_path) + out.write(fmt % spack.install_area.path) elif named_str == 'PREFIX': out.write(fmt % self.prefix) elif named_str.startswith('HASH'): @@ -2532,7 +2533,7 @@ class SpecParser(spack.parse.Parser): def spec_by_hash(self): self.expect(ID) - specs = spack.installed_db.query() + specs = spack.install_area.db.query() matches = [spec for spec in specs if spec.dag_hash()[:len(self.token.value)] == self.token.value] diff --git a/lib/spack/spack/test/cmd/uninstall.py b/lib/spack/spack/test/cmd/uninstall.py index 4ccb9ddbf4..d839c00b62 100644 --- a/lib/spack/spack/test/cmd/uninstall.py +++ b/lib/spack/spack/test/cmd/uninstall.py @@ -23,7 +23,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## import spack.test.mock_database - +import spack.install_area from spack.cmd.uninstall import uninstall @@ -51,7 +51,7 @@ class TestUninstall(spack.test.mock_database.MockDatabase): args = MockArgs(['callpath'], all=True, dependents=True) uninstall(parser, args) - all_specs = spack.install_layout.all_specs() + all_specs = spack.install_area.layout.all_specs() self.assertEqual(len(all_specs), 7) # query specs with multiple configurations mpileaks_specs = [s for s in all_specs if s.satisfies('mpileaks')] diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py index 4395f17f97..c0bb12ce10 100644 --- a/lib/spack/spack/test/database.py +++ b/lib/spack/spack/test/database.py @@ -30,6 +30,7 @@ import multiprocessing import os.path import spack +import spack.install_area from llnl.util.filesystem import join_path from llnl.util.tty.colify import colify from spack.test.mock_database import MockDatabase @@ -40,16 +41,16 @@ def _print_ref_counts(): recs = [] def add_rec(spec): - cspecs = spack.installed_db.query(spec, installed=any) + cspecs = spack.install_area.db.query(spec, installed=any) if not cspecs: recs.append("[ %-7s ] %-20s-" % ('', spec)) else: key = cspecs[0].dag_hash() - rec = spack.installed_db.get_record(cspecs[0]) + rec = spack.install_area.db.get_record(cspecs[0]) recs.append("[ %-7s ] %-20s%d" % (key[:7], spec, rec.ref_count)) - with spack.installed_db.read_transaction(): + with spack.install_area.db.read_transaction(): add_rec('mpileaks ^mpich') add_rec('callpath ^mpich') add_rec('mpich') @@ -82,7 +83,7 @@ class DatabaseTest(MockDatabase): def test_010_all_install_sanity(self): """Ensure that the install layout reflects what we think it does.""" - all_specs = spack.install_layout.all_specs() + all_specs = spack.install_area.layout.all_specs() self.assertEqual(len(all_specs), 13) # query specs with multiple configurations @@ -113,12 +114,12 @@ class DatabaseTest(MockDatabase): def test_015_write_and_read(self): # write and read DB - with spack.installed_db.write_transaction(): - specs = spack.installed_db.query() - recs = [spack.installed_db.get_record(s) for s in specs] + with spack.install_area.db.write_transaction(): + specs = spack.install_area.db.query() + recs = [spack.install_area.db.get_record(s) for s in specs] for spec, rec in zip(specs, recs): - new_rec = spack.installed_db.get_record(spec) + new_rec = spack.install_area.db.get_record(spec) self.assertEqual(new_rec.ref_count, rec.ref_count) self.assertEqual(new_rec.spec, rec.spec) self.assertEqual(new_rec.path, rec.path) @@ -126,7 +127,7 @@ class DatabaseTest(MockDatabase): def _check_merkleiness(self): """Ensure the spack database is a valid merkle graph.""" - all_specs = spack.installed_db.query(installed=any) + all_specs = spack.install_area.db.query(installed=any) seen = {} for spec in all_specs: @@ -139,8 +140,8 @@ class DatabaseTest(MockDatabase): def _check_db_sanity(self): """Utiilty function to check db against install layout.""" - expected = sorted(spack.install_layout.all_specs()) - actual = sorted(self.installed_db.query()) + expected = sorted(spack.install_area.layout.all_specs()) + actual = sorted(self.install_db.query()) self.assertEqual(len(expected), len(actual)) for e, a in zip(expected, actual): @@ -154,13 +155,13 @@ class DatabaseTest(MockDatabase): def test_025_reindex(self): """Make sure reindex works and ref counts are valid.""" - spack.installed_db.reindex(spack.install_layout) + spack.install_area.db.reindex(spack.install_area.layout) self._check_db_sanity() def test_030_db_sanity_from_another_process(self): def read_and_modify(): self._check_db_sanity() # check that other process can read DB - with self.installed_db.write_transaction(): + with self.install_db.write_transaction(): self._mock_remove('mpileaks ^zmpi') p = multiprocessing.Process(target=read_and_modify, args=()) @@ -168,40 +169,40 @@ class DatabaseTest(MockDatabase): p.join() # ensure child process change is visible in parent process - with self.installed_db.read_transaction(): - self.assertEqual(len(self.installed_db.query('mpileaks ^zmpi')), 0) + with self.install_db.read_transaction(): + self.assertEqual(len(self.install_db.query('mpileaks ^zmpi')), 0) def test_040_ref_counts(self): """Ensure that we got ref counts right when we read the DB.""" - self.installed_db._check_ref_counts() + self.install_db._check_ref_counts() def test_050_basic_query(self): """Ensure querying database is consistent with what is installed.""" # query everything - self.assertEqual(len(spack.installed_db.query()), 13) + self.assertEqual(len(spack.install_area.db.query()), 13) # query specs with multiple configurations - mpileaks_specs = self.installed_db.query('mpileaks') - callpath_specs = self.installed_db.query('callpath') - mpi_specs = self.installed_db.query('mpi') + mpileaks_specs = self.install_db.query('mpileaks') + callpath_specs = self.install_db.query('callpath') + mpi_specs = self.install_db.query('mpi') self.assertEqual(len(mpileaks_specs), 3) self.assertEqual(len(callpath_specs), 3) self.assertEqual(len(mpi_specs), 3) # query specs with single configurations - dyninst_specs = self.installed_db.query('dyninst') - libdwarf_specs = self.installed_db.query('libdwarf') - libelf_specs = self.installed_db.query('libelf') + dyninst_specs = self.install_db.query('dyninst') + libdwarf_specs = self.install_db.query('libdwarf') + libelf_specs = self.install_db.query('libelf') self.assertEqual(len(dyninst_specs), 1) self.assertEqual(len(libdwarf_specs), 1) self.assertEqual(len(libelf_specs), 1) # Query by dependency - self.assertEqual(len(self.installed_db.query('mpileaks ^mpich')), 1) - self.assertEqual(len(self.installed_db.query('mpileaks ^mpich2')), 1) - self.assertEqual(len(self.installed_db.query('mpileaks ^zmpi')), 1) + self.assertEqual(len(self.install_db.query('mpileaks ^mpich')), 1) + self.assertEqual(len(self.install_db.query('mpileaks ^mpich2')), 1) + self.assertEqual(len(self.install_db.query('mpileaks ^zmpi')), 1) def _check_remove_and_add_package(self, spec): """Remove a spec from the DB, then add it and make sure everything's @@ -209,13 +210,13 @@ class DatabaseTest(MockDatabase): removed, that it's back when added again, and that ref counts are consistent. """ - original = self.installed_db.query() - self.installed_db._check_ref_counts() + original = self.install_db.query() + self.install_db._check_ref_counts() # Remove spec - concrete_spec = self.installed_db.remove(spec) - self.installed_db._check_ref_counts() - remaining = self.installed_db.query() + concrete_spec = self.install_db.remove(spec) + self.install_db._check_ref_counts() + remaining = self.install_db.query() # ensure spec we removed is gone self.assertEqual(len(original) - 1, len(remaining)) @@ -223,14 +224,14 @@ class DatabaseTest(MockDatabase): self.assertTrue(concrete_spec not in remaining) # add it back and make sure everything is ok. - self.installed_db.add(concrete_spec, spack.install_layout) - installed = self.installed_db.query() + self.install_db.add(concrete_spec, spack.install_area.layout) + installed = self.install_db.query() self.assertTrue(concrete_spec in installed) self.assertEqual(installed, original) # sanity check against direcory layout and check ref counts. self._check_db_sanity() - self.installed_db._check_ref_counts() + self.install_db._check_ref_counts() def test_060_remove_and_add_root_package(self): self._check_remove_and_add_package('mpileaks ^mpich') @@ -239,95 +240,95 @@ class DatabaseTest(MockDatabase): self._check_remove_and_add_package('dyninst') def test_080_root_ref_counts(self): - rec = self.installed_db.get_record('mpileaks ^mpich') + rec = self.install_db.get_record('mpileaks ^mpich') # Remove a top-level spec from the DB - self.installed_db.remove('mpileaks ^mpich') + self.install_db.remove('mpileaks ^mpich') # record no longer in DB self.assertEqual( - self.installed_db.query('mpileaks ^mpich', installed=any), []) + self.install_db.query('mpileaks ^mpich', installed=any), []) # record's deps have updated ref_counts self.assertEqual( - self.installed_db.get_record('callpath ^mpich').ref_count, 0) - self.assertEqual(self.installed_db.get_record('mpich').ref_count, 1) + self.install_db.get_record('callpath ^mpich').ref_count, 0) + self.assertEqual(self.install_db.get_record('mpich').ref_count, 1) # Put the spec back - self.installed_db.add(rec.spec, spack.install_layout) + self.install_db.add(rec.spec, spack.install_area.layout) # record is present again self.assertEqual( - len(self.installed_db.query('mpileaks ^mpich', installed=any)), 1) + len(self.install_db.query('mpileaks ^mpich', installed=any)), 1) # dependencies have ref counts updated self.assertEqual( - self.installed_db.get_record('callpath ^mpich').ref_count, 1) - self.assertEqual(self.installed_db.get_record('mpich').ref_count, 2) + self.install_db.get_record('callpath ^mpich').ref_count, 1) + self.assertEqual(self.install_db.get_record('mpich').ref_count, 2) def test_090_non_root_ref_counts(self): - self.installed_db.get_record('mpileaks ^mpich') - self.installed_db.get_record('callpath ^mpich') + self.install_db.get_record('mpileaks ^mpich') + self.install_db.get_record('callpath ^mpich') # "force remove" a non-root spec from the DB - self.installed_db.remove('callpath ^mpich') + self.install_db.remove('callpath ^mpich') # record still in DB but marked uninstalled self.assertEqual( - self.installed_db.query('callpath ^mpich', installed=True), []) + self.install_db.query('callpath ^mpich', installed=True), []) self.assertEqual( - len(self.installed_db.query('callpath ^mpich', installed=any)), 1) + len(self.install_db.query('callpath ^mpich', installed=any)), 1) # record and its deps have same ref_counts - self.assertEqual(self.installed_db.get_record( + self.assertEqual(self.install_db.get_record( 'callpath ^mpich', installed=any).ref_count, 1) - self.assertEqual(self.installed_db.get_record('mpich').ref_count, 2) + self.assertEqual(self.install_db.get_record('mpich').ref_count, 2) # remove only dependent of uninstalled callpath record - self.installed_db.remove('mpileaks ^mpich') + self.install_db.remove('mpileaks ^mpich') # record and parent are completely gone. self.assertEqual( - self.installed_db.query('mpileaks ^mpich', installed=any), []) + self.install_db.query('mpileaks ^mpich', installed=any), []) self.assertEqual( - self.installed_db.query('callpath ^mpich', installed=any), []) + self.install_db.query('callpath ^mpich', installed=any), []) # mpich ref count updated properly. - mpich_rec = self.installed_db.get_record('mpich') + mpich_rec = self.install_db.get_record('mpich') self.assertEqual(mpich_rec.ref_count, 0) def test_100_no_write_with_exception_on_remove(self): def fail_while_writing(): - with self.installed_db.write_transaction(): + with self.install_db.write_transaction(): self._mock_remove('mpileaks ^zmpi') raise Exception() - with self.installed_db.read_transaction(): + with self.install_db.read_transaction(): self.assertEqual( - len(self.installed_db.query('mpileaks ^zmpi', installed=any)), + len(self.install_db.query('mpileaks ^zmpi', installed=any)), 1) self.assertRaises(Exception, fail_while_writing) # reload DB and make sure zmpi is still there. - with self.installed_db.read_transaction(): + with self.install_db.read_transaction(): self.assertEqual( - len(self.installed_db.query('mpileaks ^zmpi', installed=any)), + len(self.install_db.query('mpileaks ^zmpi', installed=any)), 1) def test_110_no_write_with_exception_on_install(self): def fail_while_writing(): - with self.installed_db.write_transaction(): + with self.install_db.write_transaction(): self._mock_install('cmake') raise Exception() - with self.installed_db.read_transaction(): + with self.install_db.read_transaction(): self.assertEqual( - self.installed_db.query('cmake', installed=any), []) + self.install_db.query('cmake', installed=any), []) self.assertRaises(Exception, fail_while_writing) # reload DB and make sure cmake was not written. - with self.installed_db.read_transaction(): + with self.install_db.read_transaction(): self.assertEqual( - self.installed_db.query('cmake', installed=any), []) + self.install_db.query('cmake', installed=any), []) diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py index 232d5aeeaf..eb051e9301 100644 --- a/lib/spack/spack/test/install.py +++ b/lib/spack/spack/test/install.py @@ -26,6 +26,7 @@ import shutil import tempfile import spack +import spack.install_area from llnl.util.filesystem import * from spack.directory_layout import YamlDirectoryLayout from spack.database import Database @@ -49,11 +50,11 @@ class InstallTest(MockPackagesTest): # Use a fake install directory to avoid conflicts bt/w # installed pkgs and mock packages. self.tmpdir = tempfile.mkdtemp() - self.orig_layout = spack.install_layout - self.orig_db = spack.installed_db + self.orig_layout = spack.install_area.layout + self.orig_db = spack.install_area.db - spack.install_layout = YamlDirectoryLayout(self.tmpdir) - spack.installed_db = Database(self.tmpdir) + spack.install_area.layout = YamlDirectoryLayout(self.tmpdir) + spack.install_area.db = Database(self.tmpdir) def tearDown(self): super(InstallTest, self).tearDown() @@ -63,8 +64,8 @@ class InstallTest(MockPackagesTest): spack.do_checksum = True # restore spack's layout. - spack.install_layout = self.orig_layout - spack.installed_db = self.orig_db + spack.install_area.layout = self.orig_layout + spack.install_area.db = self.orig_db shutil.rmtree(self.tmpdir, ignore_errors=True) def fake_fetchify(self, pkg): @@ -91,7 +92,7 @@ class InstallTest(MockPackagesTest): pkg.remove_prefix() raise - def test_install_environment(self): + def test_install_area(self): spec = Spec('cmake-client').concretized() for s in spec.traverse(): diff --git a/lib/spack/spack/test/mock_database.py b/lib/spack/spack/test/mock_database.py index d5867f06ec..d1f9fb000b 100644 --- a/lib/spack/spack/test/mock_database.py +++ b/lib/spack/spack/test/mock_database.py @@ -26,6 +26,7 @@ import shutil import tempfile import spack +import spack.install_area from spack.spec import Spec from spack.database import Database from spack.directory_layout import YamlDirectoryLayout @@ -41,7 +42,7 @@ class MockDatabase(MockPackagesTest): pkg.do_install(fake=True) def _mock_remove(self, spec): - specs = spack.installed_db.query(spec) + specs = spack.install_area.db.query(spec) assert len(specs) == 1 spec = specs[0] spec.package.do_uninstall(spec) @@ -54,17 +55,17 @@ class MockDatabase(MockPackagesTest): # Make a fake install directory self.install_path = tempfile.mkdtemp() - self.spack_install_path = spack.install_path - spack.install_path = self.install_path + self.spack_install_path = spack.install_area.path + spack.install_area.path = self.install_path self.install_layout = YamlDirectoryLayout(self.install_path) - self.spack_install_layout = spack.install_layout - spack.install_layout = self.install_layout + self.spack_install_layout = spack.install_area.layout + spack.install_area.layout = self.install_layout # Make fake database and fake install directory. - self.installed_db = Database(self.install_path) - self.spack_installed_db = spack.installed_db - spack.installed_db = self.installed_db + self.install_db = Database(self.install_path) + self.spack_install_db = spack.install_area.db + spack.install_area.db = self.install_db # make a mock database with some packages installed note that # the ref count for dyninst here will be 3, as it's recycled @@ -90,18 +91,18 @@ class MockDatabase(MockPackagesTest): # # Transaction used to avoid repeated writes. - with spack.installed_db.write_transaction(): + with spack.install_area.db.write_transaction(): self._mock_install('mpileaks ^mpich') self._mock_install('mpileaks ^mpich2') self._mock_install('mpileaks ^zmpi') def tearDown(self): - with spack.installed_db.write_transaction(): - for spec in spack.installed_db.query(): + with spack.install_area.db.write_transaction(): + for spec in spack.install_area.db.query(): spec.package.do_uninstall(spec) super(MockDatabase, self).tearDown() shutil.rmtree(self.install_path) - spack.install_path = self.spack_install_path - spack.install_layout = self.spack_install_layout - spack.installed_db = self.spack_installed_db + spack.install_area.path = self.spack_install_path + spack.install_area.layout = self.spack_install_layout + spack.install_area.db = self.spack_install_db |