Thread (20 messages) flat view 20 messages, 5 authors, 2016-06-15

Re: [PATCH v3 3/3] config: add '--show-origin' option to print the origin of a config value

From: Lars Schneider <hidden>
Date: 2016-06-15 23:08:13

On 13 Feb 2016, at 18:44, Jeff King [off-list ref] wrote:
On Sat, Feb 13, 2016 at 03:24:16PM +0100, larsxschneider@gmail.com wrote:
quoted
From: Lars Schneider <redacted>

If config values are queried using 'git config' (e.g. via --get,
--get-all, --get-regexp, or --list flag) then it is sometimes hard to
find the configuration file where the values were defined.

Teach 'git config' the '--show-origin' option to print the source
configuration file for every printed value.
Thanks, I think this version fixes the correctness issues I mentioned
earlier. I do still have nits to pick (of course :) ), that we may or
may not want to deal with.
quoted
+static void show_config_origin(struct strbuf *buf)
+{
+	const char term = end_null ? '\0' : '\t';
+	const char *type;
+	const char *name;
+
+	current_config_type_name(&type, &name);
This double out-parameter feels like a clunky interface.

I was tempted to suggest that we simply make the "struct config_source"
available to builtin/config.c (which is already pretty intimate with the
rest of the config code), and then it can pick out what it wants. But
there _is_ some logic in the function to convert the NULL "cf" into
"cmdline".

Perhaps it would be simpler to just have two accessor functions, and do:

 strbuf_addstr(buf, current_config_type());
 ...
 strbuf_addstr(buf, current_config_name());

I admit it is a pretty minor point, though.
Agreed, this looks nicer.

quoted
static int show_all_config(const char *key_, const char *value_, void *cb)
{
+	if (show_origin) {
+       struct strbuf buf = STRBUF_INIT;
+       show_config_origin(&buf);
+       fwrite(buf.buf, 1, buf.len, stdout);
+       strbuf_release(&buf);
+	}
The indentation is funky here.
True! Indentation without intention :-) 
The use of fwrite() to catch the embedded NULs is subtle enough that it
might be worth a comment.

It also made me wonder how format_config() handles this. It looks like
we send the result eventually to fwrite() there, so it all works (and it
does _not_ have the comment I mentioned :) ).
I will add a comment in both places :-)

quoted
+test_expect_success '--show-origin' '
+	>.git/config &&
+	>"$HOME"/.gitconfig &&
+	INCLUDE_DIR="$HOME/include" &&
+	mkdir -p "$INCLUDE_DIR" &&
+	cat >"$INCLUDE_DIR"/absolute.include <<-EOF &&
+		[user]
+			absolute = include
+	EOF
+	cat >"$INCLUDE_DIR"/relative.include <<-EOF &&
+		[user]
+			relative = include
+	EOF
+	test_config_global user.global "true" &&
+	test_config_global user.override "global" &&
+	test_config_global include.path "$INCLUDE_DIR"/absolute.include &&
+	test_config include.path ../include/relative.include &&
+	test_config user.local "true" &&
+	test_config user.override "local" &&
+
+	cat >expect <<-EOF &&
+		file:$HOME/.gitconfig	user.global=true
+		file:$HOME/.gitconfig	user.override=global
+		file:$HOME/.gitconfig	include.path=$INCLUDE_DIR/absolute.include
+		file:$INCLUDE_DIR/absolute.include	user.absolute=include
+		file:.git/config	include.path=../include/relative.include
+		file:.git/../include/relative.include	user.relative=include
+		file:.git/config	user.local=true
+		file:.git/config	user.override=local
+		cmdline:	user.cmdline=true
+	EOF
+	git -c user.cmdline=true config --list --show-origin >output &&
+	test_cmp expect output &&
+
+	cat >expect <<-EOF &&
+		file:$HOME/.gitconfigQuser.global
+		trueQfile:$HOME/.gitconfigQuser.override
+		globalQfile:$HOME/.gitconfigQinclude.path
+		$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
+		includeQfile:.git/configQinclude.path
+		../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
+		includeQfile:.git/configQuser.local
+		trueQfile:.git/configQuser.override
+		localQcmdline:Quser.cmdline
+		trueQ
+	EOF
I see you split this up more, but there's still quite a bit going on in
this one block. IMHO, it would be more customary in our tests to put the
setup into one test_expect_success block, then each of these
expect-run-cmp blocks into their own test_expect_success.

It does mean that the setup mutates the global test state for further
tests (and you should stop using test_config_*, which clean up at the
end of the block), but I think that's the right thing here. The point of
test_config is "flip on this switch just for a moment, so we can test
its effect without hurting further tests". But these are config tests in
the first place, and it is OK for them to show a progression of
mutations of the config (you'll note that like the other tests in this
script, you are clearing out .git/config in the first place).
TBH I am always a little annoyed if Git tests depend on each other. It makes
it harder to just disable all uninteresting tests and only focus on the one that 
I am working with. However, I agree with your point that the test block does too
many things. Would it be OK if I write a bash function that performs the test
setup? Then I would call this function in the beginning of every individual 
test. Or do you prefer the global state strategy?

Thanks,
Lars
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help