threads / patch / 8418

patchSupport environment variables in config file

Subject: [PATCH] Support environment variables in config file

## tl;dr

7 messages between Jun 3, 2007 and Jun 4, 2007. Diffs are folded; open one to read it.

replies: 6people: 3as markdown or json

Martin Waitz· Jun 3, 2007, 22:37 UTC · lore

Environment variables (e.g. $HOME) can be helpful for the GIT configuration. With this change you can use them with the normal shell "$" syntax. If you want to insert a plain "$" in a variable, it can be escaped as \$ or put inside quotes (").

Signed-off-by: Martin Waitz <tali@admingilde.org>
---

I found this particularly useful to be able to specify my own global gitignore list via core.excludesfile.

 Documentation/config.txt |   23 +++++++++++++++--------
 config.c                 |   23 +++++++++++++++++++++--
 t/t1300-repo-config.sh   |   13 +++++++++++++
 3 files changed, 49 insertions(+), 10 deletions(-)
Show changes to 3 files +49 −10

Documentation/config.txt, config.c, t/t1300-repo-config.sh

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5868d58..042a354 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -65,17 +65,24 @@ a string, an integer, or a boolean.  Boolean values may be given as yes/no,
 converting value to the canonical form using '--bool' type specifier;
 `git-config` will ensure that the output is "true" or "false".
 
+You can use the $VARIABLE shell syntax to use environment variables
+in the configuration file.  All alpha-numeric characters after the
+leading '`$`' will be interpreted as name of an environment variable
+and the value of this variable will be used instead.
+If the variable does not exist it will be treated as an empty string.
+
 String values may be entirely or partially enclosed in double quotes.
 You need to enclose variable value in double quotes if you want to
 preserve leading or trailing whitespace, or if variable value contains
-beginning of comment characters (if it contains '#' or ';').
-Double quote '`"`' and backslash '`\`' characters in variable value must
-be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'.
-
-The following escape sequences (beside '`\"`' and '`\\`') are recognized:
-'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB)
-and '`\b`' for backspace (BS).  No other char escape sequence, nor octal
-char sequences are valid.
+beginning of comment characters (if it contains '#' or ';') or a dollar
+sign which would be interpreted as a variable.
+Double quote '`"`', backslash '`\`' and dollar '`$`' characters in variable
+value must be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'.
+
+The following escape sequences (beside '`\"`', '`\$"`' and '`\\`') are
+recognized: '`\n`' for newline character (NL), '`\t`' for horizontal tabulation
+(HT, TAB) and '`\b`' for backspace (BS).  No other char escape sequence, nor
+octal char sequences are valid.
 
 Variable value ending in a '`\`' is continued on the next line in the
 customary UNIX fashion.
diff --git a/config.c b/config.c
index 0614c2b..058c0df 100644
--- a/config.c
+++ b/config.c
@@ -43,12 +43,27 @@ static int get_next_char(void)
 static char *parse_value(void)
 {
 	static char value[1024];
-	int quote = 0, comment = 0, len = 0, space = 0;
+	int quote = 0, comment = 0, envvar = -1, len = 0, space = 0;
 
 	for (;;) {
 		int c = get_next_char();
 		if (len >= sizeof(value))
 			return NULL;
+		if ((envvar >= 0) && !isalnum(c)) {
+			const char *var;
+			value[len] = 0;
+			var = getenv(&value[envvar]);
+			if (var) {
+				strncpy(&value[envvar], var,
+				        sizeof(value) - envvar);
+				if (value[sizeof(value)-1])
+					return NULL;
+				len = envvar + strlen(&value[envvar]);
+			} else {
+				len = envvar;
+			}
+			envvar = -1;
+		}
 		if (c == '\n') {
 			if (quote)
 				return NULL;
@@ -66,6 +81,10 @@ static char *parse_value(void)
 				comment = 1;
 				continue;
 			}
+			if (c == '$') {
+				envvar = len;
+				continue;
+			}
 		}
 		if (space) {
 			if (len)
@@ -87,7 +106,7 @@ static char *parse_value(void)
 				c = '\n';
 				break;
 			/* Some characters escape as themselves */
-			case '\\': case '"':
+			case '\\': case '"': case '$':
 				break;
 			/* Reject unknown escape sequences */
 			default:
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 3f3fd2d..eb84437 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -513,5 +513,18 @@ git config --list > result
 
 test_expect_success 'value continued on next line' 'cmp result expect'
 
+cat > .git/config <<\EOF
+[quoted]
+	withvar = "$HOME/foo"
+[unquoted]
+	withvar = $HOME/foo
+EOF
+
+test_expect_success 'quoted $VAR' \
+	'test x"\$HOME/foo" = x$(git config quoted.withvar)'
+
+test_expect_success 'unquoted $VAR' \
+	'test x"$HOME/foo" = x$(git config unquoted.withvar)'
+
 test_done
 
-- 
1.5.2.1.112.gdb0c


-- 
Martin Waitz
Matthias Lederhofer· Jun 4, 2007, 05:34 UTC · re: Martin Waitz · lore

Re: [PATCH] Support environment variables in config file

Martin Waitz <tali@admingilde.org> wrote:
> Environment variables (e.g. $HOME) can be helpful for the GIT configuration.
> With this change you can use them with the normal shell "$" syntax.
> If you want to insert a plain "$" in a variable, it can be escaped as \$
> or put inside quotes (").

Perhaps we should also allow variable interpolation in double quoted strings as this is quite common in various languages.

Show 13 quoted lines
> diff --git a/Documentation/config.txt b/Documentation/config.txt
> index 5868d58..042a354 100644
> --- a/Documentation/config.txt
> +++ b/Documentation/config.txt
> @@ -65,17 +65,24 @@ a string, an integer, or a boolean.  Boolean values may be given as yes/no,
>  converting value to the canonical form using '--bool' type specifier;
>  `git-config` will ensure that the output is "true" or "false".
>  
> +You can use the $VARIABLE shell syntax to use environment variables
> +in the configuration file.  All alpha-numeric characters after the
> +leading '`$`' will be interpreted as name of an environment variable
> +and the value of this variable will be used instead.
> +If the variable does not exist it will be treated as an empty string.

We could have a short example here how to concatenate a variable and a string without a space in between. I came up with '$FOO""bar' which is not that obvious imo.

Show 16 quoted lines
> diff --git a/config.c b/config.c
> index 0614c2b..058c0df 100644
> --- a/config.c
> +++ b/config.c
> @@ -43,12 +43,27 @@ static int get_next_char(void)
>  static char *parse_value(void)
>  {
>  	static char value[1024];
> -	int quote = 0, comment = 0, len = 0, space = 0;
> +	int quote = 0, comment = 0, envvar = -1, len = 0, space = 0;
>  
>  	for (;;) {
>  		int c = get_next_char();
>  		if (len >= sizeof(value))
>  			return NULL;
> +		if ((envvar >= 0) && !isalnum(c)) {
You should allow at least underscores in environment variables too.
Show 22 quoted lines
> diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
> index 3f3fd2d..eb84437 100755
> --- a/t/t1300-repo-config.sh
> +++ b/t/t1300-repo-config.sh
> @@ -513,5 +513,18 @@ git config --list > result
>  
>  test_expect_success 'value continued on next line' 'cmp result expect'
>  
> +cat > .git/config <<\EOF
> +[quoted]
> +	withvar = "$HOME/foo"
> +[unquoted]
> +	withvar = $HOME/foo
> +EOF
> +
> +test_expect_success 'quoted $VAR' \
> +	'test x"\$HOME/foo" = x$(git config quoted.withvar)'
> +
> +test_expect_success 'unquoted $VAR' \
> +	'test x"$HOME/foo" = x$(git config unquoted.withvar)'
> +
>  test_done
If you use the HOME environment variable without setting it yourself
you should place quotes around the $(..) in case there is a space in
$HOME:
    $ ./git-config test.var '$HOME'
    $ export HOME='/tmp/foo bar'
    $ ./git-config test.var
    /tmp/foo bar
    $ test x"$HOME/foo" = x$(./git-config test.var)
    test: 4: bar: unexpected operator
    $ test x"$HOME/foo" = x"$(./git-config test.var)"
Martin Waitz· Jun 4, 2007, 07:27 UTC · re: Matthias Lederhofer · lore

Re: [PATCH] Support environment variables in config file

hoi :)
thanks for the review!

Do you think the approach is ok? Can you see other examples where we may need $VAR support? Or would everybody be happy with support for ~/ in filenames?

On Mon, Jun 04, 2007 at 07:34:43AM +0200, Matthias Lederhofer wrote:
Show 8 quoted lines
> Martin Waitz <tali@admingilde.org> wrote:
> > Environment variables (e.g. $HOME) can be helpful for the GIT configuration.
> > With this change you can use them with the normal shell "$" syntax.
> > If you want to insert a plain "$" in a variable, it can be escaped as \$
> > or put inside quotes (").
> 
> Perhaps we should also allow variable interpolation in double quoted
> strings as this is quite common in various languages.

I thought about that too. I guess I first will have to do a patch which adds single quote (') support.

> We could have a short example here how to concatenate a variable and a
> string without a space in between.  I came up with '$FOO""bar' which
> is not that obvious imo.

yes, shell-like ${FOO} would be nicer but I don't know if it is that important. Perhaps your example $FOO"bar".

> You should allow at least underscores in environment variables too.
right
> If you use the HOME environment variable without setting it yourself
> you should place quotes around the $(..) in case there is a space in
> $HOME:
stupid error, yes.
-- 
Martin Waitz
Matthias Lederhofer· Jun 4, 2007, 08:44 UTC · re: Martin Waitz · lore

Re: [PATCH] Support environment variables in config file

Martin Waitz <tali@admingilde.org> wrote:
> Do you think the approach is ok?
Looks fine from the reading part.  Up to now
    $ git config "$key" "$value" &&
      [ "$value" = "$(git config "$key")" ] &&
      echo true
will echo true for all values (at least from the things I tried with
", \ and \n).  When interpreting $VAR this changes.  I dunno if there
are any programs out there that rely on the fact that the value you
get out of the config is exactly the same as you have put in.
> Can you see other examples where we may need $VAR support?
> Or would everybody be happy with support for ~/ in filenames?

In my config I don't even use the path to my home directory anywhere and spontaneously I can't think of any config option for which I'd use an environment variable as value.

Johannes Schindelin· Jun 4, 2007, 15:57 UTC · re: Martin Waitz · lore

Re: [PATCH] Support environment variables in config file

Hi,
On Mon, 4 Jun 2007, Martin Waitz wrote:
> Do you think the approach is ok?

I actually would like it more if the calling program did the interpolation itself.

So, for example if you want a script to access whatever.my.url, and want to allow to interpolate any environment variable, why not

	url=$(eval $(git config whatever.my.url))

I am just hesitant to change the existing behaviour, and possibly introduce weird breakages. (There could even be some unwanted env leakages in programs like gitweb...)

Ciao, Dscho

Martin Waitz· Jun 4, 2007, 17:47 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Support environment variables in config file

hoi :)
On Mon, Jun 04, 2007 at 04:57:35PM +0100, Johannes Schindelin wrote:
> I actually would like it more if the calling program did the interpolation 
> itself.
That's another possibility, perhaps along the line of git_config_int.
> So, for example if you want a script to access whatever.my.url, and want 
> to allow to interpolate any environment variable, why not
> 
> 	url=$(eval $(git config whatever.my.url))

Well, complete shell syntax does too much: it also supports $() and friends.

> I am just hesitant to change the existing behaviour, and possibly 
> introduce weird breakages. (There could even be some unwanted env leakages 
> in programs like gitweb...)
exactly.

So should we simply update semantics of config variables to not require any environment variables?

-- 
Martin Waitz
Johannes Schindelin· Jun 4, 2007, 17:59 UTC · re: Martin Waitz · lore

Re: [PATCH] Support environment variables in config file

Hi,
On Mon, 4 Jun 2007, Martin Waitz wrote:
Show 5 quoted lines
> On Mon, Jun 04, 2007 at 04:57:35PM +0100, Johannes Schindelin wrote:
> > I actually would like it more if the calling program did the 
> > interpolation itself.
> 
> That's another possibility, perhaps along the line of git_config_int.
Maybe...
Show 7 quoted lines
> > So, for example if you want a script to access whatever.my.url, and 
> > want to allow to interpolate any environment variable, why not
> > 
> > 	url=$(eval $(git config whatever.my.url))
> 
> Well, complete shell syntax does too much: it also supports $() and 
> friends.
Good point.
Show 8 quoted lines
> > I am just hesitant to change the existing behaviour, and possibly 
> > introduce weird breakages. (There could even be some unwanted env 
> > leakages in programs like gitweb...)
> 
> exactly.
> 
> So should we simply update semantics of config variables to not require 
> any environment variables?

Well, actually there is a perfect example when you would want to do even more than just expanding environment variables: aliases.

I'm happy to understand the config as a relatively versatile key/value store, without much in the way of pre- or post-processing from git-config or git_config().

But if there are a few callers of git_config() which want environment variable interpolation, git_config_expand_envs() would be good.

Ciao, Dscho

← back to recent threads