Skip to content

Commit 89d2d24

Browse files
holzmanjjerphan
authored andcommitted
fix: precedence for rc files, CONDARC/MAMBARC env vars
This code changes the rc file precedence to match the documentation and fixes a bug where if CONDARC or MAMBARC were set that it was ignoring all other configuration files.
1 parent a25529e commit 89d2d24

File tree

3 files changed

+149
-65
lines changed

3 files changed

+149
-65
lines changed

docs/source/user_guide/configuration.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,27 @@ RC files have their own precedence order and use the same resolution process as
118118
{ root_prefix }/condarc
119119
{ root_prefix }/condarc.d
120120
{ root_prefix }/.mambarc
121+
122+
{ $XDG_CONFIG_HOME | ~/.config}/conda/.condarc
123+
{ $XDG_CONFIG_HOME | ~/.config}/conda/condarc
124+
{ $XDG_CONFIG_HOME | ~/.config}/condarc.d
121125
~/.conda/.condarc
122126
~/.conda/condarc
123127
~/.conda/condarc.d
124128
~/.condarc
129+
130+
{ $XDG_CONFIG_HOME | ~/.config}/mamba/.mambarc
131+
{ $XDG_CONFIG_HOME | ~/.config}/mamba/mambarc
132+
{ $XDG_CONFIG_HOME | ~/.config}/mamba/mambarc.d
133+
~/.mamba/.mambarc
134+
~/.mamba/mambarc
135+
~/.mamba/mambarc.d
125136
~/.mambarc
137+
126138
{ target_prefix }/.condarc
127139
{ target_prefix }/condarc
128140
{ target_prefix }/condarc.d
129141
{ target_prefix }/.mambarc
142+
130143
$CONDARC,
131144
$MAMBARC;

libmamba/src/api/configuration.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,9 +2030,10 @@ namespace mamba
20302030
not be considered as logs (see log_level).)")));
20312031

20322032
// Config
2033+
2034+
// MAMBARC/CONDARC env dirs get parsed in target/root prefix hooks
20332035
insert(Configurable("rc_files", std::vector<fs::u8path>({}))
20342036
.group("Config sources")
2035-
.set_env_var_names({ "MAMBARC", "CONDARC" })
20362037
.needs({ "no_rc" })
20372038
.set_post_merge_hook<std::vector<fs::u8path>>(
20382039
[this](std::vector<fs::u8path>& value)
@@ -2093,12 +2094,6 @@ namespace mamba
20932094
// Precedence is initially set least to most, and then at the end the list is reversed.
20942095
// Configuration::set_rc_values iterates over all config options, and then over all config
20952096
// file source. Essentially first come first serve.
2096-
// just FYI re "../conda": env::user_config_dir's default value is $XDG_CONFIG_HOME/mamba
2097-
// But we wanted to also allow $XDG_CONFIG_HOME/conda and '..' seems like the best way to
2098-
// make it conda/mamba compatible. Otherwise I would have to set user_config_dir to either
2099-
// be just $XDG_CONFIG_HOME and always supply mamba after calling it, or I would have to
2100-
// give env::user_config_dir a mamba argument, all so I can supply conda in a few default
2101-
// cases. It seems like ../conda is an easier solution
21022097
//
21032098
std::vector<fs::u8path>
21042099
Configuration::compute_default_rc_sources(const Context& context, const RCConfigLevel& level)
@@ -2143,18 +2138,11 @@ namespace mamba
21432138
conda_user.push_back(fs::u8path(xgd_config_home) / "conda" / path);
21442139
}
21452140
}
2146-
if (util::get_env("CONDA_PREFIX"))
2147-
{
2148-
const std::string conda_prefix = util::get_env("CONDA_PREFIX").value();
2149-
for (const auto& path : condarc_list)
2150-
{
2151-
conda_user.push_back(fs::u8path(conda_prefix) / path);
2152-
}
2153-
}
21542141

2142+
std::vector<fs::u8path> env_var;
21552143
if (util::get_env("CONDARC"))
21562144
{
2157-
conda_user.push_back(fs::u8path(util::get_env("CONDARC").value()));
2145+
env_var.push_back(fs::u8path(util::get_env("CONDARC").value()));
21582146
}
21592147

21602148
std::vector<fs::u8path> mamba_user = {
@@ -2168,7 +2156,7 @@ namespace mamba
21682156
};
21692157
if (util::get_env("MAMBARC"))
21702158
{
2171-
mamba_user.push_back(fs::u8path(util::get_env("MAMBARC").value()));
2159+
env_var.push_back(fs::u8path(util::get_env("MAMBARC").value()));
21722160
}
21732161

