submodule: add die_in_unpopulated_submodule function

Currently 'git add' is the only command which dies when launched from an unpopulated submodule (the place-holder directory for a submodule which hasn't been checked out). This is triggered implicitly by passing the PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE flag to 'parse_pathspec()'. Instead make this desire more explicit by creating a function 'die_in_unpopulated_submodule()' which dies if the provided 'prefix' has a leading path component which matches a submodule in the the index. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed May 9, 2017 at 12:17 UTC bdab972153a73815e04e9699406433e409ed28ab
5 files changed +36 -34
builtin/add.c
+3
@@ -17,6 +17,7 @@
17 #include "revision.h"
18 #include "bulk-checkin.h"
19 #include "argv-array.h"
20 +#include "submodule.h"
21
22 static const char * const builtin_add_usage[] = {
23 N_("git add [<options>] [--] <pathspec>..."),
@@ -379,6 +380,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
380 if (read_cache() < 0)
381 die(_("index file corrupt"));
382
383 + die_in_unpopulated_submodule(&the_index, prefix);
384 +
385 /*
386 * Check the "pathspec '%s' did not match any files" block
387 * below before enabling new magic.
pathspec.c
-29
@@ -424,27 +424,6 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)
424 }
425 }
426
427 -static void die_inside_submodule_path(struct pathspec_item *item)
428 -{
429 - int i;
430 -
431 - for (i = 0; i < active_nr; i++) {
432 - struct cache_entry *ce = active_cache[i];
433 - int ce_len = ce_namelen(ce);
434 -
435 - if (!S_ISGITLINK(ce->ce_mode))
436 - continue;
437 -
438 - if (item->len < ce_len ||
439 - !(item->match[ce_len] == '/' || item->match[ce_len] == '\0') ||
440 - memcmp(ce->name, item->match, ce_len))
441 - continue;
442 -
443 - die(_("Pathspec '%s' is in submodule '%.*s'"),
444 - item->original, ce_len, ce->name);
445 - }
446 -}
447 -
427 /*
428 * Perform the initialization of a pathspec_item based on a pathspec element.
429 */
@@ -547,14 +526,6 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
526 /* sanity checks, pathspec matchers assume these are sane */
527 if (item->nowildcard_len > item->len ||
528 item->prefix > item->len) {
550 - /*
551 - * This case can be triggered by the user pointing us to a
552 - * pathspec inside a submodule, which is an input error.
553 - * Detect that here and complain, but fallback in the
554 - * non-submodule case to a BUG, as we have no idea what
555 - * would trigger that.
556 - */
557 - die_inside_submodule_path(item);
529 die ("BUG: error initializing pathspec_item");
530 }
531 }
submodule.c
+30
@@ -282,6 +282,36 @@ int is_submodule_populated_gently(const char *path, int *return_error_code)
282 return ret;
283 }
284
285 +/*
286 + * Dies if the provided 'prefix' corresponds to an unpopulated submodule
287 + */
288 +void die_in_unpopulated_submodule(const struct index_state *istate,
289 + const char *prefix)
290 +{
291 + int i, prefixlen;
292 +
293 + if (!prefix)
294 + return;
295 +
296 + prefixlen = strlen(prefix);
297 +
298 + for (i = 0; i < istate->cache_nr; i++) {
299 + struct cache_entry *ce = istate->cache[i];
300 + int ce_len = ce_namelen(ce);
301 +
302 + if (!S_ISGITLINK(ce->ce_mode))
303 + continue;
304 + if (prefixlen <= ce_len)
305 + continue;
306 + if (strncmp(ce->name, prefix, ce_len))
307 + continue;
308 + if (prefix[ce_len] != '/')
309 + continue;
310 +
311 + die(_("in unpopulated submodule '%s'"), ce->name);
312 + }
313 +}
314 +
315 int parse_submodule_update_strategy(const char *value,
316 struct submodule_update_strategy *dst)
317 {
submodule.h
+2
@@ -49,6 +49,8 @@ extern int is_submodule_initialized(const char *path);
49 * Otherwise the return error code is the same as of resolve_gitdir_gently.
50 */
51 extern int is_submodule_populated_gently(const char *path, int *return_error_code);
52 +extern void die_in_unpopulated_submodule(const struct index_state *istate,
53 + const char *prefix);
54 extern int parse_submodule_update_strategy(const char *value,
55 struct submodule_update_strategy *dst);
56 extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
t/t6134-pathspec-in-submodule.sh
+1 -5
@@ -24,13 +24,9 @@ test_expect_success 'error message for path inside submodule' '
24 test_cmp expect actual
25 '
26
27 -cat <<EOF >expect
28 -fatal: Pathspec '.' is in submodule 'sub'
29 -EOF
30 -
27 test_expect_success 'error message for path inside submodule from within submodule' '
28 test_must_fail git -C sub add . 2>actual &&
33 - test_cmp expect actual
29 + test_i18ngrep "in unpopulated submodule" actual
30 '
31
32 test_done