From 9fb37dfd765a2439d5f739581c39fa6176d03551 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 15 Oct 2018 10:33:12 -0700 Subject: env: `spack install SPEC` installs into currently active environment. - install will now add (if necessary), concretize, and install a single spec into the active environment. --- lib/spack/spack/cmd/env.py | 4 +-- lib/spack/spack/cmd/install.py | 16 +++++++-- lib/spack/spack/environment.py | 72 +++++++++++++++++++++++++++++++++++++++-- lib/spack/spack/test/cmd/env.py | 17 ++++++++-- 4 files changed, 100 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py index df26e9ece7..a0bf91bf48 100644 --- a/lib/spack/spack/cmd/env.py +++ b/lib/spack/spack/cmd/env.py @@ -283,7 +283,7 @@ def env_list(args): def env_add_setup_parser(subparser): """add a spec to an environment""" subparser.add_argument( - '-e', '--env', help='add spec to environment with this name') + '-e', '--env', help='add spec to this environment') subparser.add_argument( 'specs', nargs=argparse.REMAINDER, help="spec of the package to add") @@ -371,7 +371,7 @@ def env_install(args): env.write() # install all specs in the environment - env.install(args) + env.install_all(args) # REMOVE diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py index c1f1d09072..a628ba85c4 100644 --- a/lib/spack/spack/cmd/install.py +++ b/lib/spack/spack/cmd/install.py @@ -150,17 +150,27 @@ def default_log_file(spec): def install_spec(cli_args, kwargs, spec): - # Do the actual installation + """Do the actual installation.""" + + # handle active environment, if any + def install(spec, kwargs): + env = spack.environment.active + if env: + new_specs = env.install(spec, kwargs) + env.write(dump_packages=new_specs) + else: + spec.package.do_install(**kwargs) + try: if cli_args.things_to_install == 'dependencies': # Install dependencies as-if they were installed # for root (explicit=False in the DB) kwargs['explicit'] = False for s in spec.dependencies(): - s.package.do_install(**kwargs) + install(s, kwargs) else: kwargs['explicit'] = True - spec.package.do_install(**kwargs) + install(spec, kwargs) except spack.build_environment.InstallError as e: if cli_args.show_log_on_error: diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index fd21ece9e1..049fdff66d 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -116,9 +116,29 @@ def deactivate(): """ global active + if not active: return + deactivate_config_scope(active) + spack.repo.path.remove(active.repo) + + tty.debug("Deactivated environmennt '%s'" % active.name) + active = None + + +@contextmanager +def env_context(env): + """Context manager that activates and deactivates an environment.""" + old_active = active + activate(env) + + yield + + deactivate() + if old_active: + activate(old_active) + def root(name): """Get the root directory for an environment by name.""" @@ -333,7 +353,7 @@ class Environment(object): """Remove this environment from Spack entirely.""" shutil.rmtree(self.path) - def add(self, user_spec, report_existing=True): + def add(self, user_spec): """Add a single user_spec (non-concretized) to the Environment Returns: @@ -342,6 +362,10 @@ class Environment(object): """ spec = Spec(user_spec) + if not spec.name: + raise EnvError('cannot add anonymous specs to an environment!') + elif not spack.repo.path.exists(spec.name): + raise EnvError('no such package: %s' % spec.name) existing = set(s for s in self.user_specs if s.name == spec.name) if not existing: @@ -425,7 +449,45 @@ class Environment(object): # return only the newly concretized specs return new_specs - def install(self, args=None): + def install(self, user_spec, install_args=None): + """Install a single spec into an environment. + + This will automatically concretize the single spec, but it won't + affect other as-yet unconcretized specs. + + Returns: + (Spec): concrete spec if the spec was installed, None if it + was already present and installed. + + """ + spec = Spec(user_spec) + + # TODO: do a more sophisticated match than just by name + added = self.add(spec) + concrete = None + if added: + # newly added spec + spec = self.user_specs[-1] + concrete = spec.concretized() + h = concrete.dag_hash() + + self.concretized_user_specs.append(spec) + self.concretized_order.append(h) + self.specs_by_hash[h] = concrete + + else: + # spec might be in the user_specs, but not installed. + spec = next(s for s in self.user_specs if s.name == spec.name) + if spec not in self.concretized_user_specs: + concrete = spec.concretized() + self.concretized_user_specs.append(spec) + self.concretized_order.append(h) + self.specs_by_hash[h] = concrete + + if concrete: + spec.package.do_install(**install_args) + + def install_all(self, args=None): """Install all concretized specs in an environment.""" # Make sure log directory exists @@ -706,6 +768,12 @@ def prepare_config_scope(env): spack.config.config.push_scope(scope) +def deactivate_config_scope(env): + """Remove any scopes from env from the global config path.""" + for scope in env.config_scopes(): + spack.config.config.remove_scope(scope.name) + + class EnvError(spack.error.SpackError): """Superclass for all errors to do with Spack environments. diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 95ab60d569..7b61f11f8b 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -71,16 +71,29 @@ def test_concretize(): assert any(x.name == 'mpileaks' for x in env_specs) -def test_env_install(install_mockery, mock_fetch): +def test_env_install_all(install_mockery, mock_fetch): e = ev.Environment('test') e.add('cmake-client') e.concretize() - e.install() + e.install_all() env_specs = e._get_environment_specs() spec = next(x for x in env_specs if x.name == 'cmake-client') assert spec.package.installed +def test_env_install(install_mockery, mock_fetch): + env('create', 'test') + install = SpackCommand('install') + + with ev.env_context('test'): + install('cmake-client') + + e = ev.read('test') + assert e.user_specs[0].name == 'cmake-client' + assert e.concretized_user_specs[0].name == 'cmake-client' + assert e.specs_by_hash[e.concretized_order[0]].name == 'cmake-client' + + def test_remove_after_concretize(): e = ev.Environment('test') -- cgit v1.2.3-70-g09d2