views: support querying view layouts as well

This abstracts out the layout in use between the global installations
and a specific view.
This commit is contained in:
Oliver Breitwieser 2017-09-18 09:04:32 -04:00 committed by scheibelp
parent 00a893aa79
commit 078f85a125
5 changed files with 56 additions and 26 deletions

View File

@ -100,9 +100,9 @@ def extensions(parser, args):
spack.cmd.find.display_specs(installed, mode=args.mode)
#
# List specs of activated extensions.
# List specs of globally activated extensions.
#
activated = spack.store.layout.extension_map(spec)
activated = spack.store.extensions.extension_map(spec)
print
if not activated:
tty.msg("None activated.")

View File

@ -751,14 +751,16 @@ def installed_extensions_for(self, extendee_spec):
yield spec.package
@_autospec
def activated_extensions_for(self, extendee_spec):
def activated_extensions_for(self, extendee_spec, extensions_layout=None):
"""
Return the specs of all packages that extend
the given spec
"""
if extensions_layout is None:
extensions_layout = spack.store.extensions
for spec in self.query():
try:
spack.store.layout.check_activated(extendee_spec, spec)
extensions_layout.check_activated(extendee_spec, spec)
yield spec.package
except spack.directory_layout.NoSuchExtensionError:
continue

View File

@ -30,4 +30,5 @@ def pre_uninstall(spec):
if pkg.is_extension:
if pkg.is_activated():
# deactivate globally
pkg.do_deactivate(force=True)

View File