21742162
std::vector<fs::u8path> prefix = { context.prefix_params.target_prefix / ".condarc",
@@ -2216,6 +2204,7 @@ namespace mamba
22162204
insertIntoSources(prefix);
22172205
}
22182206

2207+
insertIntoSources(env_var);
22192208
// Sort by precedence
22202209
std::reverse(sources.begin(), sources.end());
22212210

micromamba/tests/test_config.py

Lines changed: 130 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,33 @@
1010

1111
from . import helpers
1212

13+
all_rc_files_list = [
14+
# TODO: test system located sources?
15+
# "/etc/conda/.condarc",
16+
# "/etc/conda/condarc",
17+
# "/etc/conda/condarc.d/",
18+
# "/etc/conda/.mambarc",
19+
# "/var/lib/conda/.condarc",
20+
# "/var/lib/conda/condarc",
21+
# "/var/lib/conda/condarc.d/",
22+
# "/var/lib/conda/.mambarc",
23+
("root_prefix", ".condarc"),
24+
("root_prefix", "condarc"),
25+
("root_prefix", "condarc.d"),
26+
("root_prefix", ".mambarc"),
27+
("home", ".conda/.condarc"),
28+
("home", ".conda/condarc"),
29+
("home", ".conda/condarc.d"),
30+
("home", ".condarc"),
31+
("env_set_xdg", "mambarc"),
32+
("user_config_dir", "mambarc"),
33+
("home", ".mambarc"),
34+
("prefix", ".condarc"),
35+
("prefix", "condarc"),
36+
("prefix", "condarc.d"),
37+
("prefix", ".mambarc"),
38+
]
39+
1340

1441
@pytest.fixture
1542
def user_config_dir(tmp_home: Path):
@@ -59,6 +86,41 @@ def rc_file_text(rc_file_args):
5986
return yaml.dump(rc_file_args, Dumper=Dumper)
6087

6188

