spack env create <env>: dir if dir-like (#44024)

A named env cannot contain `.` and `/`.

So when a user runs `spack env create ./here` do not error but treat it
as `spack env create -d ./here`.

Also fix help string of `spack env create`, which seems to have been
copied from `activate` incorrectly.
This commit is contained in:
Harmen Stoppels 2024-05-06 10:00:23 +02:00 committed by GitHub
parent b471d62dbd
commit 715214c1a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 44 deletions

View file

@ -142,12 +142,8 @@ 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 The ``activate`` command can also be used to create a new environment if it does not already
not already defined, by adding the ``--create`` flag. Managed and anonymous exist.
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 .. code-block:: console
@ -176,21 +172,36 @@ environment will remove the view from the user environment.
Anonymous Environments Anonymous Environments
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
Any directory can be treated as an environment if it contains a file Apart from managed environments, Spack also supports anonymous environments.
``spack.yaml``. To load an anonymous environment, use:
Anonymous environments can be placed in any directory of choice.
.. note::
When uninstalling packages, Spack asks the user to confirm the removal of packages
that are still used in a managed environment. This is not the case for anonymous
environments.
To create an anonymous environment, use one of the following commands:
.. code-block:: console .. code-block:: console
$ spack env activate -d /path/to/directory $ spack env create --dir my_env
$ spack env create ./my_env
Anonymous specs can be created in place using the command: As a shorthand, you can also create an anonymous environment upon activation if it does not
already exist:
.. code-block:: console .. code-block:: console
$ spack env create -d . $ spack env activate --create ./my_env
For convenience, Spack can also place an anonymous environment in a temporary directory for you:
.. code-block:: console
$ spack env activate --temp
In this case Spack simply creates a ``spack.yaml`` file in the requested
directory.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Environment Sensitive Commands Environment Sensitive Commands

View file

@ -16,7 +16,7 @@
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.tty.colify import colify from llnl.util.tty.colify import colify
from llnl.util.tty.color import colorize from llnl.util.tty.color import cescape, colorize
import spack.cmd import spack.cmd
import spack.cmd.common import spack.cmd.common
@ -61,14 +61,7 @@
# #
def env_create_setup_parser(subparser): def env_create_setup_parser(subparser):
"""create a new environment""" """create a new environment"""
subparser.add_argument( subparser.add_argument("env_name", metavar="env", help="name or directory of environment")
"env_name",
metavar="env",
help=(
"name of managed environment or directory of the anonymous env "
"(when using --dir/-d) to activate"
),
)
subparser.add_argument( subparser.add_argument(
"-d", "--dir", action="store_true", help="create an environment in a specific directory" "-d", "--dir", action="store_true", help="create an environment in a specific directory"
) )
@ -114,7 +107,7 @@ def env_create(args):
env = _env_create( env = _env_create(
args.env_name, args.env_name,
init_file=args.envfile, init_file=args.envfile,
dir=args.dir, dir=args.dir or os.path.sep in args.env_name or args.env_name in (".", ".."),
with_view=with_view, with_view=with_view,
keep_relative=args.keep_relative, keep_relative=args.keep_relative,
) )
@ -123,34 +116,39 @@ def env_create(args):
env.regenerate_views() env.regenerate_views()
def _env_create(name_or_path, *, init_file=None, dir=False, with_view=None, keep_relative=False): def _env_create(
name_or_path: str,
*,
init_file: Optional[str] = None,
dir: bool = False,
with_view: Optional[str] = None,
keep_relative: bool = False,
):
"""Create a new environment, with an optional yaml description. """Create a new environment, with an optional yaml description.
Arguments: Arguments:
name_or_path (str): name of the environment to create, or path to it name_or_path: name of the environment to create, or path to it
init_file (str or file): optional initialization file -- can be init_file: optional initialization file -- can be a JSON lockfile (*.lock, *.json) or YAML
a JSON lockfile (*.lock, *.json) or YAML manifest file manifest file
dir (bool): if True, create an environment in a directory instead dir: if True, create an environment in a directory instead of a managed environment
of a named environment keep_relative: if True, develop paths are copied verbatim into the new environment file,
keep_relative (bool): if True, develop paths are copied verbatim into otherwise they may be made absolute if the new environment is in a different location
the new environment file, otherwise they may be made absolute if the
new environment is in a different location
""" """
if not dir: if not dir:
env = ev.create( env = ev.create(
name_or_path, init_file=init_file, with_view=with_view, keep_relative=keep_relative 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(
tty.msg("You can activate this environment with:") colorize(
tty.msg(" spack env activate %s" % (name_or_path)) f"Created environment @c{{{cescape(env.name)}}} in: @c{{{cescape(env.path)}}}"
return env )
)
env = ev.create_in_dir( else:
name_or_path, init_file=init_file, with_view=with_view, keep_relative=keep_relative 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(colorize(f"Created anonymous environment in: @c{{{cescape(env.path)}}}"))
tty.msg(" spack env activate %s" % env.path) tty.msg(f"Activate with: {colorize(f'@c{{spack env activate {cescape(name_or_path)}}}')}")
return env return env

View file

@ -3290,7 +3290,7 @@ def test_create_and_activate_managed(tmp_path):
def test_create_and_activate_anonymous(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", env_dir)
active_env_var = next(line for line in shell.splitlines() if ev.spack_env_var in line) 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 str(env_dir) in active_env_var
assert ev.is_env_dir(env_dir) assert ev.is_env_dir(env_dir)