Better activate/deactivate logic.
spack activate - now activates dependency extensions - ensures dependencies are activated in the python installation. - -f/--force option still allows the old activate behavior. spack deactivate - checks for dependents before deactivating (like uninstall) - deactivate -a/--all <extension> will deactviate a package and ALL of its dependency extensions. - deactivate -a/--all <extendee> activates all extensions of <extendee> e.g.: spack deactivate -a python - deactivate -f/--force option allows removing regardless of dependents. - deactivate -f can be run EVEN if a package is not activated. - allows for clenup of activations gone wrong.
This commit is contained in:
parent
57f331e2ac
commit
d800c23cec
6 changed files with 95 additions and 19 deletions
|
@ -30,6 +30,9 @@
|
|||
description = "Activate a package extension."
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
'-f', '--force', action='store_true',
|
||||
help="Activate without first activating dependencies.")
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help="spec of package extension to activate.")
|
||||
|
||||
|
@ -44,6 +47,9 @@ def activate(parser, args):
|
|||
spack.db.get(specs[0])
|
||||
|
||||
spec = spack.cmd.disambiguate_spec(specs[0])
|
||||
if not spec.package.is_extension:
|
||||
tty.die("%s is not an extension." % spec.name)
|
||||
|
||||
if spec.package.activated:
|
||||
tty.die("Package %s is already activated." % specs[0].short_spec)
|
||||
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
##############################################################################
|
||||
from external import argparse
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
from spack.graph import topological_sort
|
||||
|
||||
description = "Deactivate a package extension."
|
||||
|
||||
|
@ -33,6 +35,10 @@ def setup_parser(subparser):
|
|||
subparser.add_argument(
|
||||
'-f', '--force', action='store_true',
|
||||
help="Run deactivation even if spec is NOT currently activated.")
|
||||
subparser.add_argument(
|
||||
'-a', '--all', action='store_true',
|
||||
help="Deactivate all extensions of an extendable pacakge, or "
|
||||
"deactivate an extension AND its dependencies.")
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.")
|
||||
|
||||
|
@ -42,12 +48,52 @@ def deactivate(parser, args):
|
|||
if len(specs) != 1:
|
||||
tty.die("deactivate requires one spec. %d given." % len(specs))
|
||||
|
||||
# TODO: remove this hack when DAG info is stored in dir layout.
|
||||
# TODO: remove this hack when DAG info is stored properly.
|
||||
# This ensures the ext spec is always normalized properly.
|
||||
spack.db.get(specs[0])
|
||||
|
||||
spec = spack.cmd.disambiguate_spec(specs[0])
|
||||
if not args.force and not spec.package.activated:
|
||||
tty.die("Package %s is not activated." % specs[0].short_spec)
|
||||
pkg = spec.package
|
||||
|
||||
spec.package.do_deactivate(force=args.force)
|
||||
if args.all:
|
||||
if pkg.extendable:
|
||||
tty.msg("Deactivating all extensions of %s" % pkg.spec.short_spec)
|
||||
ext_pkgs = spack.db.installed_extensions_for(spec)
|
||||
for ext_pkg in ext_pkgs:
|
||||
ext_pkg.spec.normalize()
|
||||
if ext_pkg.activated:
|
||||
ext_pkg.do_deactivate(force=True)
|
||||
|
||||
elif pkg.is_extension:
|
||||
# TODO: store DAG info properly (see above)
|
||||
spec.normalize()
|
||||
|
||||
tty.msg("Deactivating %s and all dependencies." % pkg.spec.short_spec)
|
||||
|
||||
topo_order = topological_sort(spec)
|
||||
index = spec.index()
|
||||
|
||||
for name in topo_order:
|
||||
espec = index[name]
|
||||
epkg = espec.package
|
||||
|
||||
# TODO: store DAG info properly (see above)
|
||||
epkg.spec.normalize()
|
||||
|
||||
if epkg.extends(pkg.extendee_spec):
|
||||
if epkg.activated or args.force:
|
||||
|
||||
epkg.do_deactivate(force=args.force)
|
||||
|
||||
else:
|
||||
tty.die("spack deactivate --all requires an extendable package or an extension.")
|
||||
|
||||
else:
|
||||
if not pkg.is_extension:
|
||||
tty.die("spack deactivate requires an extension.",
|
||||
"Did you mean 'spack deactivate --all'?")
|
||||
|
||||
if not args.force and not spec.package.activated:
|
||||
tty.die("Package %s is not activated." % specs[0].short_spec)
|
||||
|
||||
spec.package.do_deactivate(force=args.force)
|
||||
|
|
|
@ -85,7 +85,7 @@ def display_specs(specs, **kwargs):
|
|||
|
||||
elif mode == 'deps':
|
||||
for spec in specs:
|
||||
print spec.tree(indent=4, format='$_$@$+', color=True),
|
||||
print spec.tree(indent=4, format='$_$@$+$#', color=True),
|
||||
|
||||
elif mode in ('short', 'long'):
|
||||
fmt = '$-_$@$+'
|
||||
|
|
|
@ -371,7 +371,7 @@ def add_extension(self, spec, ext_spec):
|
|||
_check_concrete(ext_spec)
|
||||
|
||||
# Check whether it's already installed or if it's a conflict.
|
||||
exts = self.extension_map(spec)
|
||||
exts = self._extension_map(spec)
|
||||
self.check_extension_conflict(spec, ext_spec)
|
||||
|
||||
# do the actual adding.
|
||||
|
@ -384,7 +384,7 @@ def remove_extension(self, spec, ext_spec):
|
|||
_check_concrete(ext_spec)
|
||||
|
||||
# Make sure it's installed before removing.
|
||||
exts = self.extension_map(spec)
|
||||
exts = self._extension_map(spec)
|
||||
self.check_activated(spec, ext_spec)
|
||||
|
||||
# do the actual removing.
|
||||
|
@ -450,10 +450,10 @@ def __init__(self, spec, ext_spec, conflict):
|
|||
|
||||
|
||||
class NoSuchExtensionError(DirectoryLayoutError):
|
||||
"""Raised when an extension isn't there on remove."""
|
||||
"""Raised when an extension isn't there on deactivate."""
|
||||
def __init__(self, spec, ext_spec):
|
||||
super(NoSuchExtensionError, self).__init__(
|
||||
"%s cannot be removed from %s because it's not installed."% (
|
||||
"%s cannot be removed from %s because it's not activated."% (
|
||||
ext_spec.short_spec, spec.short_spec))
|
||||
|
||||
|
||||
|
|
|
@ -33,4 +33,4 @@ def pre_uninstall(pkg):
|
|||
|
||||
if pkg.is_extension:
|
||||
if pkg.activated:
|
||||
pkg.do_deactivate()
|
||||
pkg.do_deactivate(force=True)
|
||||
|
|
|
@ -529,11 +529,8 @@ def extends(self, spec):
|
|||
|
||||
@property
|
||||
def activated(self):
|
||||
if not self.spec.concrete:
|
||||
raise ValueError("Only concrete package extensions can be activated.")
|
||||
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)
|
||||
return (self.name in exts) and (exts[self.name] == self.spec)
|
||||
|
||||
|
@ -956,20 +953,33 @@ def _sanity_check_extension(self):
|
|||
raise ValueError("%s does not extend %s!" % (self.name, self.extendee.name))
|
||||
|
||||
|
||||
def do_activate(self):
|
||||
def do_activate(self, **kwargs):
|
||||
"""Called on an etension to invoke the extendee's activate method.
|
||||
|
||||
Commands should call this routine, and should not call
|
||||
activate() directly.
|
||||
"""
|
||||
self._sanity_check_extension()
|
||||
force = kwargs.get('force', False)
|
||||
|
||||
# TODO: get rid of this normalize - DAG handling.
|
||||
self.spec.normalize()
|
||||
|
||||
spack.install_layout.check_extension_conflict(self.extendee_spec, self.spec)
|
||||
|
||||
if not force:
|
||||
for spec in self.spec.traverse(root=False):
|
||||
if spec.package.extends(self.extendee_spec):
|
||||
# TODO: fix this normalize() requirement -- revisit DAG handling.
|
||||
spec.package.spec.normalize()
|
||||
if not spec.package.activated:
|
||||
spec.package.do_activate(**kwargs)
|
||||
|
||||
self.extendee_spec.package.activate(self, **self.extendee_args)
|
||||
|
||||
spack.install_layout.add_extension(self.extendee_spec, self.spec)
|
||||
tty.msg("Activated extension %s for %s."
|
||||
% (self.spec.short_spec, self.extendee_spec.short_spec))
|
||||
% (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@")))
|
||||
|
||||
|
||||
def activate(self, extension, **kwargs):
|
||||
|
@ -994,15 +1004,21 @@ def ignore(filename):
|
|||
|
||||
def do_deactivate(self, **kwargs):
|
||||
"""Called on the extension to invoke extendee's deactivate() method."""
|
||||
force = kwargs.get('force', False)
|
||||
|
||||
self._sanity_check_extension()
|
||||
force = kwargs.get('force', False)
|
||||
|
||||
# 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)
|
||||
|
||||
activated = spack.install_layout.extension_map(self.extendee_spec)
|
||||
for name, aspec in activated.items():
|
||||
if aspec != self.spec and self.spec in aspec:
|
||||
raise ActivationError(
|
||||
"Cannot deactivate %s beacuse %s is activated and depends on it."
|
||||
% (self.spec.short_spec, aspec.short_spec))
|
||||
|
||||
self.extendee_spec.package.deactivate(self, **self.extendee_args)
|
||||
|
||||
# redundant activation check -- makes SURE the spec is not
|
||||
|
@ -1011,7 +1027,7 @@ def do_deactivate(self, **kwargs):
|
|||
spack.install_layout.remove_extension(self.extendee_spec, self.spec)
|
||||
|
||||
tty.msg("Deactivated extension %s for %s."
|
||||
% (self.spec.short_spec, self.extendee_spec.short_spec))
|
||||
% (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@")))
|
||||
|
||||
|
||||
def deactivate(self, extension, **kwargs):
|
||||
|
@ -1236,7 +1252,15 @@ def __init__(self, cls):
|
|||
"Package %s has no version with a URL." % cls.__name__)
|
||||
|
||||
|
||||
class ExtensionConflictError(PackageError):
|
||||
class ExtensionError(PackageError): pass
|
||||
|
||||
|
||||
class ExtensionConflictError(ExtensionError):
|
||||
def __init__(self, path):
|
||||
super(ExtensionConflictError, self).__init__(
|
||||
"Extension blocked by file: %s" % path)
|
||||
|
||||
|
||||
class ActivationError(ExtensionError):
|
||||
def __init__(self, msg, long_msg=None):
|
||||
super(ActivationError, self).__init__(msg, long_msg)
|
||||
|
|
Loading…
Reference in a new issue