89+
def create_rc_file(
90+
where,
91+
rc_filename,
92+
rc_file_text,
93+
tmp_home,
94+
tmp_root_prefix,
95+
tmp_prefix,
96+
tmp_path,
97+
user_config_dir,
98+
monkeypatch,
99+
):
100+
if where == "home":
101+
rc_file = tmp_home / rc_filename
102+
elif where == "root_prefix":
103+
rc_file = tmp_root_prefix / rc_filename
104+
elif where == "prefix":
105+
rc_file = tmp_prefix / rc_filename
106+
elif where == "user_config_dir":
107+
rc_file = user_config_dir / rc_filename
108+
elif where == "env_set_xdg":
109+
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_home / "custom_xdg_config_dir"))
110+
rc_file = tmp_home / "custom_xdg_config_dir" / "mamba" / rc_filename
111+
elif where == "absolute":
112+
rc_file = Path(rc_filename)
113+
else:
114+
raise ValueError("Bad rc file location")
115+
if rc_file.suffix == ".d":
116+
rc_file = rc_file / "test.yaml"
117+
118+
rc_file.parent.mkdir(parents=True, exist_ok=True)
119+
rc_file.write_text(rc_file_text)
120+
121+
return rc_file
122+
123+
62124
@pytest.fixture
63125
def rc_file(
64126
request,
@@ -68,6 +130,7 @@ def rc_file(
68130
tmp_prefix,
69131
tmp_path,
70132
user_config_dir,
133+
monkeypatch,
71134
):
72135
"""Parametrizable fixture to create an rc file at the desired location.
73136
@@ -76,33 +139,55 @@ def rc_file(
76139
"""
77140
if hasattr(request, "param"):
78141
where, rc_filename = request.param
79-
if where == "home":
80-
rc_file = tmp_home / rc_filename
81-
elif where == "root_prefix":
82-
rc_file = tmp_root_prefix / rc_filename
83-
elif where == "prefix":
84-
rc_file = tmp_prefix / rc_filename
85-
elif where == "user_config_dir":
86-
rc_file = user_config_dir / rc_filename
87-
elif where == "env_set_xdg":
88-
os.environ["XDG_CONFIG_HOME"] = str(tmp_home / "custom_xdg_config_dir")
89-
rc_file = tmp_home / "custom_xdg_config_dir" / "mamba" / rc_filename
90-
elif where == "absolute":
91-
rc_file = Path(rc_filename)
92-
else:
93-
raise ValueError("Bad rc file location")
94-
if rc_file.suffix == ".d":
95-
rc_file = rc_file / "test.yaml"
96142
else:
97-
rc_file = tmp_path / "umamba/config.yaml"
98-
99-
rc_file.parent.mkdir(parents=True, exist_ok=True)
100-
with open(rc_file, "w+") as f:
101-
f.write(rc_file_text)
143+
where, rc_filename = ("absolute", tmp_path / "umamba/config.yaml")
144+
145+
rc_file = create_rc_file(
146+
where,
147+
rc_filename,
148+
rc_file_text,
149+
tmp_home,
150+
tmp_root_prefix,
151+
tmp_prefix,
152+
tmp_path,
153+
user_config_dir,
154+
monkeypatch,
155+
)
102156

103157
return rc_file
104158

105159

160+
@pytest.fixture
161+
def all_rc_files(
162+
rc_file_text, tmp_home, tmp_root_prefix, tmp_prefix, tmp_path, user_config_dir, monkeypatch
163+
):
164+
"""Fixture to create all rc files
165+
166+
The files are created in isolated folders and set as the prefix, root prefix, and
167+
home folder.
168+
169+
"""
170+
171+
files = []
172+
for where, filename in all_rc_files_list:
173+
if where == "user_config_dir":
174+
continue # redundant with XDG_HOME_DIR
175+
f = create_rc_file(
176+
where,
177+
filename,
178+
rc_file_text,
179+
tmp_home,
180+
tmp_root_prefix,
181+
tmp_prefix,
182+
tmp_path,
183+
user_config_dir,
184+
monkeypatch,
185+
)
186+
187+
files.append(f)
188+
return files
189+
190+
106191
class TestConfig:
107192
def test_config_empty(self, tmp_home):
108193
assert "Configuration of micromamba" in config()
@@ -140,34 +225,9 @@ def test_config_sources_empty(self, tmp_prefix, quiet_flag, norc):
140225
res = config("sources", quiet_flag)
141226
assert res.startswith("Configuration files (by precedence order):")
142227

143-
# TODO: test system located sources?
144228
@pytest.mark.parametrize(
145229
"rc_file",
146-
(
147-
# "/etc/conda/.condarc",
148-
# "/etc/conda/condarc",
149-
# "/etc/conda/condarc.d/",
150-
# "/etc/conda/.mambarc",
151-
# "/var/lib/conda/.condarc",
152-
# "/var/lib/conda/condarc",
153-
# "/var/lib/conda/condarc.d/",
154-
# "/var/lib/conda/.mambarc",
155-
("user_config_dir", "mambarc"),
156-
("env_set_xdg", "mambarc"),
157-
("home", ".conda/.condarc"),
158-
("home", ".conda/condarc"),
159-
("home", ".conda/condarc.d"),
160-
("home", ".condarc"),
161-
("home", ".mambarc"),
162-
("root_prefix", ".condarc"),
163-
("root_prefix", "condarc"),
164-
("root_prefix", "condarc.d"),
165-
("root_prefix", ".mambarc"),
166-
("prefix", ".condarc"),
167-
("prefix", "condarc"),
168-
("prefix", "condarc.d"),
169-
("prefix", ".mambarc"),
170-
),
230+
all_rc_files_list,
171231
indirect=True,
172232
)
173233
@pytest.mark.parametrize("rc_file_args", ({"override_channels_enabled": True},), indirect=True)
@@ -177,6 +237,28 @@ def test_config_rc_file(self, rc_file, tmp_env_name):
177237
expected_srcs = f"Configuration files (by precedence order):\n{short_name}".splitlines()
178238
assert srcs == expected_srcs
179239

240+
@pytest.mark.parametrize("rc_file_args", ({"override_channels_enabled": True},), indirect=True)
241+
def test_rc_file_precedence(
242+
self, rc_file_text, all_rc_files, tmp_env_name, tmp_home, monkeypatch
243+
):
244+
env_filenames = []
245+
for x in ["conda", "mamba"]:
246+
env_x_rc = tmp_home / f"env-{x}rc.yaml"
247+
monkeypatch.setenv(f"{x.upper()}RC", f"{env_x_rc}")
248+
env_x_rc.write_text(rc_file_text)
249+
env_filenames.append(str(env_x_rc).replace(os.path.expanduser("~"), "~"))
250+
251+
srcs = config("sources", "-vvvv", "-n", tmp_env_name).strip().splitlines()
252+
for rc_file in all_rc_files:
253+
short_names = [
254+
str(rc_file).replace(os.path.expanduser("~"), "~") for rc_file in all_rc_files
255+
]
256+
257+
short_names.extend(env_filenames)
258+
short_names.reverse()
259+
260+
assert srcs[1:] == short_names
261+
180262
@pytest.mark.parametrize(
181263
"rc_file",
182264
[("home", "somefile.yml")],

0 commit comments

Comments
 (0)