This commit is contained in:
Burt Holzman 2025-07-30 18:46:23 +02:00 committed by GitHub
commit f1e8b8e20b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 148 additions and 64 deletions

View File

@ -118,14 +118,27 @@ RC files have their own precedence order and use the same resolution process as
{ root_prefix }/condarc
{ root_prefix }/condarc.d
{ root_prefix }/.mambarc
{ $XDG_CONFIG_HOME | ~/.config}/conda/.condarc
{ $XDG_CONFIG_HOME | ~/.config}/conda/condarc
{ $XDG_CONFIG_HOME | ~/.config}/condarc.d
~/.conda/.condarc
~/.conda/condarc
~/.conda/condarc.d
~/.condarc
{ $XDG_CONFIG_HOME | ~/.config}/mamba/.mambarc
{ $XDG_CONFIG_HOME | ~/.config}/mamba/mambarc
{ $XDG_CONFIG_HOME | ~/.config}/mamba/mambarc.d
~/.mamba/.mambarc
~/.mamba/mambarc
~/.mamba/mambarc.d
~/.mambarc
{ target_prefix }/.condarc
{ target_prefix }/condarc
{ target_prefix }/condarc.d
{ target_prefix }/.mambarc
$CONDARC,
$MAMBARC;

View File

@ -2000,9 +2000,10 @@ namespace mamba
not be considered as logs (see log_level).)")));
// Config
// MAMBARC/CONDARC env dirs get parsed in target/root prefix hooks
insert(Configurable("rc_files", std::vector<fs::u8path>({}))
.group("Config sources")
.set_env_var_names({ "MAMBARC", "CONDARC" })
.needs({ "no_rc" })
.set_post_merge_hook<std::vector<fs::u8path>>(
[this](std::vector<fs::u8path>& value)
@ -2063,12 +2064,6 @@ namespace mamba
// Precedence is initially set least to most, and then at the end the list is reversed.
// Configuration::set_rc_values iterates over all config options, and then over all config
// file source. Essentially first come first serve.
// just FYI re "../conda": env::user_config_dir's default value is $XDG_CONFIG_HOME/mamba
// But we wanted to also allow $XDG_CONFIG_HOME/conda and '..' seems like the best way to
// make it conda/mamba compatible. Otherwise I would have to set user_config_dir to either
// be just $XDG_CONFIG_HOME and always supply mamba after calling it, or I would have to
// give env::user_config_dir a mamba argument, all so I can supply conda in a few default
// cases. It seems like ../conda is an easier solution
//
std::vector<fs::u8path>
Configuration::compute_default_rc_sources(const Context& context, const RCConfigLevel& level)
@ -2113,18 +2108,11 @@ namespace mamba
conda_user.push_back(fs::u8path(xgd_config_home) / "conda" / path);
}
}
if (util::get_env("CONDA_PREFIX"))
{
const std::string conda_prefix = util::get_env("CONDA_PREFIX").value();
for (const auto& path : condarc_list)
{
conda_user.push_back(fs::u8path(conda_prefix) / path);
}
}
std::vector<fs::u8path> env_var;
if (util::get_env("CONDARC"))
{
conda_user.push_back(fs::u8path(util::get_env("CONDARC").value()));
env_var.push_back(fs::u8path(util::get_env("CONDARC").value()));
}
std::vector<fs::u8path> mamba_user = {
@ -2138,7 +2126,7 @@ namespace mamba
};
if (util::get_env("MAMBARC"))
{
mamba_user.push_back(fs::u8path(util::get_env("MAMBARC").value()));
env_var.push_back(fs::u8path(util::get_env("MAMBARC").value()));
}
std::vector<fs::u8path> prefix = { context.prefix_params.target_prefix / ".condarc",
@ -2186,6 +2174,7 @@ namespace mamba
insertIntoSources(prefix);
}
insertIntoSources(env_var);
// Sort by precedence
std::reverse(sources.begin(), sources.end());

View File

