Add ability to rename environments (#43296)
This commit is contained in:
parent
9f2451ddff
commit
5f9228746e
4 changed files with 239 additions and 5 deletions
|
@ -9,6 +9,7 @@
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import llnl.string as string
|
import llnl.string as string
|
||||||
|
@ -44,6 +45,7 @@
|
||||||
"deactivate",
|
"deactivate",
|
||||||
"create",
|
"create",
|
||||||
["remove", "rm"],
|
["remove", "rm"],
|
||||||
|
["rename", "mv"],
|
||||||
["list", "ls"],
|
["list", "ls"],
|
||||||
["status", "st"],
|
["status", "st"],
|
||||||
"loads",
|
"loads",
|
||||||
|
@ -472,11 +474,82 @@ def env_remove(args):
|
||||||
tty.msg(f"Successfully removed environment '{bad_env_name}'")
|
tty.msg(f"Successfully removed environment '{bad_env_name}'")
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# env rename
|
||||||
|
#
|
||||||
|
def env_rename_setup_parser(subparser):
|
||||||
|
"""rename an existing environment"""
|
||||||
|
subparser.add_argument(
|
||||||
|
"mv_from", metavar="from", help="name (or path) of existing environment"
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"mv_to", metavar="to", help="new name (or path) for existing environment"
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--dir",
|
||||||
|
action="store_true",
|
||||||
|
help="the specified arguments correspond to directory paths",
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"-f", "--force", action="store_true", help="allow overwriting of an existing environment"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def env_rename(args):
|
||||||
|
"""Rename an environment.
|
||||||
|
|
||||||
|
This renames a managed environment or moves an anonymous environment.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Directory option has been specified
|
||||||
|
if args.dir:
|
||||||
|
if not ev.is_env_dir(args.mv_from):
|
||||||
|
tty.die("The specified path does not correspond to a valid spack environment")
|
||||||
|
from_path = Path(args.mv_from)
|
||||||
|
if not args.force:
|
||||||
|
if ev.is_env_dir(args.mv_to):
|
||||||
|
tty.die(
|
||||||
|
"The new path corresponds to an existing environment;"
|
||||||
|
" specify the --force flag to overwrite it."
|
||||||
|
)
|
||||||
|
if Path(args.mv_to).exists():
|
||||||
|
tty.die("The new path already exists; specify the --force flag to overwrite it.")
|
||||||
|
to_path = Path(args.mv_to)
|
||||||
|
|
||||||
|
# Name option being used
|
||||||
|
elif ev.exists(args.mv_from):
|
||||||
|
from_path = ev.environment.environment_dir_from_name(args.mv_from)
|
||||||
|
if not args.force and ev.exists(args.mv_to):
|
||||||
|
tty.die(
|
||||||
|
"The new name corresponds to an existing environment;"
|
||||||
|
" specify the --force flag to overwrite it."
|
||||||
|
)
|
||||||
|
to_path = ev.environment.root(args.mv_to)
|
||||||
|
|
||||||
|
# Neither
|
||||||
|
else:
|
||||||
|
tty.die("The specified name does not correspond to a managed spack environment")
|
||||||
|
|
||||||
|
# Guard against renaming from or to an active environment
|
||||||
|
active_env = ev.active_environment()
|
||||||
|
if active_env:
|
||||||
|
from_env = ev.Environment(from_path)
|
||||||
|
if from_env.path == active_env.path:
|
||||||
|
tty.die("Cannot rename active environment")
|
||||||
|
if to_path == active_env.path:
|
||||||
|
tty.die(f"{args.mv_to} is an active environment")
|
||||||
|
|
||||||
|
shutil.rmtree(to_path, ignore_errors=True)
|
||||||
|
fs.rename(from_path, to_path)
|
||||||
|
tty.msg(f"Successfully renamed environment {args.mv_from} to {args.mv_to}")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# env list
|
# env list
|
||||||
#
|
#
|
||||||
def env_list_setup_parser(subparser):
|
def env_list_setup_parser(subparser):
|
||||||
"""list available environments"""
|
"""list managed environments"""
|
||||||
|
|
||||||
|
|
||||||
def env_list(args):
|
def env_list(args):
|
||||||
|
|
|
@ -188,6 +188,127 @@ def test_env_remove(capfd):
|
||||||
assert "bar" not in out
|
assert "bar" not in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_rename_managed(capfd):
|
||||||
|
# Need real environment
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "foo", "bar")
|
||||||
|
assert (
|
||||||
|
"The specified name does not correspond to a managed spack environment"
|
||||||
|
in capfd.readouterr()[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
env("create", "foo")
|
||||||
|
|
||||||
|
out = env("list")
|
||||||
|
assert "foo" in out
|
||||||
|
|
||||||
|
out = env("rename", "foo", "bar")
|
||||||
|
assert "Successfully renamed environment foo to bar" in out
|
||||||
|
|
||||||
|
out = env("list")
|
||||||
|
assert "foo" not in out
|
||||||
|
assert "bar" in out
|
||||||
|
|
||||||
|
bar = ev.read("bar")
|
||||||
|
with bar:
|
||||||
|
# Cannot rename active environment
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "bar", "baz")
|
||||||
|
assert "Cannot rename active environment" in capfd.readouterr()[0]
|
||||||
|
|
||||||
|
env("create", "qux")
|
||||||
|
|
||||||
|
# Cannot rename to an active environment (even with force flag)
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "-f", "qux", "bar")
|
||||||
|
assert "bar is an active environment" in capfd.readouterr()[0]
|
||||||
|
|
||||||
|
# Can rename inactive environment when another's active
|
||||||
|
out = env("rename", "qux", "quux")
|
||||||
|
assert "Successfully renamed environment qux to quux" in out
|
||||||
|
|
||||||
|
out = env("list")
|
||||||
|
assert "bar" in out
|
||||||
|
assert "baz" not in out
|
||||||
|
|
||||||
|
env("create", "baz")
|
||||||
|
|
||||||
|
# Cannot rename to existing environment without --force
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "bar", "baz")
|
||||||
|
errmsg = (
|
||||||
|
"The new name corresponds to an existing environment;"
|
||||||
|
" specify the --force flag to overwrite it."
|
||||||
|
)
|
||||||
|
assert errmsg in capfd.readouterr()[0]
|
||||||
|
|
||||||
|
env("rename", "-f", "bar", "baz")
|
||||||
|
out = env("list")
|
||||||
|
assert "bar" not in out
|
||||||
|
assert "baz" in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_rename_anonymous(capfd, tmpdir):
|
||||||
|
# Need real environment
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "-d", "./non-existing", "./also-non-existing")
|
||||||
|
assert (
|
||||||
|
"The specified path does not correspond to a valid spack environment"
|
||||||
|
in capfd.readouterr()[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
anon_foo = str(tmpdir / "foo")
|
||||||
|
env("create", "-d", anon_foo)
|
||||||
|
|
||||||
|
anon_bar = str(tmpdir / "bar")
|
||||||
|
out = env("rename", "-d", anon_foo, anon_bar)
|
||||||
|
assert f"Successfully renamed environment {anon_foo} to {anon_bar}" in out
|
||||||
|
assert not ev.is_env_dir(anon_foo)
|
||||||
|
assert ev.is_env_dir(anon_bar)
|
||||||
|
|
||||||
|
# Cannot rename active environment
|
||||||
|
anon_baz = str(tmpdir / "baz")
|
||||||
|
env("activate", "--sh", "-d", anon_bar)
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "-d", anon_bar, anon_baz)
|
||||||
|
assert "Cannot rename active environment" in capfd.readouterr()[0]
|
||||||
|
env("deactivate", "--sh")
|
||||||
|
|
||||||
|
assert ev.is_env_dir(anon_bar)
|
||||||
|
assert not ev.is_env_dir(anon_baz)
|
||||||
|
|
||||||
|
# Cannot rename to existing environment without --force
|
||||||
|
env("create", "-d", anon_baz)
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "-d", anon_bar, anon_baz)
|
||||||
|
errmsg = (
|
||||||
|
"The new path corresponds to an existing environment;"
|
||||||
|
" specify the --force flag to overwrite it."
|
||||||
|
)
|
||||||
|
assert errmsg in capfd.readouterr()[0]
|
||||||
|
assert ev.is_env_dir(anon_bar)
|
||||||
|
assert ev.is_env_dir(anon_baz)
|
||||||
|
|
||||||
|
env("rename", "-f", "-d", anon_bar, anon_baz)
|
||||||
|
assert not ev.is_env_dir(anon_bar)
|
||||||
|
assert ev.is_env_dir(anon_baz)
|
||||||
|
|
||||||
|
# Cannot rename to existing (non-environment) path without --force
|
||||||
|
qux = tmpdir / "qux"
|
||||||
|
qux.mkdir()
|
||||||
|
anon_qux = str(qux)
|
||||||
|
assert not ev.is_env_dir(anon_qux)
|
||||||
|
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
env("rename", "-d", anon_baz, anon_qux)
|
||||||
|
errmsg = "The new path already exists; specify the --force flag to overwrite it."
|
||||||
|
assert errmsg in capfd.readouterr()[0]
|
||||||
|
|
||||||
|
env("rename", "-f", "-d", anon_baz, anon_qux)
|
||||||
|
assert not ev.is_env_dir(anon_baz)
|
||||||
|
assert ev.is_env_dir(anon_qux)
|
||||||
|
|
||||||
|
|
||||||
def test_concretize():
|
def test_concretize():
|
||||||
e = ev.create("test")
|
e = ev.create("test")
|
||||||
e.add("mpileaks")
|
e.add("mpileaks")
|
||||||
|
@ -3133,7 +3254,7 @@ def test_create_and_activate_managed(tmp_path):
|
||||||
env("deactivate")
|
env("deactivate")
|
||||||
|
|
||||||
|
|
||||||
def test_create_and_activate_unmanaged(tmp_path):
|
def test_create_and_activate_anonymous(tmp_path):
|
||||||
with fs.working_dir(str(tmp_path)):
|
with fs.working_dir(str(tmp_path)):
|
||||||
env_dir = os.path.join(str(tmp_path), "foo")
|
env_dir = os.path.join(str(tmp_path), "foo")
|
||||||
shell = env("activate", "--without-view", "--create", "--sh", "-d", env_dir)
|
shell = env("activate", "--without-view", "--create", "--sh", "-d", env_dir)
|
||||||
|
|
|
@ -1032,7 +1032,7 @@ _spack_env() {
|
||||||
then
|
then
|
||||||
SPACK_COMPREPLY="-h --help"
|
SPACK_COMPREPLY="-h --help"
|
||||||
else
|
else
|
||||||
SPACK_COMPREPLY="activate deactivate create remove rm list ls status st loads view update revert depfile"
|
SPACK_COMPREPLY="activate deactivate create remove rm rename mv list ls status st loads view update revert depfile"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,6 +1076,24 @@ _spack_env_rm() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_spack_env_rename() {
|
||||||
|
if $list_options
|
||||||
|
then
|
||||||
|
SPACK_COMPREPLY="-h --help -d --dir -f --force"
|
||||||
|
else
|
||||||
|
SPACK_COMPREPLY=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_spack_env_mv() {
|
||||||
|
if $list_options
|
||||||
|
then
|
||||||
|
SPACK_COMPREPLY="-h --help -d --dir -f --force"
|
||||||
|
else
|
||||||
|
SPACK_COMPREPLY=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
_spack_env_list() {
|
_spack_env_list() {
|
||||||
SPACK_COMPREPLY="-h --help"
|
SPACK_COMPREPLY="-h --help"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1472,8 +1472,10 @@ complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a deactivate -d
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a create -d 'create a new environment'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a create -d 'create a new environment'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a remove -d 'remove an existing environment'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a remove -d 'remove an existing environment'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a rm -d 'remove an existing environment'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a rm -d 'remove an existing environment'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a list -d 'list available environments'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a rename -d 'rename an existing environment'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a ls -d 'list available environments'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a mv -d 'rename an existing environment'
|
||||||
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a list -d 'list managed environments'
|
||||||
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a ls -d 'list managed environments'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a status -d 'print whether there is an active environment'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a status -d 'print whether there is an active environment'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a st -d 'print whether there is an active environment'
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a st -d 'print whether there is an active environment'
|
||||||
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a loads -d 'list modules for an installed environment \'(see spack module loads)\''
|
complete -c spack -n '__fish_spack_using_command_pos 0 env' -f -a loads -d 'list modules for an installed environment \'(see spack module loads)\''
|
||||||
|
@ -1561,6 +1563,26 @@ complete -c spack -n '__fish_spack_using_command env rm' -s h -l help -d 'show t
|
||||||
complete -c spack -n '__fish_spack_using_command env rm' -s y -l yes-to-all -f -a yes_to_all
|
complete -c spack -n '__fish_spack_using_command env rm' -s y -l yes-to-all -f -a yes_to_all
|
||||||
complete -c spack -n '__fish_spack_using_command env rm' -s y -l yes-to-all -d 'assume "yes" is the answer to every confirmation request'
|
complete -c spack -n '__fish_spack_using_command env rm' -s y -l yes-to-all -d 'assume "yes" is the answer to every confirmation request'
|
||||||
|
|
||||||
|
# spack env rename
|
||||||
|
set -g __fish_spack_optspecs_spack_env_rename h/help d/dir f/force
|
||||||
|
|
||||||
|
complete -c spack -n '__fish_spack_using_command env rename' -s h -l help -f -a help
|
||||||
|
complete -c spack -n '__fish_spack_using_command env rename' -s h -l help -d 'show this help message and exit'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env rename' -s d -l dir -f -a dir
|
||||||
|
complete -c spack -n '__fish_spack_using_command env rename' -s d -l dir -d 'the specified arguments correspond to directory paths'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env rename' -s f -l force -f -a force
|
||||||
|
complete -c spack -n '__fish_spack_using_command env rename' -s f -l force -d 'allow overwriting of an existing environment'
|
||||||
|
|
||||||
|
# spack env mv
|
||||||
|
set -g __fish_spack_optspecs_spack_env_mv h/help d/dir f/force
|
||||||
|
|
||||||
|
complete -c spack -n '__fish_spack_using_command env mv' -s h -l help -f -a help
|
||||||
|
complete -c spack -n '__fish_spack_using_command env mv' -s h -l help -d 'show this help message and exit'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env mv' -s d -l dir -f -a dir
|
||||||
|
complete -c spack -n '__fish_spack_using_command env mv' -s d -l dir -d 'the specified arguments correspond to directory paths'
|
||||||
|
complete -c spack -n '__fish_spack_using_command env mv' -s f -l force -f -a force
|
||||||
|
complete -c spack -n '__fish_spack_using_command env mv' -s f -l force -d 'allow overwriting of an existing environment'
|
||||||
|
|
||||||
# spack env list
|
# spack env list
|
||||||
set -g __fish_spack_optspecs_spack_env_list h/help
|
set -g __fish_spack_optspecs_spack_env_list h/help
|
||||||
complete -c spack -n '__fish_spack_using_command env list' -s h -l help -f -a help
|
complete -c spack -n '__fish_spack_using_command env list' -s h -l help -f -a help
|
||||||
|
|
Loading…
Reference in a new issue