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:]
|
||||
else:
|
||||
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.")
|
||||
if len(specs) != 1:
|
||||
tty.die("Too many specs. Supply only one.")
|
||||
spec = specs[0]
|
||||
|
||||
if args.install_dir:
|
||||
# install_dir command matches against installed specs.
|
||||
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)
|
||||
|
||||
print matching_specs[0].prefix
|
||||
|
||||
elif args.package_dir:
|
||||
# This one just needs the spec name.
|
||||
print join_path(spack.db.root, spec.name)
|
||||
spec = spack.cmd.disambiguate_spec(specs[0])
|
||||
print spec.prefix
|
||||
|
||||
else:
|
||||
# These versions need concretized specs.
|
||||
spec.concretize()
|
||||
pkg = spack.db.get(spec)
|
||||
spec = specs[0]
|
||||
|
||||
if args.stage_dir:
|
||||
print pkg.stage.path
|
||||
if args.package_dir:
|
||||
# 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."]
|
||||
tty.die(*args)
|
||||
|
||||
|
||||
if len(matching_specs) == 0:
|
||||
tty.die("%s does not match any installed packages." % spec)
|
||||
|
||||
|
|
|
@ -27,23 +27,12 @@
|
|||
|
||||
|
||||
def post_install(pkg):
|
||||
assert(pkg.spec.concrete)
|
||||
for name, spec in pkg.extendees.items():
|
||||
ext = pkg.spec[name]
|
||||
epkg = ext.package
|
||||
if epkg.installed:
|
||||
epkg.do_activate(pkg)
|
||||
pkg.do_activate()
|
||||
|
||||
|
||||
def pre_uninstall(pkg):
|
||||
assert(pkg.spec.concrete)
|
||||
|
||||
# Need to do this b/c uninstall does not automatically do it.
|
||||
# TODO: store full graph info in stored .spec file.
|
||||
pkg.spec.normalize()
|
||||
|
||||
for name, spec in pkg.extendees.items():
|
||||
ext = pkg.spec[name]
|
||||
epkg = ext.package
|
||||
if epkg.installed:
|
||||
epkg.do_deactivate(pkg)
|
||||
pkg.do_deactivate()
|
||||
|
|
|
@ -315,15 +315,18 @@ class SomePackage(Package):
|
|||
"""Specs of virtual packages provided by this package, keyed by name."""
|
||||
provided = {}
|
||||
|
||||
"""Specs of packages this one extends, keyed by name."""
|
||||
extendees = {}
|
||||
|
||||
"""Specs of conflicting packages, keyed by name. """
|
||||
conflicted = {}
|
||||
|
||||
"""Patches to apply to newly expanded source, if any."""
|
||||
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.
|
||||
#
|
||||
|
@ -402,8 +405,8 @@ def ensure_has_dict(attr_name):
|
|||
self._fetch_time = 0.0
|
||||
self._total_time = 0.0
|
||||
|
||||
for name, spec in self.extendees.items():
|
||||
spack.db.get(spec)._check_extendable()
|
||||
if self.is_extension:
|
||||
spack.db.get(self.extendee_spec)._check_extendable()
|
||||
|
||||
|
||||
@property
|
||||
|
@ -491,6 +494,34 @@ def fetcher(self, 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):
|
||||
"""This does a preorder traversal of the package's dependence DAG."""
|
||||
virtual = kwargs.get("virtual", False)
|
||||
|
@ -784,10 +815,9 @@ def do_install(self, **kwargs):
|
|||
build_env.setup_package(self)
|
||||
|
||||
# Allow extendees to further set up the environment.
|
||||
for ext_name in self.extendees:
|
||||
ext_spec = self.spec[ext_name]
|
||||
ext_spec.package.setup_extension_environment(
|
||||
self.module, ext_spec, self.spec)
|
||||
if self.is_extension:
|
||||
self.extendee_spec.package.setup_extension_environment(
|
||||
self.module, self.extendee_spec, self.spec)
|
||||
|
||||
if fake_install:
|
||||
self.do_fake_install()
|
||||
|
@ -840,7 +870,6 @@ def do_install(self, **kwargs):
|
|||
if returncode != 0:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Once everything else is done, run post install hooks
|
||||
spack.hooks.post_install(self)
|
||||
|
||||
|
@ -919,25 +948,30 @@ def _check_extendable(self):
|
|||
raise ValueError("Package %s is not extendable!" % self.name)
|
||||
|
||||
|
||||
def _sanity_check_extension(self, extension):
|
||||
self._check_extendable()
|
||||
if not self.installed:
|
||||
def _sanity_check_extension(self):
|
||||
extendee_package = self.extendee_spec.package
|
||||
extendee_package._check_extendable()
|
||||
|
||||
if not extendee_package.installed:
|
||||
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.")
|
||||
if not self.name in extension.extendees:
|
||||
raise ValueError("%s does not extend %s!" % (extension.name, self.name))
|
||||
if not self.spec.satisfies(extension.extendees[self.name]):
|
||||
raise ValueError("%s does not satisfy %s!" % (self.spec, extension.spec))
|
||||
if not self.extendee_spec.name in self.extendees:
|
||||
raise ValueError("%s does not extend %s!" % (self.name, self.extendee.name))
|
||||
|
||||
|
||||
def do_activate(self, extension):
|
||||
self._sanity_check_extension(extension)
|
||||
def do_activate(self):
|
||||
"""Called on an etension to invoke the extendee's activate method.
|
||||
|
||||
self.activate(extension)
|
||||
spack.install_layout.add_extension(self.spec, extension.spec)
|
||||
Commands should call this routine, and should not call
|
||||
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."
|
||||
% (extension.spec.short_spec, self.spec.short_spec))
|
||||
% (self.spec.short_spec, self.extendee_spec.short_spec))
|
||||
|
||||
|
||||
def activate(self, extension):
|
||||
|
@ -957,20 +991,19 @@ def activate(self, extension):
|
|||
tree.merge(self.prefix, ignore=spack.install_layout.hidden_file_paths)
|
||||
|
||||
|
||||
def do_deactivate(self, extension):
|
||||
self._sanity_check_extension(extension)
|
||||
self.deactivate(extension)
|
||||
def do_deactivate(self):
|
||||
self._sanity_check_extension()
|
||||
self.extendee_spec.package.deactivate(self)
|
||||
|
||||
ext = extension.spec
|
||||
if ext in spack.install_layout.get_extensions(self.spec):
|
||||
spack.install_layout.remove_extension(self.spec, ext)
|
||||
if self.spec in spack.install_layout.get_extensions(self.extendee_spec):
|
||||
spack.install_layout.remove_extension(self.extendee_spec, self.spec)
|
||||
|
||||
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):
|
||||
"""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
|
||||
extension mechanisms. Spack internals (commands, hooks, etc.)
|
||||
|
@ -980,8 +1013,6 @@ def deactivate(self, extension):
|
|||
"""
|
||||
tree = LinkTree(extension.prefix)
|
||||
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):
|
||||
|
|
|
@ -77,6 +77,8 @@ def get(self, spec, **kwargs):
|
|||
copy = spec.copy()
|
||||
self.instances[copy] = package_class(copy)
|
||||
except Exception, e:
|
||||
if spack.debug:
|
||||
sys.excepthook(*sys.exc_info())
|
||||
raise FailedConstructorError(spec.name, e)
|
||||
|
||||
return self.instances[spec]
|
||||
|
|
|
@ -131,6 +131,8 @@ def extends(*specs):
|
|||
clocals = caller_locals()
|
||||
dependencies = clocals.setdefault('dependencies', {})
|
||||
extendees = clocals.setdefault('extendees', {})
|
||||
if extendees:
|
||||
raise RelationError("Packages can extend at most one other package.")
|
||||
|
||||
for string in specs:
|
||||
for spec in spack.spec.parse(string):
|
||||
|
|
Loading…
Reference in a new issue