static int clone_submodule(const char *path, const char *gitdir, const char *url, const char *depth, const char *reference, int quiet) { struct child_process cp; child_process_init(&cp); argv_array_push(&cp.args, "clone"); argv_array_push(&cp.args, "--no-checkout"); if (quiet) argv_array_push(&cp.args, "--quiet"); if (depth && *depth) argv_array_pushl(&cp.args, "--depth", depth, NULL); if (reference && *reference) argv_array_pushl(&cp.args, "--reference", reference, NULL); if (gitdir && *gitdir) argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL); argv_array_push(&cp.args, url); argv_array_push(&cp.args, path); cp.git_cmd = 1; prepare_submodule_repo_env(&cp.env_array); cp.no_stdin = 1; return run_command(&cp); }
static int clone_submodule(const char *path, const char *gitdir, const char *url, const char *depth, struct string_list *reference, int quiet, int progress) { struct child_process cp = CHILD_PROCESS_INIT; argv_array_push(&cp.args, "clone"); argv_array_push(&cp.args, "--no-checkout"); if (quiet) argv_array_push(&cp.args, "--quiet"); if (progress) argv_array_push(&cp.args, "--progress"); if (depth && *depth) argv_array_pushl(&cp.args, "--depth", depth, NULL); if (reference->nr) { struct string_list_item *item; for_each_string_list_item(item, reference) argv_array_pushl(&cp.args, "--reference", item->string, NULL); } if (gitdir && *gitdir) argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL); argv_array_push(&cp.args, url); argv_array_push(&cp.args, path); cp.git_cmd = 1; prepare_submodule_repo_env(&cp.env_array); cp.no_stdin = 1; return run_command(&cp); }
int submodule_uses_gitfile(const char *path) { struct child_process cp = CHILD_PROCESS_INIT; 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 */ cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); 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; }
static int submodule_needs_pushing(const char *path, const unsigned char sha1[20]) { if (add_submodule_odb(path) || !lookup_commit_reference(sha1)) return 0; if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) { struct child_process cp = CHILD_PROCESS_INIT; const char *argv[] = {"rev-list", NULL, "--not", "--remotes", "-n", "1" , NULL}; struct strbuf buf = STRBUF_INIT; int needs_pushing = 0; argv[1] = sha1_to_hex(sha1); cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; cp.out = -1; cp.dir = path; if (start_command(&cp)) die("Could not run 'git rev-list %s --not --remotes -n 1' command in submodule %s", sha1_to_hex(sha1), path); if (strbuf_read(&buf, cp.out, 41)) needs_pushing = 1; finish_command(&cp); close(cp.out); strbuf_release(&buf); return needs_pushing; } return 0; }
static int push_submodule(const char *path) { if (add_submodule_odb(path)) return 1; if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) { struct child_process cp = CHILD_PROCESS_INIT; const char *argv[] = {"push", NULL}; cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; cp.dir = path; if (run_command(&cp)) return 0; close(cp.out); } return 1; }
int ok_to_remove_submodule(const char *path) { ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; const char *argv[] = { "status", "--porcelain", "-u", "--ignore-submodules=none", NULL, }; struct strbuf buf = STRBUF_INIT; int ok_to_remove = 1; if (!file_exists(path) || is_empty_dir(path)) return 1; if (!submodule_uses_gitfile(path)) return 0; cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); 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 is_submodule_commit_present(const char *path, unsigned char sha1[20]) { int is_present = 0; if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) { /* Even if the submodule is checked out and the commit is * present, make sure it is reachable from a ref. */ struct child_process cp = CHILD_PROCESS_INIT; const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL}; struct strbuf buf = STRBUF_INIT; argv[3] = sha1_to_hex(sha1); cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; cp.dir = path; if (!capture_command(&cp, &buf, 1024) && !buf.len) is_present = 1; strbuf_release(&buf); } return is_present; }
/* * Launch child process to grep contents of a submodule */ static int grep_submodule_launch(struct grep_opt *opt, const struct grep_source *gs) { struct child_process cp = CHILD_PROCESS_INIT; int status, i; const char *end_of_base; const char *name; struct work_item *w = opt->output_priv; end_of_base = strchr(gs->name, ':'); if (gs->identifier && end_of_base) name = end_of_base + 1; else name = gs->name; prepare_submodule_repo_env(&cp.env_array); argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); /* Add super prefix */ argv_array_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ? super_prefix : "", name); argv_array_push(&cp.args, "grep"); /* * Add basename of parent project * When performing grep on a tree object the filename is prefixed * with the object's name: 'tree-name:filename'. In order to * provide uniformity of output we want to pass the name of the * parent project's object name to the submodule so the submodule can * prefix its output with the parent's name and not its own SHA1. */ if (gs->identifier && end_of_base) argv_array_pushf(&cp.args, "--parent-basename=%.*s", (int) (end_of_base - gs->name), gs->name); /* Add options */ for (i = 0; i < submodule_options.argc; i++) { /* * If there is a tree identifier for the submodule, add the * rev after adding the submodule options but before the * pathspecs. To do this we listen for the '--' and insert the * sha1 before pushing the '--' onto the child process argv * array. */ if (gs->identifier && !strcmp("--", submodule_options.argv[i])) { argv_array_push(&cp.args, sha1_to_hex(gs->identifier)); } argv_array_push(&cp.args, submodule_options.argv[i]); } cp.git_cmd = 1; cp.dir = gs->path; /* * Capture output to output buffer and check the return code from the * child process. A '0' indicates a hit, a '1' indicates no hit and * anything else is an error. */ status = capture_command(&cp, &w->out, 0); if (status && (status != 1)) { /* flush the buffer */ write_or_die(1, w->out.buf, w->out.len); die("process for submodule '%s' failed with exit code: %d", gs->name, status); } /* invert the return code to make a hit equal to 1 */ return !status; }
unsigned is_submodule_modified(const char *path, int ignore_untracked) { ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; const char *argv[] = { "status", "--porcelain", NULL, NULL, }; struct strbuf buf = STRBUF_INIT; unsigned dirty_submodule = 0; const char *line, *next_line; const char *git_dir; strbuf_addf(&buf, "%s/.git", path); git_dir = read_gitfile(buf.buf); if (!git_dir) git_dir = buf.buf; if (!is_directory(git_dir)) { strbuf_release(&buf); /* The submodule is not checked out, so it is not modified */ return 0; } strbuf_reset(&buf); if (ignore_untracked) argv[2] = "-uno"; cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); 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' in submodule %s", path); len = strbuf_read(&buf, cp.out, 1024); line = buf.buf; while (len > 2) { if ((line[0] == '?') && (line[1] == '?')) { dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) break; } else { dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; if (ignore_untracked || (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)) break; } next_line = strchr(line, '\n'); if (!next_line) break; next_line++; len -= (next_line - line); line = next_line; } close(cp.out); if (finish_command(&cp)) die("'git status --porcelain' failed in submodule %s", path); strbuf_release(&buf); return dirty_submodule; }
static int get_next_submodule(struct child_process *cp, struct strbuf *err, void *data, void **task_cb) { int ret = 0; struct submodule_parallel_fetch *spf = data; for (; spf->count < active_nr; spf->count++) { struct strbuf submodule_path = STRBUF_INIT; struct strbuf submodule_git_dir = STRBUF_INIT; struct strbuf submodule_prefix = STRBUF_INIT; const struct cache_entry *ce = active_cache[spf->count]; const char *git_dir, *default_argv; const struct submodule *submodule; if (!S_ISGITLINK(ce->ce_mode)) continue; submodule = submodule_from_path(null_sha1, ce->name); if (!submodule) submodule = submodule_from_name(null_sha1, ce->name); default_argv = "yes"; if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) { if (submodule && submodule->fetch_recurse != RECURSE_SUBMODULES_NONE) { if (submodule->fetch_recurse == RECURSE_SUBMODULES_OFF) continue; if (submodule->fetch_recurse == RECURSE_SUBMODULES_ON_DEMAND) { if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) continue; default_argv = "on-demand"; } } else { if ((config_fetch_recurse_submodules == RECURSE_SUBMODULES_OFF) || gitmodules_is_unmerged) continue; if (config_fetch_recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) { if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) continue; default_argv = "on-demand"; } } } else if (spf->command_line_option == RECURSE_SUBMODULES_ON_DEMAND) { if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name)) continue; default_argv = "on-demand"; } strbuf_addf(&submodule_path, "%s/%s", spf->work_tree, ce->name); strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf); strbuf_addf(&submodule_prefix, "%s%s/", spf->prefix, ce->name); git_dir = read_gitfile(submodule_git_dir.buf); if (!git_dir) git_dir = submodule_git_dir.buf; if (is_directory(git_dir)) { child_process_init(cp); cp->dir = strbuf_detach(&submodule_path, NULL); prepare_submodule_repo_env(&cp->env_array); cp->git_cmd = 1; if (!spf->quiet) strbuf_addf(err, "Fetching submodule %s%s\n", spf->prefix, ce->name); argv_array_init(&cp->args); argv_array_pushv(&cp->args, spf->args.argv); argv_array_push(&cp->args, default_argv); argv_array_push(&cp->args, "--submodule-prefix"); argv_array_push(&cp->args, submodule_prefix.buf); ret = 1; } strbuf_release(&submodule_path); strbuf_release(&submodule_git_dir); strbuf_release(&submodule_prefix); if (ret) { spf->count++; return 1; } } return 0; }