diff options
Diffstat (limited to 'submodule.c')
-rw-r--r-- | submodule.c | 160 |
1 files changed, 121 insertions, 39 deletions
diff --git a/submodule.c b/submodule.c index 50f213e926..1821a5b316 100644 --- a/submodule.c +++ b/submodule.c @@ -126,45 +126,44 @@ void gitmodules_config(void) int parse_submodule_config_option(const char *var, const char *value) { - int len; struct string_list_item *config; - struct strbuf submodname = STRBUF_INIT; + const char *name, *key; + int namelen; - var += 10; /* Skip "submodule." */ + if (parse_config_key(var, "submodule", &name, &namelen, &key) < 0 || !name) + return 0; - len = strlen(var); - if ((len > 5) && !strcmp(var + len - 5, ".path")) { - strbuf_add(&submodname, var, len - 5); + if (!strcmp(key, "path")) { config = unsorted_string_list_lookup(&config_name_for_path, value); if (config) free(config->util); else config = string_list_append(&config_name_for_path, xstrdup(value)); - config->util = strbuf_detach(&submodname, NULL); - strbuf_release(&submodname); - } else if ((len > 23) && !strcmp(var + len - 23, ".fetchrecursesubmodules")) { - strbuf_add(&submodname, var, len - 23); - config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, submodname.buf); + config->util = xmemdupz(name, namelen); + } else if (!strcmp(key, "fetchrecursesubmodules")) { + char *name_cstr = xmemdupz(name, namelen); + config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name_cstr); if (!config) - config = string_list_append(&config_fetch_recurse_submodules_for_name, - strbuf_detach(&submodname, NULL)); + config = string_list_append(&config_fetch_recurse_submodules_for_name, name_cstr); + else + free(name_cstr); config->util = (void *)(intptr_t)parse_fetch_recurse_submodules_arg(var, value); - strbuf_release(&submodname); - } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { + } else if (!strcmp(key, "ignore")) { + char *name_cstr; + if (strcmp(value, "untracked") && strcmp(value, "dirty") && strcmp(value, "all") && strcmp(value, "none")) { warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var); return 0; } - strbuf_add(&submodname, var, len - 7); - config = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf); - if (config) + name_cstr = xmemdupz(name, namelen); + config = unsorted_string_list_lookup(&config_ignore_for_name, name_cstr); + if (config) { free(config->util); - else - config = string_list_append(&config_ignore_for_name, - strbuf_detach(&submodname, NULL)); - strbuf_release(&submodname); + free(name_cstr); + } else + config = string_list_append(&config_ignore_for_name, name_cstr); config->util = xstrdup(value); return 0; } @@ -217,6 +216,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path, } static void print_submodule_summary(struct rev_info *rev, FILE *f, + const char *line_prefix, const char *del, const char *add, const char *reset) { static const char format[] = " %m %s"; @@ -227,6 +227,7 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f, struct pretty_print_context ctx = {0}; ctx.date_mode = rev->date_mode; strbuf_setlen(&sb, 0); + strbuf_addstr(&sb, line_prefix); if (commit->object.flags & SYMMETRIC_LEFT) { if (del) strbuf_addstr(&sb, del); @@ -257,12 +258,13 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg) } void show_submodule_summary(FILE *f, const char *path, + const char *line_prefix, unsigned char one[20], unsigned char two[20], - unsigned dirty_submodule, + unsigned dirty_submodule, const char *meta, const char *del, const char *add, const char *reset) { struct rev_info rev; - struct commit *left = left, *right = right; + struct commit *left = NULL, *right = NULL; const char *message = NULL; struct strbuf sb = STRBUF_INIT; int fast_forward = 0, fast_backward = 0; @@ -276,38 +278,39 @@ void show_submodule_summary(FILE *f, const char *path, else if (!(left = lookup_commit_reference(one)) || !(right = lookup_commit_reference(two))) message = "(commits not present)"; - - if (!message && - prepare_submodule_summary(&rev, path, left, right, - &fast_forward, &fast_backward)) + else if (prepare_submodule_summary(&rev, path, left, right, + &fast_forward, &fast_backward)) message = "(revision walker failed)"; if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) - fprintf(f, "Submodule %s contains untracked content\n", path); + fprintf(f, "%sSubmodule %s contains untracked content\n", + line_prefix, path); if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - fprintf(f, "Submodule %s contains modified content\n", path); + fprintf(f, "%sSubmodule %s contains modified content\n", + line_prefix, path); if (!hashcmp(one, two)) { strbuf_release(&sb); return; } - strbuf_addf(&sb, "Submodule %s %s..", path, + strbuf_addf(&sb, "%s%sSubmodule %s %s..", line_prefix, meta, path, find_unique_abbrev(one, DEFAULT_ABBREV)); if (!fast_backward && !fast_forward) strbuf_addch(&sb, '.'); strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV)); if (message) - strbuf_addf(&sb, " %s\n", message); + strbuf_addf(&sb, " %s%s\n", message, reset); else - strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : ""); + strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset); fwrite(sb.buf, sb.len, 1, f); - if (!message) { - print_submodule_summary(&rev, f, del, add, reset); + if (!message) /* only NULL if we succeeded in setting up the walk */ + print_submodule_summary(&rev, f, line_prefix, del, add, reset); + if (left) clear_commit_marks(left, ~0); + if (right) clear_commit_marks(right, ~0); - } strbuf_release(&sb); } @@ -600,9 +603,8 @@ int fetch_populated_submodules(const struct argv_array *options, if (!work_tree) goto out; - if (!the_index.initialized) - if (read_cache() < 0) - die("index file corrupt"); + if (read_cache() < 0) + die("index file corrupt"); argv_array_push(&argv, "fetch"); for (i = 0; i < options->argc; i++) @@ -759,6 +761,86 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) return dirty_submodule; } +int submodule_uses_gitfile(const char *path) +{ + struct child_process cp; + const char *argv[] = { + "submodule", + "foreach", + "--quiet", + "--recursive", + "test -f .git", + NULL, + }; + struct strbuf buf = STRBUF_INIT; + const char *git_dir; + + strbuf_addf(&buf, "%s/.git", path); + git_dir = read_gitfile(buf.buf); + if (!git_dir) { + strbuf_release(&buf); + return 0; + } + strbuf_release(&buf); + + /* Now test that all nested submodules use a gitfile too */ + memset(&cp, 0, sizeof(cp)); + cp.argv = argv; + cp.env = local_repo_env; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.no_stderr = 1; + cp.no_stdout = 1; + cp.dir = path; + if (run_command(&cp)) + return 0; + + return 1; +} + +int ok_to_remove_submodule(const char *path) +{ + struct stat st; + ssize_t len; + struct child_process cp; + const char *argv[] = { + "status", + "--porcelain", + "-u", + "--ignore-submodules=none", + NULL, + }; + struct strbuf buf = STRBUF_INIT; + int ok_to_remove = 1; + + if ((lstat(path, &st) < 0) || is_empty_dir(path)) + return 1; + + if (!submodule_uses_gitfile(path)) + return 0; + + memset(&cp, 0, sizeof(cp)); + cp.argv = argv; + cp.env = local_repo_env; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.out = -1; + cp.dir = path; + if (start_command(&cp)) + die("Could not run 'git status --porcelain -uall --ignore-submodules=none' in submodule %s", path); + + len = strbuf_read(&buf, cp.out, 1024); + if (len > 2) + ok_to_remove = 0; + close(cp.out); + + if (finish_command(&cp)) + die("'git status --porcelain -uall --ignore-submodules=none' failed in submodule %s", path); + + strbuf_release(&buf); + return ok_to_remove; +} + static int find_first_merges(struct object_array *result, const char *path, struct commit *a, struct commit *b) { |