summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Knoepfel <knoepfel@fnal.gov>2024-03-28 16:15:04 -0500
committerGitHub <noreply@github.com>2024-03-28 15:15:04 -0600
commit5f9228746e8a203f1fee2bcb0c2188c66c9189dc (patch)
tree411e50c376255e0f7f68c91d0ebc6b5ea2c31f59
parent9f2451ddff345bc938a9cf90ec7bbdd3f25b36b6 (diff)
downloadspack-5f9228746e8a203f1fee2bcb0c2188c66c9189dc.tar.gz
spack-5f9228746e8a203f1fee2bcb0c2188c66c9189dc.tar.bz2
spack-5f9228746e8a203f1fee2bcb0c2188c66c9189dc.tar.xz
spack-5f9228746e8a203f1fee2bcb0c2188c66c9189dc.zip
Add ability to rename environments (#43296)
-rw-r--r--lib/spack/spack/cmd/env.py75
-rw-r--r--lib/spack/spack/test/cmd/env.py123
-rwxr-xr-xshare/spack/spack-completion.bash20
-rwxr-xr-xshare/spack/spack-completion.fish26
4 files changed, 239 insertions, 5 deletions
diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py
index ee9d556b67..d308b89a6c 100644
--- a/lib/spack/spack/cmd/env.py
+++ b/lib/spack/spack/cmd/env.py
@@ -9,6 +9,7 @@ import shlex
import shutil
import sys
import tempfile
+from pathlib import Path
from typing import Optional
import llnl.string as string
@@ -44,6 +45,7 @@ subcommands = [
"deactivate",
"create",
["remove", "rm"],
+ ["rename", "mv"],
["list", "ls"],
["status", "st"],
"loads",
@@ -473,10 +475,81 @@ def env_remove(args):
#
+# 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
#
def env_list_setup_parser(subparser):
- """list available environments"""
+ """list managed environments"""
def env_list(args):
diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py
index aafca18544..0cf09421c0 100644
--- a/lib/spack/spack/test/cmd/env.py
+++ b/lib/spack/spack/test/cmd/env.py
@@ -188,6 +188,127 @@ def test_env_remove(capfd):
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():
e = ev.create("test")
e.add("mpileaks")
@@ -3133,7 +3254,7 @@ def test_create_and_activate_managed(tmp_path):
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)):
env_dir = os.path.join(str(tmp_path), "foo")
shell = env("activate", "--without-view", "--create", "--sh", "-d", env_dir)
diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash
index dc0d1987a6..e76f757f19 100755
--- a/share/spack/spack-completion.bash
+++ b/share/spack/spack-completion.bash
@@ -1032,7 +1032,7 @@ _spack_env() {
then
SPACK_COMPREPLY="-h --help"
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
}
@@ -1076,6 +1076,24 @@ _spack_env_rm() {
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_COMPREPLY="-h --help"
}
diff --git a/share/spack/spack-completion.fish b/share/spack/spack-completion.fish
index ff7c3b3ba1..a8ff367416 100755
--- a/share/spack/spack-completion.fish
+++ b/share/spack/spack-completion.fish
@@ -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 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 list -d 'list available environments'
-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 rename -d 'rename an existing environment'
+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 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)\''
@@ -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 -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
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