Skip to content

Commit cc0420f

Browse files
committed
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 64a620a commit cc0420f

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
@@ -2006,9 +2006,10 @@ namespace mamba
20062006
not be considered as logs (see log_level).)")));
20072007

20082008
// Config
2009+
2010+
// MAMBARC/CONDARC env dirs get parsed in target/root prefix hooks
20092011
insert(Configurable("rc_files", std::vector<fs::u8path>({}))
20102012
.group("Config sources")
2011-
.set_env_var_names({ "MAMBARC", "CONDARC" })
20122013
.needs({ "no_rc" })
20132014
.set_post_merge_hook<std::vector<fs::u8path>>(
20142015
[this](std::vector<fs::u8path>& value)
@@ -2069,12 +2070,6 @@ namespace mamba
20692070
// Precedence is initially set least to most, and then at the end the list is reversed.
20702071
// Configuration::set_rc_values iterates over all config options, and then over all config
20712072
// file source. Essentially first come first serve.
2072-
// just FYI re "../conda": env::user_config_dir's default value is $XDG_CONFIG_HOME/mamba
2073-
// But we wanted to also allow $XDG_CONFIG_HOME/conda and '..' seems like the best way to
2074-
// make it conda/mamba compatible. Otherwise I would have to set user_config_dir to either
2075-
// be just $XDG_CONFIG_HOME and always supply mamba after calling it, or I would have to
2076-
// give env::user_config_dir a mamba argument, all so I can supply conda in a few default
2077-
// cases. It seems like ../conda is an easier solution
20782073
//
20792074
std::vector<fs::u8path>
20802075
Configuration::compute_default_rc_sources(const Context& context, const RCConfigLevel& level)
@@ -2119,18 +2114,11 @@ namespace mamba
21192114
conda_user.push_back(fs::u8path(xgd_config_home) / "conda" / path);
21202115
}
21212116
}
2122-
if (util::get_env("CONDA_PREFIX"))
2123-
{
2124-
const std::string conda_prefix = util::get_env("CONDA_PREFIX").value();
2125-
for (const auto& path : condarc_list)
2126-
{
2127-
conda_user.push_back(fs::u8path(conda_prefix) / path);
2128-
}
2129-
}
21302117

2118+
std::vector<fs::u8path> env_var;
21312119
if (util::get_env("CONDARC"))
21322120
{
2133-
conda_user.push_back(fs::u8path(util::get_env("CONDARC").value()));
2121+
env_var.push_back(fs::u8path(util::get_env("CONDARC").value()));
21342122
}
21352123

21362124
std::vector<fs::u8path> mamba_user = {
@@ -2144,7 +2132,7 @@ namespace mamba
21442132
};
21452133
if (util::get_env("MAMBARC"))
21462134
{
2147-
mamba_user.push_back(fs::u8path(util::get_env("MAMBARC").value()));
2135+
env_var.push_back(fs::u8path(util::get_env("MAMBARC").value()));
21482136
}
21492137

21502138
std::vector<fs::u8path> prefix = { context.prefix_params.target_prefix / ".condarc",
@@ -2192,6 +2180,7 @@ namespace mamba
21922180
insertIntoSources(prefix);
21932181
}
21942182

2183+
insertIntoSources(env_var);
21952184
// Sort by precedence
21962185
std::reverse(sources.begin(), sources.end());
21972186

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)