summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2015-01-12 22:39:18 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2015-02-02 11:19:53 -0800
commitacc62abbd08f6d44c930b0ceed74fb9e47f365cf (patch)
treef5c13492a4a73c6d3ee92627d985a26a7ee04fae /lib
parentd13bbeb605f56214db919f6f122a8fa6ba67ddbc (diff)
downloadspack-acc62abbd08f6d44c930b0ceed74fb9e47f365cf.tar.gz
spack-acc62abbd08f6d44c930b0ceed74fb9e47f365cf.tar.bz2
spack-acc62abbd08f6d44c930b0ceed74fb9e47f365cf.tar.xz
spack-acc62abbd08f6d44c930b0ceed74fb9e47f365cf.zip
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/__init__.py15
-rw-r--r--lib/spack/spack/cmd/location.py47
-rw-r--r--lib/spack/spack/cmd/uninstall.py1
-rw-r--r--lib/spack/spack/hooks/extensions.py15
-rw-r--r--lib/spack/spack/package.py97
-rw-r--r--lib/spack/spack/packages.py2
-rw-r--r--lib/spack/spack/relations.py2
7 files changed, 105 insertions, 74 deletions
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index 537db536dd..b96ac5af51 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -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]
diff --git a/lib/spack/spack/cmd/location.py b/lib/spack/spack/cmd/location.py
index 509c336b69..810c34d0a6 100644
--- a/lib/spack/spack/cmd/location.py
+++ b/lib/spack/spack/cmd/location.py
@@ -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)
+ spec = spack.cmd.disambiguate_spec(specs[0])
+ print spec.prefix
- 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)
+ else:
+ spec = specs[0]
- print matching_specs[0].prefix
+ if args.package_dir:
+ # This one just needs the spec name.
+ print join_path(spack.db.root, spec.name)
- elif 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:
- # 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
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index e787c460ad..0962942f43 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -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)
diff --git a/lib/spack/spack/hooks/extensions.py b/lib/spack/spack/hooks/extensions.py
index 444472bffa..2cf506beed 100644
--- a/lib/spack/spack/hooks/extensions.py
+++ b/lib/spack/spack/hooks/extensions.py
@@ -27,23 +27,12 @@ import spack
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()
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 8504b96fcf..ae34f8ae45 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -315,15 +315,18 @@ class Package(object):
"""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 @@ class Package(object):
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 @@ class Package(object):
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 @@ class Package(object):
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 @@ class Package(object):
if returncode != 0:
sys.exit(1)
-
# Once everything else is done, run post install hooks
spack.hooks.post_install(self)
@@ -919,25 +948,30 @@ class Package(object):
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):
+ """Called on an etension to invoke the extendee's activate method.
- def do_activate(self, extension):
- self._sanity_check_extension(extension)
+ Commands should call this routine, and should not call
+ activate() directly.
+ """
+ self._sanity_check_extension()
+ self.extendee_spec.package.activate(self)
- self.activate(extension)
- spack.install_layout.add_extension(self.spec, extension.spec)
+ 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 @@ class Package(object):
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 @@ class Package(object):
"""
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):
diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py
index db43d3909a..bb5a94bcab 100644
--- a/lib/spack/spack/packages.py
+++ b/lib/spack/spack/packages.py
@@ -77,6 +77,8 @@ class PackageDB(object):
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]
diff --git a/lib/spack/spack/relations.py b/lib/spack/spack/relations.py
index 17bec1664f..60ff5bef34 100644
--- a/lib/spack/spack/relations.py
+++ b/lib/spack/spack/relations.py
@@ -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):