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
{ root_prefix }/condarc.d { root_prefix }/condarc.d
{ root_prefix }/.mambarc { 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 ~/.conda/condarc
~/.conda/condarc.d ~/.conda/condarc.d
~/.condarc ~/.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 ~/.mambarc
{ target_prefix }/.condarc { target_prefix }/.condarc
{ target_prefix }/condarc { target_prefix }/condarc
{ target_prefix }/condarc.d { target_prefix }/condarc.d
{ target_prefix }/.mambarc { target_prefix }/.mambarc
$CONDARC, $CONDARC,
$MAMBARC; $MAMBARC;

View File

@ -2000,9 +2000,10 @@ namespace mamba
not be considered as logs (see log_level).)"))); not be considered as logs (see log_level).)")));
// Config // Config
// MAMBARC/CONDARC env dirs get parsed in target/root prefix hooks
insert(Configurable("rc_files", std::vector<fs::u8path>({})) insert(Configurable("rc_files", std::vector<fs::u8path>({}))
.group("Config sources") .group("Config sources")
.set_env_var_names({ "MAMBARC", "CONDARC" })
.needs({ "no_rc" }) .needs({ "no_rc" })
.set_post_merge_hook<std::vector<fs::u8path>>( .set_post_merge_hook<std::vector<fs::u8path>>(
[this](std::vector<fs::u8path>& value) [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. // 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 // Configuration::set_rc_values iterates over all config options, and then over all config
// file source. Essentially first come first serve. // 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> std::vector<fs::u8path>
Configuration::compute_default_rc_sources(const Context& context, const RCConfigLevel& level) 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); 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")) 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 = { std::vector<fs::u8path> mamba_user = {
@ -2138,7 +2126,7 @@ namespace mamba
}; };
if (util::get_env("MAMBARC")) 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", std::vector<fs::u8path> prefix = { context.prefix_params.target_prefix / ".condarc",
@ -2186,6 +2174,7 @@ namespace mamba
insertIntoSources(prefix); insertIntoSources(prefix);
} }
insertIntoSources(env_var);
// Sort by precedence // Sort by precedence
std::reverse(sources.begin(), sources.end()); std::reverse(sources.begin(), sources.end());

View File

@ -10,6 +10,33 @@ import yaml
from . import helpers 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 @pytest.fixture
def user_config_dir(tmp_home: Path): def user_config_dir(tmp_home: Path):
@ -59,23 +86,17 @@ def rc_file_text(rc_file_args):
return yaml.dump(rc_file_args, Dumper=Dumper) return yaml.dump(rc_file_args, Dumper=Dumper)
@pytest.fixture def create_rc_file(
def rc_file( where,
request, rc_filename,
rc_file_text, rc_file_text,
tmp_home, tmp_home,
tmp_root_prefix, tmp_root_prefix,
tmp_prefix, tmp_prefix,
tmp_path, tmp_path,
user_config_dir, user_config_dir,
monkeypatch,
): ):
"""Parametrizable fixture to create an rc file at the desired location.
The file is created in an isolated folder and set as the prefix, root prefix, or
home folder.
"""
if hasattr(request, "param"):
where, rc_filename = request.param
if where == "home": if where == "home":
rc_file = tmp_home / rc_filename rc_file = tmp_home / rc_filename
elif where == "root_prefix": elif where == "root_prefix":
@ -85,7 +106,7 @@ def rc_file(
elif where == "user_config_dir": elif where == "user_config_dir":
rc_file = user_config_dir / rc_filename rc_file = user_config_dir / rc_filename
elif where == "env_set_xdg": elif where == "env_set_xdg":
os.environ["XDG_CONFIG_HOME"] = str(tmp_home / "custom_xdg_config_dir") monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_home / "custom_xdg_config_dir"))
rc_file = tmp_home / "custom_xdg_config_dir" / "mamba" / rc_filename rc_file = tmp_home / "custom_xdg_config_dir" / "mamba" / rc_filename
elif where == "absolute": elif where == "absolute":
rc_file = Path(rc_filename) rc_file = Path(rc_filename)
@ -93,16 +114,80 @@ def rc_file(
raise ValueError("Bad rc file location") raise ValueError("Bad rc file location")
if rc_file.suffix == ".d": if rc_file.suffix == ".d":
rc_file = rc_file / "test.yaml" rc_file = rc_file / "test.yaml"
else:
rc_file = tmp_path / "umamba/config.yaml"
rc_file.parent.mkdir(parents=True, exist_ok=True) rc_file.parent.mkdir(parents=True, exist_ok=True)
with open(rc_file, "w+") as f: rc_file.write_text(rc_file_text)
f.write(rc_file_text)
return rc_file return rc_file
@pytest.fixture
def rc_file(
request,
rc_file_text,
tmp_home,
tmp_root_prefix,
tmp_prefix,
tmp_path,
user_config_dir,
monkeypatch,
):
"""Parametrizable fixture to create an rc file at the desired location.
The file is created in an isolated folder and set as the prefix, root prefix, or
home folder.
"""
if hasattr(request, "param"):
where, rc_filename = request.param
else:
where, rc_filename = ("absolute", tmp_path / "umamba/config.yaml")
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: class TestConfig:
def test_config_empty(self, tmp_home): def test_config_empty(self, tmp_home):
assert "Configuration of micromamba" in config() assert "Configuration of micromamba" in config()
@ -140,34 +225,9 @@ class TestConfigSources:
res = config("sources", quiet_flag) res = config("sources", quiet_flag)
assert res.startswith("Configuration files (by precedence order):") assert res.startswith("Configuration files (by precedence order):")
# TODO: test system located sources?
@pytest.mark.parametrize( @pytest.mark.parametrize(
"rc_file", "rc_file",
( all_rc_files_list,
# "/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"),
),
indirect=True, indirect=True,
) )
@pytest.mark.parametrize("rc_file_args", ({"override_channels_enabled": True},), 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() expected_srcs = f"Configuration files (by precedence order):\n{short_name}".splitlines()
assert srcs == expected_srcs 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( @pytest.mark.parametrize(
"rc_file", "rc_file",
[("home", "somefile.yml")], [("home", "somefile.yml")],