Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/source/user_guide/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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;
23 changes: 6 additions & 17 deletions libmamba/src/api/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2024,9 +2024,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)
Expand Down Expand Up @@ -2087,12 +2088,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)
Expand Down Expand Up @@ -2137,18 +2132,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 = {
Expand All @@ -2162,7 +2150,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",
Expand Down Expand Up @@ -2210,6 +2198,7 @@ namespace mamba
insertIntoSources(prefix);
}

insertIntoSources(env_var);
// Sort by precedence
std::reverse(sources.begin(), sources.end());

Expand Down
178 changes: 130 additions & 48 deletions micromamba/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,33 @@

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):
Expand Down Expand Up @@ -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,
Expand All @@ -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.

Expand All @@ -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"

rc_file.parent.mkdir(parents=True, exist_ok=True)
with open(rc_file, "w+") as f:
f.write(rc_file_text)
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:
def test_config_empty(self, tmp_home):
assert "Configuration of micromamba" in config()
Expand Down Expand Up @@ -140,34 +225,9 @@ def test_config_sources_empty(self, tmp_prefix, quiet_flag, norc):
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)
Expand All @@ -177,6 +237,28 @@ def test_config_rc_file(self, rc_file, tmp_env_name):
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")],
Expand Down
Loading