@ -10,6 +10,33 @@ import yaml
from . import helpers
all_rc_files_list = [
# TODO: test system located sources?
# "/etc/conda/.condarc",
# "/etc/conda/condarc",
# "/etc/conda/condarc.d/",
# "/etc/conda/.mambarc",
# "/var/lib/conda/.condarc",
# "/var/lib/conda/condarc",
# "/var/lib/conda/condarc.d/",
# "/var/lib/conda/.mambarc",
("root_prefix", ".condarc"),
("root_prefix", "condarc"),
("root_prefix", "condarc.d"),
("root_prefix", ".mambarc"),
("home", ".conda/.condarc"),
("home", ".conda/condarc"),
("home", ".conda/condarc.d"),
("home", ".condarc"),
("env_set_xdg", "mambarc"),
("user_config_dir", "mambarc"),
("home", ".mambarc"),
("prefix", ".condarc"),
("prefix", "condarc"),
("prefix", "condarc.d"),
("prefix", ".mambarc"),
]
@pytest.fixture
def user_config_dir(tmp_home: Path):
@ -59,6 +86,41 @@ def rc_file_text(rc_file_args):
return yaml.dump(rc_file_args, Dumper=Dumper)
def create_rc_file(
where,
rc_filename,
rc_file_text,
tmp_home,
tmp_root_prefix,
tmp_prefix,
tmp_path,
user_config_dir,
monkeypatch,
):
if where == "home":
rc_file = tmp_home / rc_filename
elif where == "root_prefix":
rc_file = tmp_root_prefix / rc_filename
elif where == "prefix":
rc_file = tmp_prefix / rc_filename
elif where == "user_config_dir":
rc_file = user_config_dir / rc_filename
elif where == "env_set_xdg":
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_home / "custom_xdg_config_dir"))
rc_file = tmp_home / "custom_xdg_config_dir" / "mamba" / rc_filename
elif where == "absolute":
rc_file = Path(rc_filename)
else:
raise ValueError("Bad rc file location")
if rc_file.suffix == ".d":
rc_file = rc_file / "test.yaml"
rc_file.parent.mkdir(parents=True, exist_ok=True)
rc_file.write_text(rc_file_text)
return rc_file
@pytest.fixture
def rc_file(
request,
@ -68,6 +130,7 @@ def rc_file(
tmp_prefix,
tmp_path,
user_config_dir,
monkeypatch,
):
"""Parametrizable fixture to create an rc file at the desired location.
@ -76,33 +139,55 @@ def rc_file(
"""
if hasattr(request, "param"):
where, rc_filename = request.param
if where == "home":
rc_file = tmp_home / rc_filename
elif where == "root_prefix":
rc_file = tmp_root_prefix / rc_filename
elif where == "prefix":
rc_file = tmp_prefix / rc_filename
elif where == "user_config_dir":
rc_file = user_config_dir / rc_filename
elif where == "env_set_xdg":
os.environ["XDG_CONFIG_HOME"] = str(tmp_home / "custom_xdg_config_dir")
rc_file = tmp_home / "custom_xdg_config_dir" / "mamba" / rc_filename
elif where == "absolute":
rc_file = Path(rc_filename)
else:
raise ValueError("Bad rc file location")
if rc_file.suffix == ".d":
rc_file = rc_file / "test.yaml"
else:
rc_file = tmp_path / "umamba/config.yaml"
where, rc_filename = ("absolute", tmp_path / "umamba/config.yaml")
rc_file.parent.mkdir(parents=True, exist_ok=True)
with open(rc_file, "w+") as f:
f.write(rc_file_text)
rc_file = create_rc_file(
where,
rc_filename,
rc_file_text,
tmp_home,
tmp_root_prefix,
tmp_prefix,
tmp_path,
user_config_dir,
monkeypatch,
)
return rc_file
@pytest.fixture
def all_rc_files(
rc_file_text, tmp_home, tmp_root_prefix, tmp_prefix, tmp_path, user_config_dir, monkeypatch
):
"""Fixture to create all rc files
The files are created in isolated folders and set as the prefix, root prefix, and
home folder.
"""
files = []
for where, filename in all_rc_files_list:
if where == "user_config_dir":
continue # redundant with XDG_HOME_DIR
f = create_rc_file(
where,
filename,
rc_file_text,
tmp_home,
tmp_root_prefix,
tmp_prefix,
tmp_path,
user_config_dir,
monkeypatch,
)
files.append(f)
return files
class TestConfig:
def test_config_empty(self, tmp_home):
assert "Configuration of micromamba" in config()
@ -140,34 +225,9 @@ class TestConfigSources:
res = config("sources", quiet_flag)
assert res.startswith("Configuration files (by precedence order):")
# TODO: test system located sources?
@pytest.mark.parametrize(
"rc_file",
(
# "/etc/conda/.condarc",
# "/etc/conda/condarc",
# "/etc/conda/condarc.d/",
# "/etc/conda/.mambarc",
# "/var/lib/conda/.condarc",
# "/var/lib/conda/condarc",
# "/var/lib/conda/condarc.d/",
# "/var/lib/conda/.mambarc",
("user_config_dir", "mambarc"),
("env_set_xdg", "mambarc"),
("home", ".conda/.condarc"),
("home", ".conda/condarc"),
("home", ".conda/condarc.d"),
("home", ".condarc"),
("home", ".mambarc"),
("root_prefix", ".condarc"),
("root_prefix", "condarc"),
("root_prefix", "condarc.d"),
("root_prefix", ".mambarc"),
("prefix", ".condarc"),
("prefix", "condarc"),
("prefix", "condarc.d"),
("prefix", ".mambarc"),
),
all_rc_files_list,
indirect=True,
)
@pytest.mark.parametrize("rc_file_args", ({"override_channels_enabled": True},), indirect=True)
@ -177,6 +237,28 @@ class TestConfigSources:
expected_srcs = f"Configuration files (by precedence order):\n{short_name}".splitlines()
assert srcs == expected_srcs
@pytest.mark.parametrize("rc_file_args", ({"override_channels_enabled": True},), indirect=True)
def test_rc_file_precedence(
self, rc_file_text, all_rc_files, tmp_env_name, tmp_home, monkeypatch
):
env_filenames = []
for x in ["conda", "mamba"]:
env_x_rc = tmp_home / f"env-{x}rc.yaml"
monkeypatch.setenv(f"{x.upper()}RC", f"{env_x_rc}")
env_x_rc.write_text(rc_file_text)
env_filenames.append(str(env_x_rc).replace(os.path.expanduser("~"), "~"))
srcs = config("sources", "-vvvv", "-n", tmp_env_name).strip().splitlines()
for rc_file in all_rc_files:
short_names = [
str(rc_file).replace(os.path.expanduser("~"), "~") for rc_file in all_rc_files
]
short_names.extend(env_filenames)
short_names.reverse()
assert srcs[1:] == short_names
@pytest.mark.parametrize(
"rc_file",
[("home", "somefile.yml")],