From c0c9ab113e0078c53e60df6cb7cb064e6f92c45b Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 11 Oct 2021 12:56:03 +0200 Subject: [PATCH] Add `spack env activate --temp` (#25388) Creates an environment in a temporary directory and activates it, which is useful for a quick ephemeral environment: ``` $ spack env activate -p --temp [spack-1a203lyg] $ spack add zlib ==> Adding zlib to environment /tmp/spack-1a203lyg ==> Updating view at /tmp/spack-1a203lyg/.spack-env/view ``` --- lib/spack/spack/cmd/env.py | 58 +++++++++++++++++++++--------- lib/spack/spack/test/cmd/env.py | 12 +++++++ share/spack/qa/setup-env-test.fish | 8 ++++- share/spack/qa/setup-env-test.sh | 8 ++++- share/spack/spack-completion.bash | 2 +- 5 files changed, 69 insertions(+), 19 deletions(-) diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py index ae45e105de..5b9caa0877 100644 --- a/lib/spack/spack/cmd/env.py +++ b/lib/spack/spack/cmd/env.py @@ -6,6 +6,7 @@ import os import shutil import sys +import tempfile import llnl.util.filesystem as fs import llnl.util.tty as tty @@ -69,24 +70,38 @@ def env_activate_setup_parser(subparser): const=False, default=True, help="do not update PATH etc. with associated view") - subparser.add_argument( - '-d', '--dir', action='store_true', default=False, - help="force spack to treat env as a directory, not a name") subparser.add_argument( '-p', '--prompt', action='store_true', default=False, help="decorate the command line prompt when activating") - subparser.add_argument( - metavar='env', dest='activate_env', + + env_options = subparser.add_mutually_exclusive_group() + env_options.add_argument( + '--temp', action='store_true', default=False, + help='create and activate an environment in a temporary directory') + env_options.add_argument( + '-d', '--dir', default=None, + help="activate the environment in this directory") + env_options.add_argument( + metavar='env', dest='activate_env', nargs='?', default=None, help='name of environment to activate') +def create_temp_env_directory(): + """ + Returns the path of a temporary directory in which to + create an environment + """ + return tempfile.mkdtemp(prefix="spack-") + + def env_activate(args): - env = args.activate_env + if not args.activate_env and not args.dir and not args.temp: + tty.die('spack env activate requires an environment name, directory, or --temp') if not args.shell: spack.cmd.common.shell_init_instructions( "spack env activate", - " eval `spack env activate {sh_arg} %s`" % env, + " eval `spack env activate {sh_arg} [...]`", ) return 1 @@ -95,21 +110,32 @@ def env_activate(args): tty.die('Calling spack env activate with --env, --env-dir and --no-env ' 'is ambiguous') - if ev.exists(env) and not args.dir: - spack_env = ev.root(env) - short_name = env - env_prompt = '[%s]' % env + env_name_or_dir = args.activate_env or args.dir - elif ev.is_env_dir(env): + # Temporary environment + if args.temp: + env = create_temp_env_directory() spack_env = os.path.abspath(env) - short_name = os.path.basename(os.path.abspath(env)) - env_prompt = '[%s]' % short_name + short_name = os.path.basename(spack_env) + ev.Environment(env).write(regenerate=False) + + # Named environment + elif ev.exists(env_name_or_dir) and not args.dir: + spack_env = ev.root(env_name_or_dir) + short_name = env_name_or_dir + + # Environment directory + elif ev.is_env_dir(env_name_or_dir): + spack_env = os.path.abspath(env_name_or_dir) + short_name = os.path.basename(spack_env) else: - tty.die("No such environment: '%s'" % env) + tty.die("No such environment: '%s'" % env_name_or_dir) + + env_prompt = '[%s]' % short_name if spack_env == os.environ.get('SPACK_ENV'): - tty.debug("Environment %s is already active" % args.activate_env) + tty.debug("Environment is already active") return # Activate new environment diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 5c57035527..553d80c562 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -2681,3 +2681,15 @@ def test_custom_store_in_environment(mutable_config, tmpdir): with spack.environment.Environment(str(tmpdir)): assert str(spack.store.root) == '/tmp/store' assert str(spack.store.root) == current_store_root + + +def test_activate_temp(monkeypatch, tmpdir): + """Tests whether `spack env activate --temp` creates an environment in a + temporary directory""" + env_dir = lambda: str(tmpdir) + monkeypatch.setattr(spack.cmd.env, "create_temp_env_directory", env_dir) + shell = env('activate', '--temp', '--sh') + active_env_var = next(line for line in shell.splitlines() + if ev.spack_env_var in line) + assert str(tmpdir) in active_env_var + assert ev.is_env_dir(str(tmpdir)) diff --git a/share/spack/qa/setup-env-test.fish b/share/spack/qa/setup-env-test.fish index 585b45bb9c..5cd257aa86 100755 --- a/share/spack/qa/setup-env-test.fish +++ b/share/spack/qa/setup-env-test.fish @@ -333,7 +333,7 @@ spt_contains " spack env list " spack env list --help title 'Testing `spack env activate`' spt_contains "No such environment:" spack env activate no_such_environment -spt_contains "usage: spack env activate " spack env activate +spt_contains "env activate requires an environment " spack env activate spt_contains "usage: spack env activate " spack env activate -h spt_contains "usage: spack env activate " spack env activate --help @@ -360,6 +360,12 @@ echo "Testing 'despacktivate'" despacktivate is_not_set SPACK_ENV +echo "Testing 'spack env activate --temp'" +spack env activate --temp +is_set SPACK_ENV +spack env deactivate +is_not_set SPACK_ENV + # # NOTE: `--prompt` on fish does nothing => currently not implemented. # diff --git a/share/spack/qa/setup-env-test.sh b/share/spack/qa/setup-env-test.sh index bf3bfe63f3..88e30aefeb 100755 --- a/share/spack/qa/setup-env-test.sh +++ b/share/spack/qa/setup-env-test.sh @@ -137,7 +137,7 @@ contains " spack env list " spack env list --help title 'Testing `spack env activate`' contains "No such environment:" spack env activate no_such_environment -contains "usage: spack env activate " spack env activate +contains "env activate requires an environment " spack env activate contains "usage: spack env activate " spack env activate -h contains "usage: spack env activate " spack env activate --help @@ -173,3 +173,9 @@ echo "Testing 'despacktivate'" despacktivate is_not_set SPACK_ENV is_not_set SPACK_OLD_PS1 + +echo "Testing 'spack env activate --temp'" +spack env activate --temp +is_set SPACK_ENV +spack env deactivate +is_not_set SPACK_ENV \ No newline at end of file diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index 33553d374f..c64495e1d6 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -911,7 +911,7 @@ _spack_env() { _spack_env_activate() { if $list_options then - SPACK_COMPREPLY="-h --help --sh --csh --fish -v --with-view -V --without-view -d --dir -p --prompt" + SPACK_COMPREPLY="-h --help --sh --csh --fish -v --with-view -V --without-view -p --prompt --temp -d --dir" else _environments fi