Rework do_activate/activate and do_deactivate/deactivate semantics.
- packages can now extend only one other package. - do_activate() and do_deactivate() are now called on the extension, and they automatically find the extendee - activate() and deactivate() are still called on the extendee and are passed the extension.
This commit is contained in:
parent
d13bbeb605
commit
acc62abbd0
7 changed files with 105 additions and 74 deletions
|
@ -121,3 +121,18 @@ def elide_list(line_list, max_num=10):
|
||||||
return line_list[:max_num-1] + ['...'] + line_list[-1:]
|
return line_list[:max_num-1] + ['...'] + line_list[-1:]
|
||||||
else:
|
else:
|
||||||
return line_list
|
return line_list
|
||||||
|
|
||||||
|
|
||||||
|
def disambiguate_spec(spec):
|
||||||
|
matching_specs = spack.db.get_installed(spec)
|
||||||
|
if not matching_specs:
|
||||||
|
tty.die("Spec '%s' matches no installed packages." % spec)
|
||||||
|
|
||||||
|
elif len(matching_specs) > 1:
|
||||||
|
args = ["%s matches multiple packages." % spec,
|
||||||
|
"Matching packages:"]
|
||||||
|
args += [" " + str(s) for s in matching_specs]
|
||||||
|
args += ["Use a more specific spec."]
|
||||||
|
tty.die(*args)
|
||||||
|
|
||||||
|
return matching_specs[0]
|
||||||
|
|
|
@ -77,37 +77,30 @@ def location(parser, args):
|
||||||
tty.die("You must supply a spec.")
|
tty.die("You must supply a spec.")
|
||||||
if len(specs) != 1:
|
if len(specs) != 1:
|
||||||
tty.die("Too many specs. Supply only one.")
|
tty.die("Too many specs. Supply only one.")
|
||||||
spec = specs[0]
|
|
||||||
|
|
||||||
if args.install_dir:
|
if args.install_dir:
|
||||||
# install_dir command matches against installed specs.
|
# install_dir command matches against installed specs.
|
||||||
matching_specs = spack.db.get_installed(spec)
|
spec = spack.cmd.disambiguate_spec(specs[0])
|
||||||
if not matching_specs:
|
print spec.prefix
|
||||||
tty.die("Spec '%s' matches no installed packages." % spec)
|
|
||||||
|
|
||||||
elif len(matching_specs) > 1:
|
|
||||||
args = ["%s matches multiple packages." % spec,
|
|
||||||
"Matching packages:"]
|
|
||||||
args += [" " + str(s) for s in matching_specs]
|
|
||||||
args += ["Use a more specific spec."]
|
|
||||||
tty.die(*args)
|
|
||||||
|
|
||||||
print matching_specs[0].prefix
|
|
||||||
|
|
||||||
elif args.package_dir:
|
|
||||||
# This one just needs the spec name.
|
|
||||||
print join_path(spack.db.root, spec.name)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# These versions need concretized specs.
|
spec = specs[0]
|
||||||
spec.concretize()
|
|
||||||
pkg = spack.db.get(spec)
|
|
||||||
|
|
||||||
if args.stage_dir:
|
if args.package_dir:
|
||||||
print pkg.stage.path
|
# This one just needs the spec name.
|
||||||
|
print join_path(spack.db.root, spec.name)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# These versions need concretized specs.
|
||||||
|
spec.concretize()
|
||||||
|
pkg = spack.db.get(spec)
|
||||||
|
|
||||||
|
if args.stage_dir:
|
||||||
|
print pkg.stage.path
|
||||||
|
|
||||||
|
else: # args.build_dir is the default.
|
||||||
|
if not pkg.stage.source_path:
|
||||||
|
tty.die("Build directory does not exist yet. Run this to create it:",
|
||||||
|
"spack stage " + " ".join(args.spec))
|
||||||
|
print pkg.stage.source_path
|
||||||
|
|
||||||
else: # args.build_dir is the default.
|
|
||||||
if not pkg.stage.source_path:
|
|
||||||
tty.die("Build directory does not exist yet. Run this to create it:",
|
|
||||||
"spack stage " + " ".join(args.spec))
|
|
||||||
print pkg.stage.source_path
|
|
||||||
|
|
|
@ -65,7 +65,6 @@ def uninstall(parser, args):
|
||||||
" b) use a more specific spec."]
|
" b) use a more specific spec."]
|
||||||
tty.die(*args)
|
tty.die(*args)
|
||||||
|
|
||||||
|
|
||||||
if len(matching_specs) == 0:
|
if len(matching_specs) == 0:
|
||||||
tty.die("%s does not match any installed packages." % spec)
|
tty.die("%s does not match any installed packages." % spec)
|
||||||
|
|
||||||
|
|
|
@ -27,23 +27,12 @@
|
||||||
|
|
||||||
|
|
||||||
def post_install(pkg):
|
def post_install(pkg):
|
||||||
assert(pkg.spec.concrete)
|
pkg.do_activate()
|
||||||
for name, spec in pkg.extendees.items():
|
|
||||||
ext = pkg.spec[name]
|
|
||||||
epkg = ext.package
|
|
||||||
if epkg.installed:
|
|
||||||
epkg.do_activate(pkg)
|
|
||||||
|
|
||||||
|
|
||||||
def pre_uninstall(pkg):
|
def pre_uninstall(pkg):
|
||||||
assert(pkg.spec.concrete)
|
|
||||||
|
|
||||||
# Need to do this b/c uninstall does not automatically do it.
|
# Need to do this b/c uninstall does not automatically do it.
|
||||||
# TODO: store full graph info in stored .spec file.
|
# TODO: store full graph info in stored .spec file.
|
||||||
pkg.spec.normalize()
|
pkg.spec.normalize()
|
||||||
|
|
||||||
for name, spec in pkg.extendees.items():
|
pkg.do_deactivate()
|
||||||
ext = pkg.spec[name]
|
|
||||||
epkg = ext.package
|
|
||||||
if epkg.installed:
|
|
||||||
epkg.do_deactivate(pkg)
|
|
||||||
|
|
|
@ -315,15 +315,18 @@ class SomePackage(Package):
|
||||||
"""Specs of virtual packages provided by this package, keyed by name."""
|
"""Specs of virtual packages provided by this package, keyed by name."""
|
||||||
provided = {}
|
provided = {}
|
||||||
|
|
||||||
"""Specs of packages this one extends, keyed by name."""
|
|
||||||
extendees = {}
|
|
||||||
|
|
||||||
"""Specs of conflicting packages, keyed by name. """
|
"""Specs of conflicting packages, keyed by name. """
|
||||||
conflicted = {}
|
conflicted = {}
|
||||||
|
|
||||||
"""Patches to apply to newly expanded source, if any."""
|
"""Patches to apply to newly expanded source, if any."""
|
||||||
patches = {}
|
patches = {}
|
||||||
|
|
||||||
|
"""Specs of package this one extends, or None.
|
||||||
|
|
||||||
|
Currently, ppackages can extend at most one other package.
|
||||||
|
"""
|
||||||
|
extendees = {}
|
||||||
|
|
||||||
#
|
#
|
||||||
# These are default values for instance variables.
|
# These are default values for instance variables.
|
||||||
#
|
#
|
||||||
|
@ -402,8 +405,8 @@ def ensure_has_dict(attr_name):
|
||||||
self._fetch_time = 0.0
|
self._fetch_time = 0.0
|
||||||
self._total_time = 0.0
|
self._total_time = 0.0
|
||||||
|
|
||||||
for name, spec in self.extendees.items():
|
if self.is_extension:
|
||||||
spack.db.get(spec)._check_extendable()
|
spack.db.get(self.extendee_spec)._check_extendable()
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -491,6 +494,34 @@ def fetcher(self, f):
|
||||||
self._fetcher = f
|
self._fetcher = f
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extendee_spec(self):
|
||||||
|
"""Spec of the extendee of this package, or None if it is not an extension."""
|
||||||
|
if not self.extendees: return None
|
||||||
|
|
||||||
|
name = next(iter(self.extendees))
|
||||||
|
if not name in self.spec:
|
||||||
|
return self.extendees[name]
|
||||||
|
|
||||||
|
# Need to do this to get the concrete version of the spec
|
||||||
|
return self.spec[name]
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_extension(self):
|
||||||
|
return len(self.extendees) > 0
|
||||||
|
|
||||||
|
|
||||||
|
@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.")
|
||||||
|
|
||||||
|
return self.spec in spack.install_layout.get_extensions(self.extendee_spec)
|
||||||
|
|
||||||
|
|
||||||
def preorder_traversal(self, visited=None, **kwargs):
|
def preorder_traversal(self, visited=None, **kwargs):
|
||||||
"""This does a preorder traversal of the package's dependence DAG."""
|
"""This does a preorder traversal of the package's dependence DAG."""
|
||||||
virtual = kwargs.get("virtual", False)
|
virtual = kwargs.get("virtual", False)
|
||||||
|
@ -784,10 +815,9 @@ def do_install(self, **kwargs):
|
||||||
build_env.setup_package(self)
|
build_env.setup_package(self)
|
||||||
|
|
||||||
# Allow extendees to further set up the environment.
|
# Allow extendees to further set up the environment.
|
||||||
for ext_name in self.extendees:
|
if self.is_extension:
|
||||||
ext_spec = self.spec[ext_name]
|
self.extendee_spec.package.setup_extension_environment(
|
||||||
ext_spec.package.setup_extension_environment(
|
self.module, self.extendee_spec, self.spec)
|
||||||
self.module, ext_spec, self.spec)
|
|
||||||
|
|
||||||
if fake_install:
|
if fake_install:
|
||||||
self.do_fake_install()
|
self.do_fake_install()
|
||||||
|
@ -840,7 +870,6 @@ def do_install(self, **kwargs):
|
||||||
if returncode != 0:
|
if returncode != 0:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
# Once everything else is done, run post install hooks
|
# Once everything else is done, run post install hooks
|
||||||
spack.hooks.post_install(self)
|
spack.hooks.post_install(self)
|
||||||
|
|
||||||
|
@ -919,25 +948,30 @@ def _check_extendable(self):
|
||||||
raise ValueError("Package %s is not extendable!" % self.name)
|
raise ValueError("Package %s is not extendable!" % self.name)
|
||||||
|
|
||||||
|
|
||||||
def _sanity_check_extension(self, extension):
|
def _sanity_check_extension(self):
|
||||||
self._check_extendable()
|
extendee_package = self.extendee_spec.package
|
||||||
if not self.installed:
|
extendee_package._check_extendable()
|
||||||
|
|
||||||
|
if not extendee_package.installed:
|
||||||
raise ValueError("Can only (de)activate extensions for installed packages.")
|
raise ValueError("Can only (de)activate extensions for installed packages.")
|
||||||
if not extension.installed:
|
if not self.installed:
|
||||||
raise ValueError("Extensions must first be installed.")
|
raise ValueError("Extensions must first be installed.")
|
||||||
if not self.name in extension.extendees:
|
if not self.extendee_spec.name in self.extendees:
|
||||||
raise ValueError("%s does not extend %s!" % (extension.name, self.name))
|
raise ValueError("%s does not extend %s!" % (self.name, self.extendee.name))
|
||||||
if not self.spec.satisfies(extension.extendees[self.name]):
|
|
||||||
raise ValueError("%s does not satisfy %s!" % (self.spec, extension.spec))
|
|
||||||
|
|
||||||
|
|
||||||
def do_activate(self, extension):
|
def do_activate(self):
|
||||||
self._sanity_check_extension(extension)
|
"""Called on an etension to invoke the extendee's activate method.
|
||||||
|
|
||||||
self.activate(extension)
|
Commands should call this routine, and should not call
|
||||||
spack.install_layout.add_extension(self.spec, extension.spec)
|
activate() directly.
|
||||||
|
"""
|
||||||
|
self._sanity_check_extension()
|
||||||
|
self.extendee_spec.package.activate(self)
|
||||||
|
|
||||||
|
spack.install_layout.add_extension(self.extendee_spec, self.spec)
|
||||||
tty.msg("Activated extension %s for %s."
|
tty.msg("Activated extension %s for %s."
|
||||||
% (extension.spec.short_spec, self.spec.short_spec))
|
% (self.spec.short_spec, self.extendee_spec.short_spec))
|
||||||
|
|
||||||
|
|
||||||
def activate(self, extension):
|
def activate(self, extension):
|
||||||
|
@ -957,20 +991,19 @@ def activate(self, extension):
|
||||||
tree.merge(self.prefix, ignore=spack.install_layout.hidden_file_paths)
|
tree.merge(self.prefix, ignore=spack.install_layout.hidden_file_paths)
|
||||||
|
|
||||||
|
|
||||||
def do_deactivate(self, extension):
|
def do_deactivate(self):
|
||||||
self._sanity_check_extension(extension)
|
self._sanity_check_extension()
|
||||||
self.deactivate(extension)
|
self.extendee_spec.package.deactivate(self)
|
||||||
|
|
||||||
ext = extension.spec
|
if self.spec in spack.install_layout.get_extensions(self.extendee_spec):
|
||||||
if ext in spack.install_layout.get_extensions(self.spec):
|
spack.install_layout.remove_extension(self.extendee_spec, self.spec)
|
||||||
spack.install_layout.remove_extension(self.spec, ext)
|
|
||||||
|
|
||||||
tty.msg("Deactivated extension %s for %s."
|
tty.msg("Deactivated extension %s for %s."
|
||||||
% (extension.spec.short_spec, self.spec.short_spec))
|
% (self.spec.short_spec, self.extendee_spec.short_spec))
|
||||||
|
|
||||||
|
|
||||||
def deactivate(self, extension):
|
def deactivate(self, extension):
|
||||||
"""Unlinks all files from extension out of extendee's install dir.
|
"""Unlinks all files from extension out of this package's install dir.
|
||||||
|
|
||||||
Package authors can override this method to support other
|
Package authors can override this method to support other
|
||||||
extension mechanisms. Spack internals (commands, hooks, etc.)
|
extension mechanisms. Spack internals (commands, hooks, etc.)
|
||||||
|
@ -980,8 +1013,6 @@ def deactivate(self, extension):
|
||||||
"""
|
"""
|
||||||
tree = LinkTree(extension.prefix)
|
tree = LinkTree(extension.prefix)
|
||||||
tree.unmerge(self.prefix, ignore=spack.install_layout.hidden_file_paths)
|
tree.unmerge(self.prefix, ignore=spack.install_layout.hidden_file_paths)
|
||||||
tty.msg("Deactivated %s as extension of %s."
|
|
||||||
% (extension.spec.short_spec, self.spec.short_spec))
|
|
||||||
|
|
||||||
|
|
||||||
def do_clean(self):
|
def do_clean(self):
|
||||||
|
|
|
@ -77,6 +77,8 @@ def get(self, spec, **kwargs):
|
||||||
copy = spec.copy()
|
copy = spec.copy()
|
||||||
self.instances[copy] = package_class(copy)
|
self.instances[copy] = package_class(copy)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
if spack.debug:
|
||||||
|
sys.excepthook(*sys.exc_info())
|
||||||
raise FailedConstructorError(spec.name, e)
|
raise FailedConstructorError(spec.name, e)
|
||||||
|
|
||||||
return self.instances[spec]
|
return self.instances[spec]
|
||||||
|
|
|
@ -131,6 +131,8 @@ def extends(*specs):
|
||||||
clocals = caller_locals()
|
clocals = caller_locals()
|
||||||
dependencies = clocals.setdefault('dependencies', {})
|
dependencies = clocals.setdefault('dependencies', {})
|
||||||
extendees = clocals.setdefault('extendees', {})
|
extendees = clocals.setdefault('extendees', {})
|
||||||
|
if extendees:
|
||||||
|
raise RelationError("Packages can extend at most one other package.")
|
||||||
|
|
||||||
for string in specs:
|
for string in specs:
|
||||||
for spec in spack.spec.parse(string):
|
for spec in spack.spec.parse(string):
|
||||||
|
|
Loading…
Reference in a new issue