Add --create
to spack env activate
(#40896)
Add `--create` option to `env activate` to allow users to create and activate in one command. --------- Co-authored-by: Wouter Deconinck <wdconinc@gmail.com> Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Co-authored-by: psakievich <psakievich@users.noreply.github.com>
This commit is contained in:
parent
ec758bfd5b
commit
12963529af
@ -142,6 +142,21 @@ user's prompt to begin with the environment name in brackets.
|
|||||||
$ spack env activate -p myenv
|
$ spack env activate -p myenv
|
||||||
[myenv] $ ...
|
[myenv] $ ...
|
||||||
|
|
||||||
|
The ``activate`` command can also be used to create a new environment, if it is
|
||||||
|
not already defined, by adding the ``--create`` flag. Managed and anonymous
|
||||||
|
environments, anonymous environments are explained in the next section,
|
||||||
|
can both be created using the same flags that `spack env create` accepts.
|
||||||
|
If an environment already exists then spack will simply activate it and ignore the
|
||||||
|
create specific flags.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ spack env activate --create -p myenv
|
||||||
|
# ...
|
||||||
|
# [creates if myenv does not exist yet]
|
||||||
|
# ...
|
||||||
|
[myenv] $ ...
|
||||||
|
|
||||||
To deactivate an environment, use the command:
|
To deactivate an environment, use the command:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
@ -54,6 +54,104 @@
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# env create
|
||||||
|
#
|
||||||
|
def env_create_setup_parser(subparser):
|
||||||
|
"""create a new environment"""
|
||||||
|
subparser.add_argument(
|
||||||
|
"env_name",
|
||||||
|
metavar="env",
|
||||||
|
help=(
|
||||||
|
"name of managed environment or directory of the anonymous env "
|
||||||
|
"(when using --dir/-d) to activate"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"-d", "--dir", action="store_true", help="create an environment in a specific directory"
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"--keep-relative",
|
||||||
|
action="store_true",
|
||||||
|
help="copy relative develop paths verbatim into the new environment"
|
||||||
|
" when initializing from envfile",
|
||||||
|
)
|
||||||
|
view_opts = subparser.add_mutually_exclusive_group()
|
||||||
|
view_opts.add_argument(
|
||||||
|
"--without-view", action="store_true", help="do not maintain a view for this environment"
|
||||||
|
)
|
||||||
|
view_opts.add_argument(
|
||||||
|
"--with-view",
|
||||||
|
help="specify that this environment should maintain a view at the"
|
||||||
|
" specified path (by default the view is maintained in the"
|
||||||
|
" environment directory)",
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"envfile",
|
||||||
|
nargs="?",
|
||||||
|
default=None,
|
||||||
|
help="either a lockfile (must end with '.json' or '.lock') or a manifest file",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def env_create(args):
|
||||||
|
if args.with_view:
|
||||||
|
# Expand relative paths provided on the command line to the current working directory
|
||||||
|
# This way we interpret `spack env create --with-view ./view --dir ./env` as
|
||||||
|
# a view in $PWD/view, not $PWD/env/view. This is different from specifying a relative
|
||||||
|
# path in the manifest, which is resolved relative to the manifest file's location.
|
||||||
|
with_view = os.path.abspath(args.with_view)
|
||||||
|
elif args.without_view:
|
||||||
|
with_view = False
|
||||||
|
else:
|
||||||
|
# Note that 'None' means unspecified, in which case the Environment
|
||||||
|
# object could choose to enable a view by default. False means that
|
||||||
|
# the environment should not include a view.
|
||||||
|
with_view = None
|
||||||
|
|
||||||
|
env = _env_create(
|
||||||
|
args.env_name,
|
||||||
|
init_file=args.envfile,
|
||||||
|
dir=args.dir,
|
||||||
|
with_view=with_view,
|
||||||
|
keep_relative=args.keep_relative,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate views, only really useful for environments created from spack.lock files.
|
||||||
|
env.regenerate_views()
|
||||||
|
|
||||||
|
|
||||||
|
def _env_create(name_or_path, *, init_file=None, dir=False, with_view=None, keep_relative=False):
|
||||||
|
"""Create a new environment, with an optional yaml description.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
name_or_path (str): name of the environment to create, or path to it
|
||||||
|
init_file (str or file): optional initialization file -- can be
|
||||||
|
a JSON lockfile (*.lock, *.json) or YAML manifest file
|
||||||
|
dir (bool): if True, create an environment in a directory instead
|
||||||
|
of a named environment
|
||||||
|
keep_relative (bool): if True, develop paths are copied verbatim into
|
||||||
|
the new environment file, otherwise they may be made absolute if the
|
||||||
|
new environment is in a different location
|
||||||
|
"""
|
||||||
|
if not dir:
|
||||||
|
env = ev.create(
|
||||||
|
name_or_path, init_file=init_file, with_view=with_view, keep_relative=keep_relative
|
||||||
|
)
|
||||||
|
tty.msg("Created environment '%s' in %s" % (name_or_path, env.path))
|
||||||
|
tty.msg("You can activate this environment with:")
|
||||||
|
tty.msg(" spack env activate %s" % (name_or_path))
|
||||||
|
return env
|
||||||
|
|
||||||
|
env = ev.create_in_dir(
|
||||||
|
name_or_path, init_file=init_file, with_view=with_view, keep_relative=keep_relative
|
||||||
|
)
|
||||||
|
tty.msg("Created environment in %s" % env.path)
|
||||||
|
tty.msg("You can activate this environment with:")
|
||||||
|
tty.msg(" spack env activate %s" % env.path)
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# env activate
|
# env activate
|
||||||
#
|
#
|
||||||
@ -118,22 +216,46 @@ def env_activate_setup_parser(subparser):
|
|||||||
help="decorate the command line prompt when activating",
|
help="decorate the command line prompt when activating",
|
||||||
)
|
)
|
||||||
|
|
||||||
env_options = subparser.add_mutually_exclusive_group()
|
subparser.add_argument(
|
||||||
env_options.add_argument(
|
|
||||||
"--temp",
|
"--temp",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
default=False,
|
default=False,
|
||||||
help="create and activate an environment in a temporary directory",
|
help="create and activate an environment in a temporary directory",
|
||||||
)
|
)
|
||||||
env_options.add_argument(
|
subparser.add_argument(
|
||||||
"-d", "--dir", default=None, help="activate the environment in this directory"
|
"--create",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="create and activate the environment if it doesn't exist",
|
||||||
)
|
)
|
||||||
env_options.add_argument(
|
subparser.add_argument(
|
||||||
metavar="env",
|
"--envfile",
|
||||||
dest="activate_env",
|
|
||||||
nargs="?",
|
nargs="?",
|
||||||
default=None,
|
default=None,
|
||||||
help="name of environment to activate",
|
help="either a lockfile (must end with '.json' or '.lock') or a manifest file",
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"--keep-relative",
|
||||||
|
action="store_true",
|
||||||
|
help="copy relative develop paths verbatim into the new environment"
|
||||||
|
" when initializing from envfile",
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--dir",
|
||||||
|
default=False,
|
||||||
|
action="store_true",
|
||||||
|
help="activate environment based on the directory supplied",
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
metavar="env",
|
||||||
|
dest="env_name",
|
||||||
|
nargs="?",
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
"name of managed environment or directory of the anonymous env"
|
||||||
|
" (when using --dir/-d) to activate"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -162,11 +284,17 @@ def env_activate(args):
|
|||||||
if args.env or args.no_env or args.env_dir:
|
if args.env or args.no_env or args.env_dir:
|
||||||
tty.die("Calling spack env activate with --env, --env-dir and --no-env is ambiguous")
|
tty.die("Calling spack env activate with --env, --env-dir and --no-env is ambiguous")
|
||||||
|
|
||||||
env_name_or_dir = args.activate_env or args.dir
|
# special parser error handling relative to the --temp flag
|
||||||
|
temp_conflicts = iter([args.keep_relative, args.dir, args.env_name, args.with_view])
|
||||||
|
if args.temp and any(temp_conflicts):
|
||||||
|
tty.die(
|
||||||
|
"spack env activate --temp cannot be combined with managed environments, --with-view,"
|
||||||
|
" --keep-relative, or --dir."
|
||||||
|
)
|
||||||
|
|
||||||
# When executing `spack env activate` without further arguments, activate
|
# When executing `spack env activate` without further arguments, activate
|
||||||
# the default environment. It's created when it doesn't exist yet.
|
# the default environment. It's created when it doesn't exist yet.
|
||||||
if not env_name_or_dir and not args.temp:
|
if not args.env_name and not args.temp:
|
||||||
short_name = "default"
|
short_name = "default"
|
||||||
if not ev.exists(short_name):
|
if not ev.exists(short_name):
|
||||||
ev.create(short_name)
|
ev.create(short_name)
|
||||||
@ -185,17 +313,25 @@ def env_activate(args):
|
|||||||
_tty_info(f"Created and activated temporary environment in {env_path}")
|
_tty_info(f"Created and activated temporary environment in {env_path}")
|
||||||
|
|
||||||
# Managed environment
|
# Managed environment
|
||||||
elif ev.exists(env_name_or_dir) and not args.dir:
|
elif ev.exists(args.env_name) and not args.dir:
|
||||||
env_path = ev.root(env_name_or_dir)
|
env_path = ev.root(args.env_name)
|
||||||
short_name = env_name_or_dir
|
short_name = args.env_name
|
||||||
|
|
||||||
# Environment directory
|
# Environment directory
|
||||||
elif ev.is_env_dir(env_name_or_dir):
|
elif ev.is_env_dir(args.env_name):
|
||||||
env_path = os.path.abspath(env_name_or_dir)
|
env_path = os.path.abspath(args.env_name)
|
||||||
short_name = os.path.basename(env_path)
|
short_name = os.path.basename(env_path)
|
||||||
|
|
||||||
|
# create if user requested, and then recall recursively
|
||||||
|
elif args.create:
|
||||||
|
tty.set_msg_enabled(False)
|
||||||
|
env_create(args)
|
||||||
|
tty.set_msg_enabled(True)
|
||||||
|
env_activate(args)
|
||||||
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
tty.die("No such environment: '%s'" % env_name_or_dir)
|
tty.die("No such environment: '%s'" % args.env_name)
|
||||||
|
|
||||||
env_prompt = "[%s]" % short_name
|
env_prompt = "[%s]" % short_name
|
||||||
|
|
||||||
@ -290,97 +426,6 @@ def env_deactivate(args):
|
|||||||
sys.stdout.write(cmds)
|
sys.stdout.write(cmds)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# env create
|
|
||||||
#
|
|
||||||
def env_create_setup_parser(subparser):
|
|
||||||
"""create a new environment"""
|
|
||||||
subparser.add_argument("create_env", metavar="env", help="name of environment to create")
|
|
||||||
subparser.add_argument(
|
|
||||||
"-d", "--dir", action="store_true", help="create an environment in a specific directory"
|
|
||||||
)
|
|
||||||
subparser.add_argument(
|
|
||||||
"--keep-relative",
|
|
||||||
action="store_true",
|
|
||||||
help="copy relative develop paths verbatim into the new environment"
|
|
||||||
" when initializing from envfile",
|
|
||||||
)
|
|
||||||
view_opts = subparser.add_mutually_exclusive_group()
|
|
||||||
view_opts.add_argument(
|
|
||||||
"--without-view", action="store_true", help="do not maintain a view for this environment"
|
|
||||||
)
|
|
||||||
view_opts.add_argument(
|
|
||||||
"--with-view",
|
|
||||||
help="specify that this environment should maintain a view at the"
|
|
||||||
" specified path (by default the view is maintained in the"
|
|
||||||
" environment directory)",
|
|
||||||
)
|
|
||||||
subparser.add_argument(
|
|
||||||
"envfile",
|
|
||||||
nargs="?",
|
|
||||||
default=None,
|
|
||||||
help="either a lockfile (must end with '.json' or '.lock') or a manifest file",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def env_create(args):
|
|
||||||
if args.with_view:
|
|
||||||
# Expand relative paths provided on the command line to the current working directory
|
|
||||||
# This way we interpret `spack env create --with-view ./view --dir ./env` as
|
|
||||||
# a view in $PWD/view, not $PWD/env/view. This is different from specifying a relative
|
|
||||||
# path in the manifest, which is resolved relative to the manifest file's location.
|
|
||||||
with_view = os.path.abspath(args.with_view)
|
|
||||||
elif args.without_view:
|
|
||||||
with_view = False
|
|
||||||
else:
|
|
||||||
# Note that 'None' means unspecified, in which case the Environment
|
|
||||||
# object could choose to enable a view by default. False means that
|
|
||||||
# the environment should not include a view.
|
|
||||||
with_view = None
|
|
||||||
|
|
||||||
env = _env_create(
|
|
||||||
args.create_env,
|
|
||||||
init_file=args.envfile,
|
|
||||||
dir=args.dir,
|
|
||||||
with_view=with_view,
|
|
||||||
keep_relative=args.keep_relative,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate views, only really useful for environments created from spack.lock files.
|
|
||||||
env.regenerate_views()
|
|
||||||
|
|
||||||
|
|
||||||
def _env_create(name_or_path, *, init_file=None, dir=False, with_view=None, keep_relative=False):
|
|
||||||
"""Create a new environment, with an optional yaml description.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
name_or_path (str): name of the environment to create, or path to it
|
|
||||||
init_file (str or file): optional initialization file -- can be
|
|
||||||
a JSON lockfile (*.lock, *.json) or YAML manifest file
|
|
||||||
dir (bool): if True, create an environment in a directory instead
|
|
||||||
of a named environment
|
|
||||||
keep_relative (bool): if True, develop paths are copied verbatim into
|
|
||||||
the new environment file, otherwise they may be made absolute if the
|
|
||||||
new environment is in a different location
|
|
||||||
"""
|
|
||||||
if not dir:
|
|
||||||
env = ev.create(
|
|
||||||
name_or_path, init_file=init_file, with_view=with_view, keep_relative=keep_relative
|
|
||||||
)
|
|
||||||
tty.msg("Created environment '%s' in %s" % (name_or_path, env.path))
|
|
||||||
tty.msg("You can activate this environment with:")
|
|
||||||
tty.msg(" spack env activate %s" % (name_or_path))
|
|
||||||
return env
|
|
||||||
|
|
||||||
env = ev.create_in_dir(
|
|
||||||
name_or_path, init_file=init_file, with_view=with_view, keep_relative=keep_relative
|
|
||||||
)
|
|
||||||
tty.msg("Created environment in %s" % env.path)
|
|
||||||
tty.msg("You can activate this environment with:")
|
|
||||||
tty.msg(" spack env activate %s" % env.path)
|
|
||||||
return env
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# env remove
|
# env remove
|
||||||
#
|
#
|
||||||
|
@ -2956,7 +2956,9 @@ def test_query_develop_specs(tmpdir):
|
|||||||
)
|
)
|
||||||
def test_activation_and_deactiviation_ambiguities(method, env, no_env, env_dir, capsys):
|
def test_activation_and_deactiviation_ambiguities(method, env, no_env, env_dir, capsys):
|
||||||
"""spack [-e x | -E | -D x/] env [activate | deactivate] y are ambiguous"""
|
"""spack [-e x | -E | -D x/] env [activate | deactivate] y are ambiguous"""
|
||||||
args = Namespace(shell="sh", activate_env="a", env=env, no_env=no_env, env_dir=env_dir)
|
args = Namespace(
|
||||||
|
shell="sh", env_name="a", env=env, no_env=no_env, env_dir=env_dir, keep_relative=False
|
||||||
|
)
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
method(args)
|
method(args)
|
||||||
_, err = capsys.readouterr()
|
_, err = capsys.readouterr()
|
||||||
@ -2997,6 +2999,34 @@ def test_activate_temp(monkeypatch, tmpdir):
|
|||||||
assert ev.is_env_dir(str(tmpdir))
|
assert ev.is_env_dir(str(tmpdir))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"conflict_arg", [["--dir"], ["--keep-relative"], ["--with-view", "foo"], ["env"]]
|
||||||
|
)
|
||||||
|
def test_activate_parser_conflicts_with_temp(conflict_arg):
|
||||||
|
with pytest.raises(SpackCommandError):
|
||||||
|
env("activate", "--sh", "--temp", *conflict_arg)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_and_activate_managed(tmp_path):
|
||||||
|
with fs.working_dir(str(tmp_path)):
|
||||||
|
shell = env("activate", "--without-view", "--create", "--sh", "foo")
|
||||||
|
active_env_var = next(line for line in shell.splitlines() if ev.spack_env_var in line)
|
||||||
|
assert str(tmp_path) in active_env_var
|
||||||
|
active_ev = ev.active_environment()
|
||||||
|
assert "foo" == active_ev.name
|
||||||
|
env("deactivate")
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_and_activate_unmanaged(tmp_path):
|
||||||
|
with fs.working_dir(str(tmp_path)):
|
||||||
|
env_dir = os.path.join(str(tmp_path), "foo")
|
||||||
|
shell = env("activate", "--without-view", "--create", "--sh", "-d", env_dir)
|
||||||
|
active_env_var = next(line for line in shell.splitlines() if ev.spack_env_var in line)
|
||||||
|
assert str(env_dir) in active_env_var
|
||||||
|
assert ev.is_env_dir(env_dir)
|
||||||
|
env("deactivate")
|
||||||
|
|
||||||
|
|
||||||
def test_activate_default(monkeypatch):
|
def test_activate_default(monkeypatch):
|
||||||
"""Tests whether `spack env activate` creates / activates the default
|
"""Tests whether `spack env activate` creates / activates the default
|
||||||
environment"""
|
environment"""
|
||||||
|
@ -1030,7 +1030,7 @@ _spack_env() {
|
|||||||
_spack_env_activate() {
|
_spack_env_activate() {
|
||||||
if $list_options
|
if $list_options
|
||||||
then
|
then
|
||||||
SPACK_COMPREPLY="-h --help --sh --csh --fish --bat --pwsh --with-view -v --without-view -V -p --prompt --temp -d --dir"
|
SPACK_COMPREPLY="-h --help --sh --csh --fish --bat --pwsh --with-view -v --without-view -V -p --prompt --temp --create --envfile --keep-relative -d --dir"
|
||||||
else
|
else
|
||||||
_environments
|
_environments
|
||||||
fi
|
fi
|
||||||
|
@ -1467,7 +1467,7 @@ complete -c spack -n '__fish_spack_using_command env' -s h -l help -f -a help
|
|||||||
complete -c spack -n '__fish_spack_using_command env' -s h -l help -d 'show this help message and exit'
|
complete -c spack -n '__fish_spack_using_command env' -s h -l help -d 'show this help message and exit'
|
||||||
|
|
||||||
# spack env activate
|
# spack env activate
|
||||||
set -g __fish_spack_optspecs_spack_env_activate h/help sh csh fish bat pwsh v/with-view= V/without-view p/prompt temp d/dir=
|
set -g __fish_spack_optspecs_spack_env_activate h/help sh csh fish bat pwsh v/with-view= V/without-view p/prompt temp create envfile= keep-relative d/dir
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env activate' -f -a '(__fish_spack_environments)'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env activate' -f -a '(__fish_spack_environments)'
|
||||||
complete -c spack -n '__fish_spack_using_command env activate' -s h -l help -f -a help
|
complete -c spack -n '__fish_spack_using_command env activate' -s h -l help -f -a help
|
||||||
complete -c spack -n '__fish_spack_using_command env activate' -s h -l help -d 'show this help message and exit'
|
complete -c spack -n '__fish_spack_using_command env activate' -s h -l help -d 'show this help message and exit'
|
||||||
@ -1489,8 +1489,14 @@ complete -c spack -n '__fish_spack_using_command env activate' -s p -l prompt -f
|
|||||||
complete -c spack -n '__fish_spack_using_command env activate' -s p -l prompt -d 'decorate the command line prompt when activating'
|
complete -c spack -n '__fish_spack_using_command env activate' -s p -l prompt -d 'decorate the command line prompt when activating'
|
||||||
complete -c spack -n '__fish_spack_using_command env activate' -l temp -f -a temp
|
complete -c spack -n '__fish_spack_using_command env activate' -l temp -f -a temp
|
||||||
complete -c spack -n '__fish_spack_using_command env activate' -l temp -d 'create and activate an environment in a temporary directory'
|
complete -c spack -n '__fish_spack_using_command env activate' -l temp -d 'create and activate an environment in a temporary directory'
|
||||||
complete -c spack -n '__fish_spack_using_command env activate' -s d -l dir -r -f -a dir
|
complete -c spack -n '__fish_spack_using_command env activate' -l create -f -a create
|
||||||
complete -c spack -n '__fish_spack_using_command env activate' -s d -l dir -r -d 'activate the environment in this directory'
|
complete -c spack -n '__fish_spack_using_command env activate' -l create -d 'create and activate the environment if it doesn\'t exist'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env activate' -l envfile -r -f -a envfile
|
||||||
|
complete -c spack -n '__fish_spack_using_command env activate' -l envfile -r -d 'either a lockfile (must end with \'.json\' or \'.lock\') or a manifest file'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env activate' -l keep-relative -f -a keep_relative
|
||||||
|
complete -c spack -n '__fish_spack_using_command env activate' -l keep-relative -d 'copy relative develop paths verbatim into the new environment when initializing from envfile'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env activate' -s d -l dir -f -a dir
|
||||||
|
complete -c spack -n '__fish_spack_using_command env activate' -s d -l dir -d 'activate environment based on the directory supplied'
|
||||||
|
|
||||||
# spack env deactivate
|
# spack env deactivate
|
||||||
set -g __fish_spack_optspecs_spack_env_deactivate h/help sh csh fish bat pwsh
|
set -g __fish_spack_optspecs_spack_env_deactivate h/help sh csh fish bat pwsh
|
||||||
|
Loading…
Reference in New Issue
Block a user