config: use git_config_parse_key() in git_config_parse_parameter()

The parsing of one-shot assignments of configuration variables that come from the command line historically was quite loose and allowed anything to pass. It also downcased everything in the variable name, even a three-level <section>.<subsection>.<variable> name in which the <subsection> part must be treated in a case sensitive manner. Existing git_config_parse_key() helper is used to parse the variable name that comes from the command line, i.e. "git config VAR VAL", and handles these details correctly. Replace the strbuf_tolower() call in git_config_parse_parameter() with a call to it to correct both issues. git_config_parse_key() does a bit more things that are not necessary for the purpose of this codepath (e.g. it allocates a separate buffer to return the canonicalized variable name because it takes a "const char *" input), but we are not in a performance-critical codepath here. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Feb 23, 2017 at 15:04 UTC 1274a155af96fcbcf2e60ae9fc9ee8dbdbbe987a
2 files changed +71 -5
config.c
+9 -5
@@ -295,7 +295,9 @@ int git_config_parse_parameter(const char *text,
295 config_fn_t fn, void *data)
296 {
297 const char *value;
298 + char *canonical_name;
299 struct strbuf **pair;
300 + int ret;
301
302 pair = strbuf_split_str(text, '=', 2);
303 if (!pair[0])
@@ -313,13 +315,15 @@ int git_config_parse_parameter(const char *text,
315 strbuf_list_free(pair);
316 return error("bogus config parameter: %s", text);
317 }
316 - strbuf_tolower(pair[0]);
317 - if (fn(pair[0]->buf, value, data) < 0) {
318 - strbuf_list_free(pair);
319 - return -1;
318 +
319 + if (git_config_parse_key(pair[0]->buf, &canonical_name, NULL)) {
320 + ret = -1;
321 + } else {
322 + ret = (fn(canonical_name, value, data) < 0) ? -1 : 0;
323 + free(canonical_name);
324 }
325 strbuf_list_free(pair);
322 - return 0;
326 + return ret;
327 }
328
329 int git_config_from_parameters(config_fn_t fn, void *data)
t/t1300-repo-config.sh
+62
@@ -1097,6 +1097,68 @@ test_expect_success 'multiple git -c appends config' '
1097 test_cmp expect actual
1098 '
1099
1100 +test_expect_success 'last one wins: two level vars' '
1101 +
1102 + # sec.var and sec.VAR are the same variable, as the first
1103 + # and the last level of a configuration variable name is
1104 + # case insensitive.
1105 +
1106 + echo VAL >expect &&
1107 +
1108 + git -c sec.var=val -c sec.VAR=VAL config --get sec.var >actual &&
1109 + test_cmp expect actual &&
1110 + git -c SEC.var=val -c sec.var=VAL config --get sec.var >actual &&
1111 + test_cmp expect actual &&
1112 +
1113 + git -c sec.var=val -c sec.VAR=VAL config --get SEC.var >actual &&
1114 + test_cmp expect actual &&
1115 + git -c SEC.var=val -c sec.var=VAL config --get sec.VAR >actual &&
1116 + test_cmp expect actual
1117 +'
1118 +
1119 +test_expect_success 'last one wins: three level vars' '
1120 +
1121 + # v.a.r and v.A.r are not the same variable, as the middle
1122 + # level of a three-level configuration variable name is
1123 + # case sensitive.
1124 +
1125 + echo val >expect &&
1126 + git -c v.a.r=val -c v.A.r=VAL config --get v.a.r >actual &&
1127 + test_cmp expect actual &&
1128 + git -c v.a.r=val -c v.A.r=VAL config --get V.a.R >actual &&
1129 + test_cmp expect actual &&
1130 +
1131 + # v.a.r and V.a.R are the same variable, as the first
1132 + # and the last level of a configuration variable name is
1133 + # case insensitive.
1134 +
1135 + echo VAL >expect &&
1136 + git -c v.a.r=val -c v.a.R=VAL config --get v.a.r >actual &&
1137 + test_cmp expect actual &&
1138 + git -c v.a.r=val -c V.a.r=VAL config --get v.a.r >actual &&
1139 + test_cmp expect actual &&
1140 + git -c v.a.r=val -c v.a.R=VAL config --get V.a.R >actual &&
1141 + test_cmp expect actual &&
1142 + git -c v.a.r=val -c V.a.r=VAL config --get V.a.R >actual &&
1143 + test_cmp expect actual
1144 +'
1145 +
1146 +for VAR in a .a a. a.0b a."b c". a."b c".0d
1147 +do
1148 + test_expect_success "git -c $VAR=VAL rejects invalid '$VAR'" '
1149 + test_must_fail git -c "$VAR=VAL" config -l
1150 + '
1151 +done
1152 +
1153 +for VAR in a.b a."b c".d
1154 +do
1155 + test_expect_success "git -c $VAR=VAL works with valid '$VAR'" '
1156 + echo VAL >expect &&
1157 + git -c "$VAR=VAL" config --get "$VAR" >actual &&
1158 + test_cmp expect actual
1159 + '
1160 +done
1161 +
1162 test_expect_success 'git -c is not confused by empty environment' '
1163 GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
1164 '