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:
		| @@ -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): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Todd Gamblin
					Todd Gamblin