Skip to content

Commit 34ed545

Browse files
mrstegemanefiop
andauthored
cli: config: add support for --show-origin (#5126)
* cli: config: add support for --show-origin Support the --show-origin option for config, which, similar to git, prefixes each config option with the source file it originated from. Fixes #5119 * Reformat with black. * Simplify logic for local config files. * Add test for --show-config output. * Update tests/func/test_config.py Co-authored-by: Ruslan Kuprieiev <[email protected]>
1 parent 23811e0 commit 34ed545

File tree

2 files changed

+77
-4
lines changed

2 files changed

+77
-4
lines changed

dvc/command/config.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import argparse
22
import logging
3+
import os
34

45
from dvc.command.base import CmdBaseNoRepo, append_doc_link
56
from dvc.config import Config, ConfigError
7+
from dvc.repo import Repo
68
from dvc.utils.flatten import flatten
79

810
logger = logging.getLogger(__name__)
@@ -34,6 +36,14 @@ def __init__(self, args):
3436
self.config = Config(validate=False)
3537

3638
def run(self):
39+
if self.args.show_origin:
40+
if any((self.args.value, self.args.unset)):
41+
logger.error(
42+
"--show-origin can't be used together with any of these "
43+
"options: -u/--unset, value"
44+
)
45+
return 1
46+
3747
if self.args.list:
3848
if any((self.args.name, self.args.value, self.args.unset)):
3949
logger.error(
@@ -43,7 +53,11 @@ def run(self):
4353
return 1
4454

4555
conf = self.config.load_one(self.args.level)
46-
logger.info("\n".join(self._format_config(conf)))
56+
prefix = self._config_file_prefix(
57+
self.args.show_origin, self.config, self.args.level
58+
)
59+
60+
logger.info("\n".join(self._format_config(conf, prefix)))
4761
return 0
4862

4963
if self.args.name is None:
@@ -54,10 +68,14 @@ def run(self):
5468

5569
if self.args.value is None and not self.args.unset:
5670
conf = self.config.load_one(self.args.level)
71+
prefix = self._config_file_prefix(
72+
self.args.show_origin, self.config, self.args.level
73+
)
74+
5775
if remote:
5876
conf = conf["remote"]
5977
self._check(conf, remote, section, opt)
60-
logger.info(conf[section][opt])
78+
logger.info("{}{}".format(prefix, conf[section][opt]))
6179
return 0
6280

6381
with self.config.edit(self.args.level) as conf:
@@ -90,9 +108,21 @@ def _check(self, conf, remote, section, opt=None):
90108
)
91109

92110
@staticmethod
93-
def _format_config(config):
111+
def _format_config(config, prefix=""):
94112
for key, value in flatten(config).items():
95-
yield f"{key}={value}"
113+
yield f"{prefix}{key}={value}"
114+
115+
@staticmethod
116+
def _config_file_prefix(show_origin, config, level):
117+
if not show_origin:
118+
return ""
119+
120+
fname = config.files[level]
121+
122+
if level in ["local", "repo"]:
123+
fname = os.path.relpath(fname, start=Repo.find_root())
124+
125+
return fname + "\t"
96126

97127

98128
parent_config_parser = argparse.ArgumentParser(add_help=False)
@@ -152,4 +182,10 @@ def add_parser(subparsers, parent_parser):
152182
action="store_true",
153183
help="List all defined config values.",
154184
)
185+
config_parser.add_argument(
186+
"--show-origin",
187+
default=False,
188+
action="store_true",
189+
help="Show the source file containing each config value.",
190+
)
155191
config_parser.set_defaults(func=CmdConfig)

tests/func/test_config.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ def _do_test(self, local=False):
4848
self.assertEqual(ret, 0)
4949
self.assertTrue(self._contains(section, field, value, local))
5050

51+
ret = main(base + [section_field, value, "--show-origin"])
52+
self.assertEqual(ret, 1)
53+
5154
ret = main(base + [section_field])
5255
self.assertEqual(ret, 0)
5356

57+
ret = main(base + ["--show-origin", section_field])
58+
self.assertEqual(ret, 0)
59+
5460
ret = main(base + [section_field, newvalue])
5561
self.assertEqual(ret, 0)
5662
self.assertTrue(self._contains(section, field, newvalue, local))
@@ -60,9 +66,15 @@ def _do_test(self, local=False):
6066
self.assertEqual(ret, 0)
6167
self.assertFalse(self._contains(section, field, value, local))
6268

69+
ret = main(base + [section_field, "--unset", "--show-origin"])
70+
self.assertEqual(ret, 1)
71+
6372
ret = main(base + ["--list"])
6473
self.assertEqual(ret, 0)
6574

75+
ret = main(base + ["--list", "--show-origin"])
76+
self.assertEqual(ret, 0)
77+
6678
def test(self):
6779
self._do_test(False)
6880

@@ -174,3 +186,28 @@ def test_config_remote(tmp_dir, dvc, caplog):
174186
caplog.clear()
175187
assert main(["config", "remote.myremote.region"]) == 0
176188
assert "myregion" in caplog.text
189+
190+
191+
def test_config_show_origin(tmp_dir, dvc, caplog):
192+
(tmp_dir / ".dvc" / "config").write_text(
193+
"['remote \"myremote\"']\n"
194+
" url = s3://bucket/path\n"
195+
" region = myregion\n"
196+
)
197+
198+
caplog.clear()
199+
assert main(["config", "--show-origin", "remote.myremote.url"]) == 0
200+
assert (
201+
"{}\t{}\n".format(os.path.join(".dvc", "config"), "s3://bucket/path")
202+
in caplog.text
203+
)
204+
205+
caplog.clear()
206+
assert main(["config", "--list", "--show-origin"]) == 0
207+
assert (
208+
"{}\t{}\n".format(
209+
os.path.join(".dvc", "config"),
210+
"remote.myremote.url=s3://bucket/path",
211+
)
212+
in caplog.text
213+
)

0 commit comments

Comments
 (0)