submodule: allow erroneous values for the fetchRecurseSubmodules option

We should not die when reading the submodule config cache since the user might not be able to get out of that situation when the configuration is part of the history. We should handle this condition later when the value is about to be used. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Heiko Voigt committed Aug 17, 2015 at 17:22 UTC 027771fcb153e0003bcb2d68e1838594a48b0161
6 files changed +66 -17
builtin/fetch.c
+1
@@ -11,6 +11,7 @@
11 #include "run-command.h"
12 #include "parse-options.h"
13 #include "sigchain.h"
14 +#include "submodule-config.h"
15 #include "submodule.h"
16 #include "connected.h"
17 #include "argv-array.h"
submodule-config.c
+28 -1
@@ -204,6 +204,30 @@ static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
204 return submodule;
205 }
206
207 +static int parse_fetch_recurse(const char *opt, const char *arg,
208 + int die_on_error)
209 +{
210 + switch (git_config_maybe_bool(opt, arg)) {
211 + case 1:
212 + return RECURSE_SUBMODULES_ON;
213 + case 0:
214 + return RECURSE_SUBMODULES_OFF;
215 + default:
216 + if (!strcmp(arg, "on-demand"))
217 + return RECURSE_SUBMODULES_ON_DEMAND;
218 +
219 + if (die_on_error)
220 + die("bad %s argument: %s", opt, arg);
221 + else
222 + return RECURSE_SUBMODULES_ERROR;
223 + }
224 +}
225 +
226 +int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
227 +{
228 + return parse_fetch_recurse(opt, arg, 1);
229 +}
230 +
231 static void warn_multiple_config(const unsigned char *commit_sha1,
232 const char *name, const char *option)
233 {
@@ -255,6 +279,8 @@ static int parse_config(const char *var, const char *value, void *data)
279 submodule->path = strbuf_detach(&path, NULL);
280 cache_put_path(me->cache, submodule);
281 } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
282 + /* when parsing worktree configurations we can die early */
283 + int die_on_error = is_null_sha1(me->gitmodules_sha1);
284 if (!me->overwrite &&
285 submodule->fetch_recurse != RECURSE_SUBMODULES_NONE) {
286 warn_multiple_config(me->commit_sha1, submodule->name,
@@ -262,7 +288,8 @@ static int parse_config(const char *var, const char *value, void *data)
288 goto release_return;
289 }
290
265 - submodule->fetch_recurse = parse_fetch_recurse_submodules_arg(var, value);
291 + submodule->fetch_recurse = parse_fetch_recurse(var, value,
292 + die_on_error);
293 } else if (!strcmp(item.buf, "ignore")) {
294 struct strbuf ignore = STRBUF_INIT;
295 if (!me->overwrite && submodule->ignore != NULL) {
submodule-config.h
+1
@@ -18,6 +18,7 @@ struct submodule {
18 unsigned char gitmodules_sha1[20];
19 };
20
21 +int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
22 int parse_submodule_config_option(const char *var, const char *value);
23 const struct submodule *submodule_from_name(const unsigned char *commit_sha1,
24 const char *name);
submodule.c
-15
@@ -288,21 +288,6 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
288 strbuf_release(&sb);
289 }
290
291 -int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
292 -{
293 - switch (git_config_maybe_bool(opt, arg)) {
294 - case 1:
295 - return RECURSE_SUBMODULES_ON;
296 - case 0:
297 - return RECURSE_SUBMODULES_OFF;
298 - default:
299 - if (!strcmp(arg, "on-demand"))
300 - return RECURSE_SUBMODULES_ON_DEMAND;
301 - /* TODO: remove the die for history parsing here */
302 - die("bad %s argument: %s", opt, arg);
303 - }
304 -}
305 -
291 void show_submodule_summary(FILE *f, const char *path,
292 const char *line_prefix,
293 unsigned char one[20], unsigned char two[20],
submodule.h
+1 -1
@@ -5,6 +5,7 @@ struct diff_options;
5 struct argv_array;
6
7 enum {
8 + RECURSE_SUBMODULES_ERROR = -3,
9 RECURSE_SUBMODULES_NONE = -2,
10 RECURSE_SUBMODULES_ON_DEMAND = -1,
11 RECURSE_SUBMODULES_OFF = 0,
@@ -21,7 +22,6 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
22 int submodule_config(const char *var, const char *value, void *cb);
23 void gitmodules_config(void);
24 void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
24 -int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
25 void show_submodule_summary(FILE *f, const char *path,
26 const char *line_prefix,
27 unsigned char one[20], unsigned char two[20],
t/t7411-submodule-config.sh
+35
@@ -115,4 +115,39 @@ test_expect_success 'reading of local configuration' '
115 )
116 '
117
118 +cat >super/expect_fetchrecurse_die.err <<EOF
119 +fatal: bad submodule.submodule.fetchrecursesubmodules argument: blabla
120 +EOF
121 +
122 +test_expect_success 'local error in fetchrecursesubmodule dies early' '
123 + (cd super &&
124 + git config submodule.submodule.fetchrecursesubmodules blabla &&
125 + test_must_fail test-submodule-config \
126 + "" b \
127 + "" submodule \
128 + >actual.out 2>actual.err &&
129 + touch expect_fetchrecurse_die.out &&
130 + test_cmp expect_fetchrecurse_die.out actual.out &&
131 + test_cmp expect_fetchrecurse_die.err actual.err &&
132 + git config --unset submodule.submodule.fetchrecursesubmodules
133 + )
134 +'
135 +
136 +test_expect_success 'error in history in fetchrecursesubmodule lets continue' '
137 + (cd super &&
138 + git config -f .gitmodules \
139 + submodule.submodule.fetchrecursesubmodules blabla &&
140 + git add .gitmodules &&
141 + git config --unset -f .gitmodules \
142 + submodule.submodule.fetchrecursesubmodules &&
143 + git commit -m "add error in fetchrecursesubmodules" &&
144 + test-submodule-config \
145 + HEAD b \
146 + HEAD submodule \
147 + >actual &&
148 + test_cmp expect_error actual &&
149 + git reset --hard HEAD^
150 + )
151 +'
152 +
153 test_done