diff --git a/libmamba/data/mamba.xsh b/libmamba/data/mamba.xsh index 31775802f6..cefacab6c0 100644 --- a/libmamba/data/mamba.xsh +++ b/libmamba/data/mamba.xsh @@ -20,7 +20,9 @@ _REACTIVATE_COMMANDS = ('install', 'update', 'upgrade', 'remove', 'uninstall') def _parse_args(args=None): from argparse import ArgumentParser p = ArgumentParser(add_help=False) - p.add_argument('command') + p.add_argument('command', nargs='?') + p.add_argument('-h', '--help', dest='help', action='store_true', default=False) + p.add_argument('-v', '--version', dest='version', action='store_true', default=False) ns, _ = p.parse_known_args(args) if ns.command == 'activate': p.add_argument('env_name_or_prefix', default='base') @@ -44,9 +46,9 @@ def _raise_pipeline_error(pipeline): def _mamba_activate_handler(env_name_or_prefix=None): if env_name_or_prefix == 'base' or not env_name_or_prefix: env_name_or_prefix = $MAMBA_ROOT_PREFIX - __xonsh__.execer.exec($($MAMBA_EXE shell activate -s xonsh -p @(env_name_or_prefix)), + __xonsh__.execer.exec($($MAMBA_EXE shell activate -s xonsh @(env_name_or_prefix)), glbs=__xonsh__.ctx, - filename="$($MAMBA_EXE shell activate -s xonsh -p " + env_name_or_prefix + ")") + filename="$($MAMBA_EXE shell activate -s xonsh " + env_name_or_prefix + ")") def _mamba_deactivate_handler(): @@ -91,6 +93,7 @@ if 'CONDA_SHLVL' not in ${...}: aliases['micromamba'] = _micromamba_main +aliases['mamba'] = _micromamba_main @contextual_command_completer diff --git a/libmamba/src/core/activation.cpp b/libmamba/src/core/activation.cpp index da261b0926..9bd5a324f4 100644 --- a/libmamba/src/core/activation.cpp +++ b/libmamba/src/core/activation.cpp @@ -1123,7 +1123,7 @@ namespace mamba for (const std::string& uvar : env_transform.unset_vars) { - out << "del $" << uvar << "\n"; + out << "try:\n del $" << uvar << "\nexcept KeyError:\n pass\n"; } for (const auto& [skey, svar] : env_transform.set_vars) diff --git a/micromamba/tests/test_activation.py b/micromamba/tests/test_activation.py index acf1b50904..a3593b58d0 100644 --- a/micromamba/tests/test_activation.py +++ b/micromamba/tests/test_activation.py @@ -1,6 +1,7 @@ import os import pathlib import platform +import re import shutil import subprocess import tempfile @@ -933,6 +934,67 @@ def test_activate_envs_dirs( assert any([env_name in p for p in dict_res.values()]) +@pytest.mark.skipif( + "xonsh" not in valid_interpreters, + reason="xonsh not available", +) +@pytest.mark.parametrize("alias", ["micromamba", "mamba"]) +def test_xonsh_help_and_version(tmp_home, tmp_root_prefix, tmp_path, alias): + umamba = helpers.get_umamba() + + s = [f"{umamba} shell init -r {tmp_root_prefix} -s xonsh"] + call_interpreter(s, tmp_path, "xonsh") + + def call(s): + return call_interpreter(s, tmp_path, "xonsh", interactive=True) + + s = [f"{alias} --help"] + stdout, stderr = call(s) + assert not stderr, f"stderr was not empty: {stderr}" + assert "--help" in stdout + assert "Print this help message and exit" in stdout + + s = [f"{alias} --version"] + stdout, stderr = call(s) + assert not stderr, f"stderr was not empty: {stderr}" + assert re.search(r"\d+\.\d+\.\d+", stdout.strip()), f"not a version: {stdout}" + + +@pytest.mark.skipif( + "xonsh" not in valid_interpreters, + reason="xonsh not available", +) +@pytest.mark.parametrize("alias", ["micromamba", "mamba"]) +def test_xonsh_del_nonexistent_env_var(tmp_home, tmp_root_prefix, tmp_path, alias): + umamba = helpers.get_umamba() + + s = [f"{umamba} shell init -r {tmp_root_prefix} -s xonsh"] + call_interpreter(s, tmp_path, "xonsh") + + def call(s): + return call_interpreter(s, tmp_path, "xonsh", interactive=True) + + helpers.create("-n", "test_unset_env", "--offline", "--no-rc", no_dry_run=True) + + prefix = tmp_root_prefix / "envs" / "test_unset_env" + state_file = prefix / "conda-meta" / "state" + state_file.write_text(helpers.json.dumps({"env_vars": {"MAMBA_UNSET_TEST": "hello"}})) + + # activate → manually delete var → deactivate + s = [ + f"{alias} activate test_unset_env", + "del $MAMBA_UNSET_TEST", + f"{alias} deactivate", + ] + + try: + stdout, stderr = call(s) + except subprocess.CalledProcessError: + pytest.fail("deactivate crashed on del of non-existent env var") + + assert "does not contain any filesystem separator" not in stderr + + @pytest.fixture def tmp_umamba(): mamba_exe = helpers.get_umamba()