]> git.ipfire.org Git - thirdparty/git.git/commitdiff
config: store "git -c" variables using more robust format
authorPatrick Steinhardt <ps@pks.im>
Tue, 12 Jan 2021 12:27:01 +0000 (13:27 +0100)
committerJunio C Hamano <gitster@pobox.com>
Fri, 15 Jan 2021 21:03:18 +0000 (13:03 -0800)
The previous commit added a new format for $GIT_CONFIG_PARAMETERS which
is able to robustly handle subsections with "=" in them. Let's start
writing the new format. Unfortunately, this does much less than you'd
hope, because "git -c" itself has the same ambiguity problem! But it's
still worth doing:

  - we've now pushed the problem from the inter-process communication
    into the "-c" command-line parser. This would free us up to later
    add an unambiguous format there (e.g., separate arguments like "git
    --config key value", etc).

  - for --config-env, the parser already disallows "=" in the
    environment variable name. So:

      git --config-env section.with=equals.key=ENVVAR

    will robustly set section.with=equals.key to the contents of
    $ENVVAR.

The new test shows the improvement for --config-env.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
config.c
t/t1300-config.sh

index dd559f060b0dd5fa2eb5db363f0bd8ebb9afd9bf..4a490583ad53a714e1c502a8716733849830b893 100644 (file)
--- a/config.c
+++ b/config.c
@@ -332,7 +332,7 @@ int git_config_include(const char *var, const char *value, void *data)
        return ret;
 }
 
-void git_config_push_parameter(const char *text)
+static void git_config_push_split_parameter(const char *key, const char *value)
 {
        struct strbuf env = STRBUF_INIT;
        const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
@@ -340,20 +340,60 @@ void git_config_push_parameter(const char *text)
                strbuf_addstr(&env, old);
                strbuf_addch(&env, ' ');
        }
-       sq_quote_buf(&env, text);
+       sq_quote_buf(&env, key);
+       strbuf_addch(&env, '=');
+       if (value)
+               sq_quote_buf(&env, value);
        setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
        strbuf_release(&env);
 }
 
+void git_config_push_parameter(const char *text)
+{
+       const char *value;
+
+       /*
+        * When we see:
+        *
+        *   section.subsection=with=equals.key=value
+        *
+        * we cannot tell if it means:
+        *
+        *   [section "subsection=with=equals"]
+        *   key = value
+        *
+        * or:
+        *
+        *   [section]
+        *   subsection = with=equals.key=value
+        *
+        * We parse left-to-right for the first "=", meaning we'll prefer to
+        * keep the value intact over the subsection. This is historical, but
+        * also sensible since values are more likely to contain odd or
+        * untrusted input than a section name.
+        *
+        * A missing equals is explicitly allowed (as a bool-only entry).
+        */
+       value = strchr(text, '=');
+       if (value) {
+               char *key = xmemdupz(text, value - text);
+               git_config_push_split_parameter(key, value + 1);
+               free(key);
+       } else {
+               git_config_push_split_parameter(text, NULL);
+       }
+}
+
 void git_config_push_env(const char *spec)
 {
-       struct strbuf buf = STRBUF_INIT;
+       char *key;
        const char *env_name;
        const char *env_value;
 
        env_name = strrchr(spec, '=');
        if (!env_name)
                die(_("invalid config format: %s"), spec);
+       key = xmemdupz(spec, env_name - spec);
        env_name++;
        if (!*env_name)
                die(_("missing environment variable name for configuration '%.*s'"),
@@ -364,10 +404,8 @@ void git_config_push_env(const char *spec)
                die(_("missing environment variable '%s' for configuration '%.*s'"),
                    env_name, (int)(env_name - spec - 1), spec);
 
-       strbuf_add(&buf, spec, env_name - spec);
-       strbuf_addstr(&buf, env_value);
-       git_config_push_parameter(buf.buf);
-       strbuf_release(&buf);
+       git_config_push_split_parameter(key, env_value);
+       free(key);
 }
 
 static inline int iskeychar(int c)
index efdf2bf9975bf1eb81765331538b8ee06567d6d5..cc68b42b972e77168b3d9ef11eeea15431641a75 100755 (executable)
@@ -1416,6 +1416,14 @@ test_expect_success 'git -c and --config-env override each other' '
        test_cmp expect actual
 '
 
+test_expect_success '--config-env handles keys with equals' '
+       echo value=with=equals >expect &&
+       ENVVAR=value=with=equals git \
+               --config-env=section.subsection=with=equals.key=ENVVAR \
+               config section.subsection=with=equals.key >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git config --edit works' '
        git config -f tmp test.value no &&
        echo test.value=yes >expect &&