Skip to content

Commit f475a52

Browse files
only use dropin configs when option config.dropins is true
Boolean option `config.dropins` must be set to `true` so that dropin configs for the according config type are considered. So if the option config.dropins=true in enabled in local config, only local dropin configs are used (but no system or global ones).
1 parent bd7eb4d commit f475a52

File tree

2 files changed

+84
-31
lines changed

2 files changed

+84
-31
lines changed

src/west/configuration.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,34 @@ def from_path(path: Path | None) -> '_InternalCF | None':
7878

7979
def __init__(self, path: Path):
8080
self.cp = _configparser()
81-
self.dropin_cp = _configparser()
8281
self.path = path if path.exists() else None
83-
dropin_dir = Path(f'{path}.d')
84-
self.dropin_dir = dropin_dir if dropin_dir.exists() else None
82+
if self.path:
83+
self.cp.read(self.path, encoding='utf-8')
84+
85+
# consider dropin configs
86+
self.dropin_cp = _configparser()
87+
self.dropin_dir = None
8588
self.dropin_paths = []
86-
if self.dropin_dir:
87-
# dropin configs are applied in alphabetical order
88-
for conf in sorted(self.dropin_dir.iterdir()):
89-
# only consider .conf files
90-
if conf.suffix.lower() in ['.conf', '.ini']:
91-
self.dropin_paths.append(self.dropin_dir / conf)
92-
self._read()
89+
# dropin configs must be enabled in config
90+
if self.cp.getboolean('config', 'dropins', fallback=False):
91+
# dropin dir is the config path with .d suffix
92+
dropin_dir = Path(f'{path}.d')
93+
self.dropin_dir = dropin_dir if dropin_dir.exists() else None
94+
if self.dropin_dir:
95+
# dropin configs are applied in alphabetical order
96+
for conf in sorted(self.dropin_dir.iterdir()):
97+
# only consider .conf files
98+
if conf.suffix in ['.conf', '.ini']:
99+
self.dropin_paths.append(self.dropin_dir / conf)
100+
if self.dropin_paths:
101+
self.dropin_cp.read(self.dropin_paths, encoding='utf-8')
93102

94103
def _paths(self) -> list[Path]:
95104
ret = [p for p in self.dropin_paths]
96105
if self.path:
97106
ret.append(self.path)
98107
return ret
99108

100-
def _read(self):
101-
if self.path:
102-
self.cp.read(self.path, encoding='utf-8')
103-
if self.dropin_paths:
104-
self.dropin_cp.read(self.dropin_paths, encoding='utf-8')
105-
106109
def _write(self):
107110
if not self.path:
108111
raise WestNotFound('No config file exists that can be written')

tests/test_config.py

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def test_config_list_paths_extended():
156156
''').splitlines()
157157
)
158158

159-
# create some dropins files
159+
# create some dropin config files
160160
dropin_files = [
161161
pathlib.Path(WEST_CONFIG_GLOBAL + '.d') / 'a.conf',
162162
pathlib.Path(WEST_CONFIG_GLOBAL + '.d') / 'z.conf',
@@ -169,7 +169,23 @@ def test_config_list_paths_extended():
169169
dropin_file.parent.mkdir(exist_ok=True)
170170
dropin_file.touch()
171171

172-
# list the configs
172+
# list the configs (dropin configs are not enabled by default)
173+
stdout = cmd('config --list-paths')
174+
assert (
175+
stdout.splitlines()
176+
== textwrap.dedent(f'''\
177+
{WEST_CONFIG_GLOBAL}
178+
{WEST_CONFIG_SYSTEM}
179+
{WEST_CONFIG_LOCAL}
180+
''').splitlines()
181+
)
182+
183+
# enable config.dropins for each config type
184+
cmd('config --local config.dropins true')
185+
cmd('config --global config.dropins true')
186+
cmd('config --system config.dropins true')
187+
188+
# list the configs (consider dropin configs)
173189
stdout = cmd('config --list-paths')
174190
assert (
175191
stdout.splitlines()
@@ -186,10 +202,27 @@ def test_config_list_paths_extended():
186202
''').splitlines()
187203
)
188204

189-
# print nothing if local config does not exist (exit code 0)
190-
del os.environ['WEST_CONFIG_LOCAL']
191-
stdout = cmd('config --local --print-path')
192-
assert "" == stdout.rstrip()
205+
# list the configs only when dropin configs are disabled
206+
cmd('config --local config.dropins false')
207+
cmd('config --global config.dropins false')
208+
cmd('config --system config.dropins false')
209+
stdout = cmd('config --list-paths')
210+
assert (
211+
stdout.splitlines()
212+
== textwrap.dedent(f'''\
213+
{WEST_CONFIG_GLOBAL}
214+
{WEST_CONFIG_SYSTEM}
215+
{WEST_CONFIG_LOCAL}
216+
''').splitlines()
217+
)
218+
219+
# do not list any configs if no config files exist
220+
# (Note: even no local config exists, same as outside any west workspace)
221+
pathlib.Path(WEST_CONFIG_GLOBAL).unlink()
222+
pathlib.Path(WEST_CONFIG_SYSTEM).unlink()
223+
pathlib.Path(WEST_CONFIG_LOCAL).unlink()
224+
stdout = cmd('config --list-paths')
225+
assert stdout.splitlines() == []
193226

194227

195228
def test_config_local():
@@ -310,7 +343,7 @@ def test_local_creation():
310343
assert cfg(f=LOCAL)['pytest']['key'] == 'val'
311344

312345

313-
TEST_CASES_CONFIG_D = [
346+
TEST_CASES_DROPIN_CONFIGS = [
314347
# (flag, env_var)
315348
('', 'WEST_CONFIG_LOCAL'),
316349
('--local', 'WEST_CONFIG_LOCAL'),
@@ -319,16 +352,17 @@ def test_local_creation():
319352
]
320353

321354

322-
@pytest.mark.parametrize("test_case", TEST_CASES_CONFIG_D)
323-
def test_config_d_local(test_case):
355+
@pytest.mark.parametrize("test_case", TEST_CASES_DROPIN_CONFIGS)
356+
def test_config_dropins(test_case):
324357
flag, env_var = test_case
325358
config_path = pathlib.Path(os.environ[env_var])
326-
config_d_dir = pathlib.Path(f'{config_path}.d')
327-
config_d_dir.mkdir()
359+
dropin_configs_dir = pathlib.Path(f'{config_path}.d')
360+
dropin_configs_dir.mkdir()
328361

329362
# write value in actual config file
330363
cmd(f'config {flag} pytest.key val')
331364
cmd(f'config {flag} pytest.config-only val')
365+
cmd(f'config {flag} config.dropins true')
332366

333367
# read config value via command line
334368
stdout = cmd(f'config {flag} pytest.key')
@@ -344,10 +378,13 @@ def test_config_d_local(test_case):
344378
key = val
345379
config-only = val
346380
381+
[config]
382+
dropins = true
383+
347384
''')
348385

349386
# create a dropin config under .d
350-
with open(config_d_dir / 'a.conf', 'w') as conf:
387+
with open(dropin_configs_dir / 'a.conf', 'w') as conf:
351388
conf.write(
352389
textwrap.dedent('''
353390
[pytest]
@@ -358,7 +395,7 @@ def test_config_d_local(test_case):
358395
)
359396

360397
# create a dropin config under .d
361-
with open(config_d_dir / 'z.conf', 'w') as conf:
398+
with open(dropin_configs_dir / 'z.conf', 'w') as conf:
362399
conf.write(
363400
textwrap.dedent('''
364401
[pytest]
@@ -390,16 +427,20 @@ def test_config_d_local(test_case):
390427
[pytest]
391428
key = val
392429
430+
[config]
431+
dropins = true
432+
393433
''')
394434

395-
# remove config file
435+
# remove config file and only set config.dropins true again
396436
config_path.unlink()
437+
cmd(f'config {flag} config.dropins true')
397438

398439
# values from config are unset now
399440
stderr = cmd_raises(f'config {flag} pytest.config-only', subprocess.CalledProcessError)
400441
assert 'ERROR: pytest.config-only is unset' == stderr.rstrip()
401442

402-
# dropin applies now, since config does not exist
443+
# dropin config values are used now, since they are not set in config
403444
stdout = cmd(f'config {flag} pytest.key')
404445
assert 'from dropin a' == stdout.rstrip()
405446
# alphabetical order (z.conf is overwriting a.conf)
@@ -415,6 +456,15 @@ def test_config_d_local(test_case):
415456
# deletion of a value that is not existing anymore should fail
416457
cmd_raises(f'config {flag} -d pytest.config-only', subprocess.CalledProcessError)
417458

459+
# remove config (config.dropins is false by default)
460+
config_path.unlink()
461+
462+
# values from dropin configs are not considered now
463+
cmd_raises(f'config {flag} pytest.key', subprocess.CalledProcessError)
464+
cmd_raises(f'config {flag} pytest.dropin-only', subprocess.CalledProcessError)
465+
cmd_raises(f'config {flag} pytest.dropin-only-a', subprocess.CalledProcessError)
466+
cmd_raises(f'config {flag} pytest.dropin-only-z', subprocess.CalledProcessError)
467+
418468

419469
def test_local_creation_with_topdir():
420470
# Like test_local_creation, with a specified topdir.

0 commit comments

Comments
 (0)