Skip to content

Commit 1faa42c

Browse files
add support for 'config --list-paths'
added config command to list all config files and dropin files which are currently considered by west.
1 parent c032bc3 commit 1faa42c

File tree

3 files changed

+118
-4
lines changed

3 files changed

+118
-4
lines changed

src/west/app/config.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import argparse
88

99
from west.commands import CommandError, WestCommand
10-
from west.configuration import ConfigFile
10+
from west.configuration import ConfigFile, Configuration
1111

1212
CONFIG_DESCRIPTION = '''\
1313
West configuration file handling.
@@ -73,6 +73,14 @@
7373
7474
To delete <name> everywhere it's set, including the system file:
7575
west config -D <name>
76+
77+
To list the configuration files that are loaded (both the main config file
78+
and all drop-ins) in the exact order they were applied (where later values
79+
override earlier ones):
80+
west config --list-paths
81+
west config --local --list-paths
82+
west config --global --list-paths
83+
west config --system --list-paths
7684
'''
7785

7886
CONFIG_EPILOG = '''\
@@ -105,10 +113,16 @@ def do_add_parser(self, parser_adder):
105113
).add_mutually_exclusive_group()
106114

107115
group.add_argument(
108-
'-p',
109116
'--print-path',
110117
action='store_true',
111-
help='print file path from according west config(--system, --global, --local)',
118+
help='print the file path from according west '
119+
'config (--local [default], --global, --system)',
120+
)
121+
group.add_argument(
122+
'--list-paths',
123+
action='store_true',
124+
help='list all config files and dropin files that '
125+
'are currently considered by west config',
112126
)
113127
group.add_argument(
114128
'-l', '--list', action='store_true', help='list all options and their values'
@@ -164,14 +178,16 @@ def do_run(self, args, user_args):
164178
if args.list:
165179
if args.name:
166180
self.parser.error('-l cannot be combined with name argument')
167-
elif not args.name and not args.print_path:
181+
elif not any([args.name, args.print_path, args.list_paths]):
168182
self.parser.error('missing argument name (to list all options and values, use -l)')
169183
elif args.append:
170184
if args.value is None:
171185
self.parser.error('-a requires both name and value')
172186

173187
if args.print_path:
174188
self.print_path(args)
189+
elif args.list_paths:
190+
self.list_paths(args)
175191
elif args.list:
176192
self.list(args)
177193
elif delete:
@@ -188,6 +204,11 @@ def print_path(self, args):
188204
if config_path:
189205
print(config_path)
190206

207+
def list_paths(self, args):
208+
config_paths = Configuration().get_paths(args.configfile or ALL)
209+
for config_path in config_paths:
210+
print(config_path)
211+
191212
def list(self, args):
192213
what = args.configfile or ALL
193214
for option, value in self.config.items(configfile=what):

src/west/configuration.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,16 @@ def get_path(self, configfile: ConfigFile = ConfigFile.LOCAL):
191191
elif configfile == ConfigFile.GLOBAL:
192192
return self._global_path
193193

194+
def get_paths(self, configfile: ConfigFile = ConfigFile.ALL):
195+
ret = []
196+
if self._global and configfile in [ConfigFile.GLOBAL, ConfigFile.ALL]:
197+
ret += self._global._paths()
198+
if self._system and configfile in [ConfigFile.SYSTEM, ConfigFile.ALL]:
199+
ret += self._system._paths()
200+
if self._local and configfile in [ConfigFile.LOCAL, ConfigFile.ALL]:
201+
ret += self._local._paths()
202+
return ret
203+
194204
def get(
195205
self, option: str, default: str | None = None, configfile: ConfigFile = ConfigFile.ALL
196206
) -> str | None:

tests/test_config.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,89 @@ def test_config_print_path():
103103
stdout = cmd('config --system --print-path')
104104
assert os.environ["WEST_CONFIG_SYSTEM"] == stdout.rstrip()
105105

106+
# print nothing if local config does not exist (exit code 0)
107+
del os.environ['WEST_CONFIG_LOCAL']
108+
stdout = cmd('config --local --print-path')
109+
assert "" == stdout.rstrip()
110+
111+
112+
TEST_CASES_CONFIG_LIST_PATHS = [
113+
# (flag, env_var)
114+
('--local', 'WEST_CONFIG_LOCAL'),
115+
('--system', 'WEST_CONFIG_SYSTEM'),
116+
('--global', 'WEST_CONFIG_GLOBAL'),
117+
]
118+
119+
120+
@pytest.mark.parametrize("test_case", TEST_CASES_CONFIG_LIST_PATHS)
121+
def test_config_list_paths(test_case):
122+
flag, env_var = test_case
123+
124+
# no config is listed (since it does not exist)
125+
stdout = cmd(f'config {flag} --list-paths')
126+
assert '' == stdout.rstrip()
127+
128+
# create the config
129+
cmd(f'config {flag} pytest.key val')
130+
131+
# check that the config is listed now
132+
stdout = cmd(f'config {flag} --list-paths')
133+
config_path = pathlib.Path(os.environ[env_var])
134+
assert f'{config_path}' == stdout.rstrip()
135+
136+
137+
def test_config_list_paths_extended():
138+
WEST_CONFIG_LOCAL = os.environ['WEST_CONFIG_LOCAL']
139+
WEST_CONFIG_GLOBAL = os.environ['WEST_CONFIG_GLOBAL']
140+
WEST_CONFIG_SYSTEM = os.environ['WEST_CONFIG_SYSTEM']
141+
142+
# create the configs
143+
cmd('config --local pytest.key val')
144+
cmd('config --global pytest.key val')
145+
cmd('config --system pytest.key val')
146+
147+
# list the configs
148+
stdout = cmd('config --list-paths')
149+
assert (
150+
stdout.splitlines()
151+
== textwrap.dedent(f'''\
152+
{WEST_CONFIG_GLOBAL}
153+
{WEST_CONFIG_SYSTEM}
154+
{WEST_CONFIG_LOCAL}
155+
''').splitlines()
156+
)
157+
158+
# create some dropins files
159+
dropin_files = [
160+
pathlib.Path(WEST_CONFIG_GLOBAL + '.d') / 'a.conf',
161+
pathlib.Path(WEST_CONFIG_GLOBAL + '.d') / 'z.conf',
162+
pathlib.Path(WEST_CONFIG_SYSTEM + '.d') / 'a.conf',
163+
pathlib.Path(WEST_CONFIG_SYSTEM + '.d') / 'z.conf',
164+
pathlib.Path(WEST_CONFIG_LOCAL + '.d') / 'a.conf',
165+
pathlib.Path(WEST_CONFIG_LOCAL + '.d') / 'z.conf',
166+
]
167+
for dropin_file in dropin_files:
168+
dropin_file.parent.mkdir(exist_ok=True)
169+
dropin_file.touch()
170+
171+
# list the configs
172+
stdout = cmd('config --list-paths')
173+
assert (
174+
stdout.splitlines()
175+
== textwrap.dedent(f'''\
176+
{dropin_files[0]}
177+
{dropin_files[1]}
178+
{WEST_CONFIG_GLOBAL}
179+
{dropin_files[2]}
180+
{dropin_files[3]}
181+
{WEST_CONFIG_SYSTEM}
182+
{dropin_files[4]}
183+
{dropin_files[5]}
184+
{WEST_CONFIG_LOCAL}
185+
''').splitlines()
186+
)
187+
188+
# print nothing if local config does not exist (exit code 0)
106189
del os.environ['WEST_CONFIG_LOCAL']
107190
stdout = cmd('config --local --print-path')
108191
assert "" == stdout.rstrip()

0 commit comments

Comments
 (0)