@ -903,12 +903,14 @@ def extends(self, spec):
s = self.extendee_spec
return s and spec.satisfies(s)
def is_activated(self):
def is_activated(self, extensions_layout=None):
"""Return True if package is activated."""
if not self.is_extension:
raise ValueError(
"is_extension called on package that is not an extension.")
exts = spack.store.layout.extension_map(self.extendee_spec)
if extensions_layout is None:
extensions_layout = spack.store.extensions
exts = extensions_layout.extension_map(self.extendee_spec)
return (self.name in exts) and (exts[self.name] == self.spec)
def provides(self, vpkg_name):
@ -1773,7 +1775,7 @@ def _sanity_check_extension(self):
raise ActivationError("%s does not extend %s!" %
(self.name, self.extendee.name))
def do_activate(self, force=False, verbose=True):
def do_activate(self, force=False, verbose=True, extensions_layout=None):
"""Called on an extension to invoke the extendee's activate method.
Commands should call this routine, and should not call
@ -1781,18 +1783,25 @@ def do_activate(self, force=False, verbose=True):
"""
self._sanity_check_extension()
spack.store.layout.check_extension_conflict(
if extensions_layout is None:
extensions_layout = spack.store.extensions
extensions_layout.check_extension_conflict(
self.extendee_spec, self.spec)
# Activate any package dependencies that are also extensions.
if not force:
for spec in self.dependency_activations():
if not spec.package.is_activated():
spec.package.do_activate(force=force, verbose=verbose)
if not spec.package.is_activated(
extensions_layout=extensions_layout):
spec.package.do_activate(
force=force, verbose=verbose,
extensions_layout=extensions_layout)
self.extendee_spec.package.activate(self, **self.extendee_args)
self.extendee_spec.package.activate(
self, extensions_layout=extensions_layout, **self.extendee_args)
spack.store.layout.add_extension(self.extendee_spec, self.spec)
extensions_layout.add_extension(self.extendee_spec, self.spec)
if verbose:
tty.msg(
@ -1805,7 +1814,9 @@ def dependency_activations(self):
if spec.package.extends(self.extendee_spec))
def activate(self, extension, **kwargs):
"""Symlinks all files from the extension into extendee's install dir.
"""Make extension package usable by linking all its files to a target
provided by the directory layout (depending if the user wants to
activate globally or in a specified file system view).
Package authors can override this method to support other
extension mechanisms. Spack internals (commands, hooks, etc.)
@ -1813,48 +1824,57 @@ def activate(self, extension, **kwargs):
always executed.
"""
extensions_layout = kwargs.get("extensions_layout",
spack.store.extensions)
target = extensions_layout.extendee_target_directory(self)
def ignore(filename):
return (filename in spack.store.layout.hidden_file_paths or
kwargs.get('ignore', lambda f: False)(filename))
tree = LinkTree(extension.prefix)
conflict = tree.find_conflict(self.prefix, ignore=ignore)
conflict = tree.find_conflict(target, ignore=ignore)
if conflict:
raise ExtensionConflictError(conflict)
tree.merge(self.prefix, ignore=ignore)
tree.merge(target, ignore=ignore, link=extensions_layout.link)
def do_deactivate(self, **kwargs):
"""Called on the extension to invoke extendee's deactivate() method."""
self._sanity_check_extension()
force = kwargs.get('force', False)
verbose = kwargs.get("verbose", True)
extensions_layout = kwargs.get("extensions_layout",
spack.store.extensions)
# Allow a force deactivate to happen. This can unlink
# spurious files if something was corrupted.
if not force:
spack.store.layout.check_activated(
extensions_layout.check_activated(
self.extendee_spec, self.spec)
activated = spack.store.layout.extension_map(
activated = extensions_layout.extension_map(
self.extendee_spec)
for name, aspec in activated.items():
if aspec == self.spec:
continue
for dep in aspec.traverse(deptype='run'):
if self.spec == dep:
msg = ("Cannot deactivate %s because %s is activated "
"and depends on it.")
msg = ("Cannot deactivate %s because %s is "
"activated and depends on it.")
raise ActivationError(
msg % (self.spec.short_spec, aspec.short_spec))
msg % (self.spec.cshort_spec,
aspec.cshort_spec))
self.extendee_spec.package.deactivate(self, **self.extendee_args)
self.extendee_spec.package.deactivate(
self,
extensions_layout=extensions_layout,
**self.extendee_args)
# redundant activation check -- makes SURE the spec is not
# still activated even if something was wrong above.
if self.is_activated():
spack.store.layout.remove_extension(
if self.is_activated(extensions_layout):
extensions_layout.remove_extension(
self.extendee_spec, self.spec)
if verbose:
@ -1864,7 +1884,8 @@ def do_deactivate(self, **kwargs):
self.extendee_spec.cformat("$_$@$+$%@")))
def deactivate(self, extension, **kwargs):
"""Unlinks all files from extension out of this package's install dir.
"""Unlinks all files from extension out of this package's install dir
or the corresponding filesystem view.
Package authors can override this method to support other
extension mechanisms. Spack internals (commands, hooks, etc.)
@ -1872,13 +1893,16 @@ def deactivate(self, extension, **kwargs):
always executed.
"""
extensions_layout = kwargs.get("extensions_layout",
spack.store.extensions)
target = extensions_layout.extendee_target_directory(self)
def ignore(filename):
return (filename in spack.store.layout.hidden_file_paths or
kwargs.get('ignore', lambda f: False)(filename))
tree = LinkTree(extension.prefix)
tree.unmerge(self.prefix, ignore=ignore)
tree.unmerge(target, ignore=ignore)
def do_restage(self):
"""Reverts expanded/checked out source to a pristine state."""

View File

@ -48,9 +48,10 @@
from spack.util.path import canonicalize_path
from spack.database import Database
from spack.directory_layout import YamlDirectoryLayout
from spack.directory_layout import YamlExtensionsLayout
__author__ = "Benedikt Hegner (CERN)"
__all__ = ['db', 'layout', 'root']
__all__ = ['db', 'extensions', 'layout', 'root']
#
# Read in the config
@ -75,3 +76,5 @@
layout = YamlDirectoryLayout(root,
hash_len=config.get('install_hash_length'),
path_scheme=config.get('install_path_scheme'))
extensions = YamlExtensionsLayout(root, layout)