fix: Create directories from `envs_dirs` if they do not exist (#3796)

Signed-off-by: Burt Holzman <burt@fnal.gov>
Co-authored-by: Julien Jerphanion <git@jjerphan.xyz>
This commit is contained in:
Burt Holzman 2025-02-28 05:56:06 -06:00 committed by GitHub
parent 437602625e
commit d9af139d11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 99 additions and 10 deletions

View File

@ -490,6 +490,16 @@ namespace mamba
{
for (const auto& dir : dirs)
{
try
{
fs::create_directories(dir);
}
catch (const fs::filesystem_error& e)
{
LOG_WARNING << "Error creating directory " << dir << ": " << e.what()
<< std::endl;
}
const auto candidate = dir / name;
if (mamba::path::is_writable(candidate))
{

View File

@ -284,8 +284,6 @@ def test_target_prefix(
else:
root_prefix = Path(os.environ["MAMBA_ROOT_PREFIX"])
# TODO: Remove this call to `os.makedirs` once
# https://github.com/mamba-org/mamba/issues/3790 is fixed
if root_prefix_env_exists:
os.makedirs(Path(os.environ["MAMBA_ROOT_PREFIX"]) / "envs", exist_ok=True)
@ -665,14 +663,100 @@ def test_create_empty(tmp_home, tmp_root_prefix, tmp_path, prefix_selector, crea
assert (effective_prefix / "conda-meta" / "history").exists()
def test_create_envs_dirs(tmp_root_prefix: Path, tmp_path: Path):
def test_create_envs_dirs(tmp_root_prefix: Path, tmp_path: Path, monkeypatch):
"""Create an environment when the first env dir is not writable."""
os.environ["CONDA_ENVS_DIRS"] = f"{Path('/noperm')},{tmp_path}"
noperm_root_dir = Path(tmp_path / "noperm")
noperm_envs_dir = noperm_root_dir / "envs"
monkeypatch.setenv("CONDA_ENVS_DIRS", f"{noperm_envs_dir},{tmp_path}")
env_name = "myenv"
helpers.create("-n", env_name, "--offline", "--no-rc", no_dry_run=True)
os.makedirs(noperm_root_dir, exist_ok=True)
if platform.system() == "Windows":
# Make first env_dir read-only on Windows - this requires:
# Removing inherited and granted permissions, removing ownership,
# and granting group Everyone RX access.
subprocess.run(
[
"icacls",
noperm_root_dir,
"/inheritance:r", # remove inherited permissions
"/grant:r", # remove explicitly granted permissions
"Everyone:(RX)", # grant Read-Execute to everyone
"/remove", # remove ownership from all groups
r"BUILTIN\Administrators",
"/remove",
r"NT AUTHORITY\SYSTEM",
"/remove",
"OWNER RIGHTS",
],
check=True,
)
else:
# Make first env_dir read-only on Linux
os.chmod(noperm_root_dir, 0o555)
try:
helpers.create("-n", env_name, "--offline", "--no-rc", no_dry_run=True)
finally:
if platform.system() == "Windows":
# Revert ownership change on Windows so that we can clean up
subprocess.run(
["icacls", noperm_root_dir, "/grant", r"BUILTIN\Administrators:F"], check=True
)
subprocess.run(["icacls", noperm_root_dir, "/reset"], check=True)
else:
# Revert permission change on Linux so that we can clean up
os.chmod(noperm_root_dir, 0o755)
assert (tmp_path / env_name / "conda-meta" / "history").exists()
@pytest.mark.parametrize("envs_dirs_source", ("condarc", "env_var"))
def test_mkdir_envs_dirs(tmp_path, tmp_home, monkeypatch, envs_dirs_source):
"""Test that an env dir is created if it does not exist already"""
envs_dir = tmp_path / "user_provided_envdir" / "envs"
with open(tmp_home / ".condarc", "w+") as f:
if envs_dirs_source == "env_var":
monkeypatch.setenv("CONDA_ENVS_DIRS", str(envs_dir))
else:
f.write(f"envs_dirs: [{str(envs_dir)}]")
assert not envs_dir.exists() # directory doesn't exist yet
helpers.create("-n", "bar", "--rc-file", tmp_home / ".condarc", no_rc=False)
assert envs_dir.exists()
def test_env_dir_idempotence(tmp_path, tmp_home, tmp_root_prefix):
"""
Test that setting envs_dirs to ~/.conda and running twice in a row
gives the same results
https://github.com/mamba-org/mamba/issues/3836
"""
mamba_root_prefix_envs = tmp_root_prefix / "envs"
condarc_envs_dirs = tmp_home / ".conda"
with open(tmp_home / ".condarc", "w+") as f:
f.write(f"envs_dirs: [{str(condarc_envs_dirs)}]")
env_name = "foo"
for _ in range(2):
cmd = ["-n", env_name, "--rc-file", tmp_home / ".condarc"]
helpers.create(*cmd, no_rc=False)
assert not Path(mamba_root_prefix_envs / env_name).exists()
assert Path(condarc_envs_dirs / env_name).exists()
@pytest.mark.parametrize("set_in_conda_envs_dirs", (False, True))
@pytest.mark.parametrize("set_in_condarc", (False, True))
@pytest.mark.parametrize("cli_root_prefix", (False, True))
@ -716,11 +800,6 @@ def test_root_prefix_precedence(
if set_in_condarc:
f.write(f"envs_dirs: [{str(condarc_envs_dirs)}]")
# TODO: Remove this call to `os.makedirs` once
# https://github.com/mamba-org/mamba/issues/3790 is fixed
for envs_folder in (condarc_envs_dirs, conda_envs_dirs, cli_provided_root, mamba_root_prefix):
os.makedirs(envs_folder, exist_ok=True)
cmd = ["-n", env_name, "--rc-file", tmp_home / ".condarc"]
if check_config_only: