Web lists-archives.com

Re: [PATCH] builtin/config.c: don't print a newline with --color

Taylor Blau <me@xxxxxxxxxxxx> writes:

> Invocations of 'git config <name>' print a trailing newline after
> writing the value assigned to the given configuration variable.
> This has an unexpected interaction with 63e2a0f8e9 (builtin/config:
> introduce `color` type specifier, 2018-04-09), which causes a newline to
> be printed after a color's ANSI escape sequence.
> In this case, printing a terminating newline is not desirable. Callers
> may want to print out such a configuration variable in a sub-shell in
> order to color something else, in which case they certainly don't want a
> newline.
> This bug has survived because there was never a test that would have
> caught it. The old test used 'test_decode_color', which checks that its
> input begins with a color, but stops parsing once it has parsed a single
> color successfully. In this case, it was ignoring the trailing '\n'.

The output from "git config" plumbing command were designed to help
people writing shell scripts Porcelain around it, so the expected
use for them has always been

	ERR=$(git config --type=color --default=red ui.color.error)
	... some time later ..
	echo "${ERR}this is an error message"

where the first assignment will strip the final LF (i.e. the value
of the $ERR variable does not have it).

An interesting aspect of the above is that this is *NOT* limited to
colors.  Regardless of the type you are reading, be it an int or a
bool, VAR=$(git config ...) will strip the trailing LF, and existing
scripts people have do rely on that, i.e. when people write

	VAR=$(git config ...)
	echo "var setting is $VAR"

they rely on VAR=$(...) assignment to strip trailing LF and echo to
add a final LF to the string.

So if we are going to change anything, the change MUST NOT single
out "color".  IOW, the title of the patch already tells us that it
is giving a wrong solution.

Whether you limit it to color or not, to Porcelain writers who are
writing in shell, I suspect that the code after the proposed change
will not be a huge regression.  VAR=$(git config ...) assignment,
when the output from the command ends without the final LF (i.e. an
incomplete line), will keep the string intact, so the behaviour of
these shell scripts would not change.

If an existing Porcelain script were written in Perl and uses chop
to strip the last LF coming out of "git config", however, the
proposed change WILL BREAK such a script.

Needless to say, "using chop in Perl is wrong to begin with" misses
the point from two directions---(1) 'chop in Perl' is a mere
example---scripts not written in Perl using chop may still rely on
the existing behaviour that the output always has the final LF, and
(2) even if we agree that using chop in Perl is a bad idea, such a
script has happily been working, and suddenly breaking it is a
regression no matter what.

So, I am not hugely enthused by this change, even though I am
somewhat sympathetic to it, as it would help one narrow use case,
i.e. "interpolation".

	cat <<EOF
	$(git config ...)Foo Bar$(git config ...)


		git config ...
		echo Foo Bar
                git config ...

would lack LF before Foo automatically, and forcing those who want
to have LF to add it manually would sound easier than forcing those
who want to strip LF when they do not want it.

But when you are making a list, getting the final LF for free is a
feature, so it cuts both ways.