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
@ -30,6 +30,9 @@
|
|||||||
description = "Activate a package extension."
|
description = "Activate a package extension."
|
||||||
|
|
||||||
def setup_parser(subparser):
|
def setup_parser(subparser):
|
||||||
|
subparser.add_argument(
|
||||||
|
'-f', '--force', action='store_true',
|
||||||
|
help="Activate without first activating dependencies.")
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'spec', nargs=argparse.REMAINDER, help="spec of package extension to activate.")
|
'spec', nargs=argparse.REMAINDER, help="spec of package extension to activate.")
|
||||||
|
|
||||||
@ -44,6 +47,9 @@ def activate(parser, args):
|
|||||||
spack.db.get(specs[0])
|
spack.db.get(specs[0])
|
||||||
|
|
||||||
spec = spack.cmd.disambiguate_spec(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:
|
if spec.package.activated:
|
||||||
tty.die("Package %s is already activated." % specs[0].short_spec)
|
tty.die("Package %s is already activated." % specs[0].short_spec)
|
||||||
|
|
||||||
|
@ -24,8 +24,10 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
from external import argparse
|
from external import argparse
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
|
from spack.graph import topological_sort
|
||||||
|
|
||||||
description = "Deactivate a package extension."
|
description = "Deactivate a package extension."
|
||||||
|
|
||||||
@ -33,6 +35,10 @@ def setup_parser(subparser):
|
|||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-f', '--force', action='store_true',
|
'-f', '--force', action='store_true',
|
||||||
help="Run deactivation even if spec is NOT currently activated.")
|
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(
|
subparser.add_argument(
|
||||||
'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.")
|
'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.")
|
||||||
|
|
||||||
@ -42,12 +48,52 @@ def deactivate(parser, args):
|
|||||||
if len(specs) != 1:
|
if len(specs) != 1:
|
||||||
tty.die("deactivate requires one spec. %d given." % len(specs))
|
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.
|
# This ensures the ext spec is always normalized properly.
|
||||||
spack.db.get(specs[0])
|
spack.db.get(specs[0])
|
||||||
|
|
||||||
spec = spack.cmd.disambiguate_spec(specs[0])
|
spec = spack.cmd.disambiguate_spec(specs[0])
|
||||||
if not args.force and not spec.package.activated:
|
pkg = spec.package
|
||||||
tty.die("Package %s is not activated." % specs[0].short_spec)
|
|
||||||
|
|
||||||
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':
|
elif mode == 'deps':
|
||||||
for spec in specs:
|
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'):
|
elif mode in ('short', 'long'):
|
||||||
fmt = '$-_$@$+'
|
fmt = '$-_$@$+'
|
||||||
|
@ -371,7 +371,7 @@ def add_extension(self, spec, ext_spec):
|
|||||||
_check_concrete(ext_spec)
|
_check_concrete(ext_spec)
|
||||||
|
|
||||||
# Check whether it's already installed or if it's a conflict.
|
# 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)
|
self.check_extension_conflict(spec, ext_spec)
|
||||||
|
|
||||||
# do the actual adding.
|
# do the actual adding.
|
||||||
@ -384,7 +384,7 @@ def remove_extension(self, spec, ext_spec):
|
|||||||
_check_concrete(ext_spec)
|
_check_concrete(ext_spec)
|
||||||
|
|
||||||
# Make sure it's installed before removing.
|
# Make sure it's installed before removing.
|
||||||
exts = self.extension_map(spec)
|
exts = self._extension_map(spec)
|
||||||
self.check_activated(spec, ext_spec)
|
self.check_activated(spec, ext_spec)
|
||||||
|
|
||||||
# do the actual removing.
|
# do the actual removing.
|
||||||
@ -450,10 +450,10 @@ def __init__(self, spec, ext_spec, conflict):
|
|||||||
|
|
||||||
|
|
||||||
class NoSuchExtensionError(DirectoryLayoutError):
|
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):
|
def __init__(self, spec, ext_spec):
|
||||||
super(NoSuchExtensionError, self).__init__(
|
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))
|
ext_spec.short_spec, spec.short_spec))
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,4 +33,4 @@ def pre_uninstall(pkg):
|
|||||||
|
|
||||||
if pkg.is_extension:
|
if pkg.is_extension:
|
||||||
if pkg.activated:
|
if pkg.activated:
|
||||||
pkg.do_deactivate()
|
pkg.do_deactivate(force=True)
|
||||||
|
@ -529,11 +529,8 @@ def extends(self, spec):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def activated(self):
|
def activated(self):
|
||||||
if not self.spec.concrete:
|
|
||||||
raise ValueError("Only concrete package extensions can be activated.")
|
|
||||||
if not self.is_extension:
|
if not self.is_extension:
|
||||||
raise ValueError("is_extension called on package that is not an 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_layout.extension_map(self.extendee_spec)
|
||||||
return (self.name in exts) and (exts[self.name] == self.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))
|
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.
|
"""Called on an etension to invoke the extendee's activate method.
|
||||||
|
|
||||||
Commands should call this routine, and should not call
|
Commands should call this routine, and should not call
|
||||||
activate() directly.
|
activate() directly.
|
||||||
"""
|
"""
|
||||||
self._sanity_check_extension()
|
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)
|
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)
|
self.extendee_spec.package.activate(self, **self.extendee_args)
|
||||||
|
|
||||||
spack.install_layout.add_extension(self.extendee_spec, self.spec)
|
spack.install_layout.add_extension(self.extendee_spec, self.spec)
|
||||||
tty.msg("Activated extension %s for %s."
|
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):
|
def activate(self, extension, **kwargs):
|
||||||
@ -994,15 +1004,21 @@ def ignore(filename):
|
|||||||
|
|
||||||
def do_deactivate(self, **kwargs):
|
def do_deactivate(self, **kwargs):
|
||||||
"""Called on the extension to invoke extendee's deactivate() method."""
|
"""Called on the extension to invoke extendee's deactivate() method."""
|
||||||
force = kwargs.get('force', False)
|
|
||||||
|
|
||||||
self._sanity_check_extension()
|
self._sanity_check_extension()
|
||||||
|
force = kwargs.get('force', False)
|
||||||
|
|
||||||
# Allow a force deactivate to happen. This can unlink
|
# Allow a force deactivate to happen. This can unlink
|
||||||
# spurious files if something was corrupted.
|
# spurious files if something was corrupted.
|
||||||
if not force:
|
if not force:
|
||||||
spack.install_layout.check_activated(self.extendee_spec, self.spec)
|
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)
|
self.extendee_spec.package.deactivate(self, **self.extendee_args)
|
||||||
|
|
||||||
# redundant activation check -- makes SURE the spec is not
|
# 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)
|
spack.install_layout.remove_extension(self.extendee_spec, self.spec)
|
||||||
|
|
||||||
tty.msg("Deactivated extension %s for %s."
|
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):
|
def deactivate(self, extension, **kwargs):
|
||||||
@ -1236,7 +1252,15 @@ def __init__(self, cls):
|
|||||||
"Package %s has no version with a URL." % cls.__name__)
|
"Package %s has no version with a URL." % cls.__name__)
|
||||||
|
|
||||||
|
|
||||||
class ExtensionConflictError(PackageError):
|
class ExtensionError(PackageError): pass
|
||||||
|
|
||||||
|
|
||||||
|
class ExtensionConflictError(ExtensionError):
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
super(ExtensionConflictError, self).__init__(
|
super(ExtensionConflictError, self).__init__(
|
||||||
"Extension blocked by file: %s" % path)
|
"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 New Issue
Block a user