Merge branch 'gc/submodule-update-part2'
Move more "git submodule update" to C. * gc/submodule-update-part2: submodule--helper: remove forward declaration submodule: move core cmd_update() logic to C submodule--helper: reduce logic in run_update_procedure() submodule--helper: teach update_data more options builtin/submodule--helper.c: rename option struct to "opt" submodule update: use die_message() submodule--helper: run update using child process struct
This commit is contained in:
commit
cf0e875cd8
@ -1643,7 +1643,10 @@ struct module_clone_data {
|
||||
unsigned int require_init: 1;
|
||||
int single_branch;
|
||||
};
|
||||
#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
|
||||
#define MODULE_CLONE_DATA_INIT { \
|
||||
.reference = STRING_LIST_INIT_NODUP, \
|
||||
.single_branch = -1, \
|
||||
}
|
||||
|
||||
struct submodule_alternate_setup {
|
||||
const char *submodule_name;
|
||||
@ -1967,28 +1970,13 @@ struct update_clone_data {
|
||||
};
|
||||
|
||||
struct submodule_update_clone {
|
||||
/* index into 'list', the list of submodules to look into for cloning */
|
||||
/* index into 'update_data.list', the list of submodules to look into for cloning */
|
||||
int current;
|
||||
struct module_list list;
|
||||
unsigned warn_if_uninitialized : 1;
|
||||
|
||||
/* update parameter passed via commandline */
|
||||
struct submodule_update_strategy update;
|
||||
|
||||
/* configuration parameters which are passed on to the children */
|
||||
int progress;
|
||||
int quiet;
|
||||
int recommend_shallow;
|
||||
struct string_list references;
|
||||
int dissociate;
|
||||
unsigned require_init;
|
||||
const char *depth;
|
||||
const char *recursive_prefix;
|
||||
const char *prefix;
|
||||
int single_branch;
|
||||
struct list_objects_filter_options *filter_options;
|
||||
struct update_data *update_data;
|
||||
|
||||
/* to be consumed by git-submodule.sh */
|
||||
/* to be consumed by update_submodule() */
|
||||
struct update_clone_data *update_clone;
|
||||
int update_clone_nr; int update_clone_alloc;
|
||||
|
||||
@ -1998,35 +1986,49 @@ struct submodule_update_clone {
|
||||
/* failed clones to be retried again */
|
||||
const struct cache_entry **failed_clones;
|
||||
int failed_clones_nr, failed_clones_alloc;
|
||||
|
||||
int max_jobs;
|
||||
unsigned int init;
|
||||
};
|
||||
#define SUBMODULE_UPDATE_CLONE_INIT { \
|
||||
#define SUBMODULE_UPDATE_CLONE_INIT { 0 }
|
||||
|
||||
struct update_data {
|
||||
const char *prefix;
|
||||
const char *recursive_prefix;
|
||||
const char *displaypath;
|
||||
const char *update_default;
|
||||
struct object_id suboid;
|
||||
struct string_list references;
|
||||
struct submodule_update_strategy update_strategy;
|
||||
struct list_objects_filter_options *filter_options;
|
||||
struct module_list list;
|
||||
int depth;
|
||||
int max_jobs;
|
||||
int single_branch;
|
||||
int recommend_shallow;
|
||||
unsigned int require_init;
|
||||
unsigned int force;
|
||||
unsigned int quiet;
|
||||
unsigned int nofetch;
|
||||
unsigned int remote;
|
||||
unsigned int progress;
|
||||
unsigned int dissociate;
|
||||
unsigned int init;
|
||||
unsigned int warn_if_uninitialized;
|
||||
unsigned int recursive;
|
||||
|
||||
/* copied over from update_clone_data */
|
||||
struct object_id oid;
|
||||
unsigned int just_cloned;
|
||||
const char *sm_path;
|
||||
};
|
||||
#define UPDATE_DATA_INIT { \
|
||||
.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
|
||||
.list = MODULE_LIST_INIT, \
|
||||
.update = SUBMODULE_UPDATE_STRATEGY_INIT, \
|
||||
.recommend_shallow = -1, \
|
||||
.references = STRING_LIST_INIT_DUP, \
|
||||
.single_branch = -1, \
|
||||
.max_jobs = 1, \
|
||||
.warn_if_uninitialized = 1, \
|
||||
}
|
||||
|
||||
struct update_data {
|
||||
const char *recursive_prefix;
|
||||
const char *sm_path;
|
||||
const char *displaypath;
|
||||
struct object_id oid;
|
||||
struct object_id suboid;
|
||||
struct submodule_update_strategy update_strategy;
|
||||
int depth;
|
||||
unsigned int force;
|
||||
unsigned int quiet;
|
||||
unsigned int nofetch;
|
||||
unsigned int just_cloned;
|
||||
unsigned int remote;
|
||||
};
|
||||
#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
|
||||
|
||||
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
|
||||
struct strbuf *out, const char *displaypath)
|
||||
{
|
||||
@ -2034,7 +2036,7 @@ static void next_submodule_warn_missing(struct submodule_update_clone *suc,
|
||||
* Only mention uninitialized submodules when their
|
||||
* paths have been specified.
|
||||
*/
|
||||
if (suc->warn_if_uninitialized) {
|
||||
if (suc->update_data->warn_if_uninitialized) {
|
||||
strbuf_addf(out,
|
||||
_("Submodule path '%s' not initialized"),
|
||||
displaypath);
|
||||
@ -2066,8 +2068,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
||||
int need_free_url = 0;
|
||||
|
||||
if (ce_stage(ce)) {
|
||||
if (suc->recursive_prefix)
|
||||
strbuf_addf(&sb, "%s/%s", suc->recursive_prefix, ce->name);
|
||||
if (suc->update_data->recursive_prefix)
|
||||
strbuf_addf(&sb, "%s/%s", suc->update_data->recursive_prefix, ce->name);
|
||||
else
|
||||
strbuf_addstr(&sb, ce->name);
|
||||
strbuf_addf(out, _("Skipping unmerged submodule %s"), sb.buf);
|
||||
@ -2077,8 +2079,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
||||
|
||||
sub = submodule_from_path(the_repository, null_oid(), ce->name);
|
||||
|
||||
if (suc->recursive_prefix)
|
||||
displaypath = relative_path(suc->recursive_prefix,
|
||||
if (suc->update_data->recursive_prefix)
|
||||
displaypath = relative_path(suc->update_data->recursive_prefix,
|
||||
ce->name, &displaypath_sb);
|
||||
else
|
||||
displaypath = ce->name;
|
||||
@ -2096,8 +2098,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
||||
}
|
||||
free(key);
|
||||
|
||||
if (suc->update.type == SM_UPDATE_NONE
|
||||
|| (suc->update.type == SM_UPDATE_UNSPECIFIED
|
||||
if (suc->update_data->update_strategy.type == SM_UPDATE_NONE
|
||||
|| (suc->update_data->update_strategy.type == SM_UPDATE_UNSPECIFIED
|
||||
&& update_type == SM_UPDATE_NONE)) {
|
||||
strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
|
||||
strbuf_addch(out, '\n');
|
||||
@ -2141,33 +2143,33 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
||||
child->err = -1;
|
||||
strvec_push(&child->args, "submodule--helper");
|
||||
strvec_push(&child->args, "clone");
|
||||
if (suc->progress)
|
||||
if (suc->update_data->progress)
|
||||
strvec_push(&child->args, "--progress");
|
||||
if (suc->quiet)
|
||||
if (suc->update_data->quiet)
|
||||
strvec_push(&child->args, "--quiet");
|
||||
if (suc->prefix)
|
||||
strvec_pushl(&child->args, "--prefix", suc->prefix, NULL);
|
||||
if (suc->recommend_shallow && sub->recommend_shallow == 1)
|
||||
if (suc->update_data->prefix)
|
||||
strvec_pushl(&child->args, "--prefix", suc->update_data->prefix, NULL);
|
||||
if (suc->update_data->recommend_shallow && sub->recommend_shallow == 1)
|
||||
strvec_push(&child->args, "--depth=1");
|
||||
if (suc->filter_options && suc->filter_options->choice)
|
||||
else if (suc->update_data->depth)
|
||||
strvec_pushf(&child->args, "--depth=%d", suc->update_data->depth);
|
||||
if (suc->update_data->filter_options && suc->update_data->filter_options->choice)
|
||||
strvec_pushf(&child->args, "--filter=%s",
|
||||
expand_list_objects_filter_spec(suc->filter_options));
|
||||
if (suc->require_init)
|
||||
expand_list_objects_filter_spec(suc->update_data->filter_options));
|
||||
if (suc->update_data->require_init)
|
||||
strvec_push(&child->args, "--require-init");
|
||||
strvec_pushl(&child->args, "--path", sub->path, NULL);
|
||||
strvec_pushl(&child->args, "--name", sub->name, NULL);
|
||||
strvec_pushl(&child->args, "--url", url, NULL);
|
||||
if (suc->references.nr) {
|
||||
if (suc->update_data->references.nr) {
|
||||
struct string_list_item *item;
|
||||
for_each_string_list_item(item, &suc->references)
|
||||
for_each_string_list_item(item, &suc->update_data->references)
|
||||
strvec_pushl(&child->args, "--reference", item->string, NULL);
|
||||
}
|
||||
if (suc->dissociate)
|
||||
if (suc->update_data->dissociate)
|
||||
strvec_push(&child->args, "--dissociate");
|
||||
if (suc->depth)
|
||||
strvec_push(&child->args, suc->depth);
|
||||
if (suc->single_branch >= 0)
|
||||
strvec_push(&child->args, suc->single_branch ?
|
||||
if (suc->update_data->single_branch >= 0)
|
||||
strvec_push(&child->args, suc->update_data->single_branch ?
|
||||
"--single-branch" :
|
||||
"--no-single-branch");
|
||||
|
||||
@ -2189,8 +2191,8 @@ static int update_clone_get_next_task(struct child_process *child,
|
||||
const struct cache_entry *ce;
|
||||
int index;
|
||||
|
||||
for (; suc->current < suc->list.nr; suc->current++) {
|
||||
ce = suc->list.entries[suc->current];
|
||||
for (; suc->current < suc->update_data->list.nr; suc->current++) {
|
||||
ce = suc->update_data->list.entries[suc->current];
|
||||
if (prepare_to_clone_next_submodule(ce, child, suc, err)) {
|
||||
int *p = xmalloc(sizeof(*p));
|
||||
*p = suc->current;
|
||||
@ -2205,7 +2207,7 @@ static int update_clone_get_next_task(struct child_process *child,
|
||||
* stragglers again, which we can imagine as an extension of the
|
||||
* entry list.
|
||||
*/
|
||||
index = suc->current - suc->list.nr;
|
||||
index = suc->current - suc->update_data->list.nr;
|
||||
if (index < suc->failed_clones_nr) {
|
||||
int *p;
|
||||
ce = suc->failed_clones[index];
|
||||
@ -2250,8 +2252,8 @@ static int update_clone_task_finished(int result,
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
if (idx < suc->list.nr) {
|
||||
ce = suc->list.entries[idx];
|
||||
if (idx < suc->update_data->list.nr) {
|
||||
ce = suc->update_data->list.entries[idx];
|
||||
strbuf_addf(err, _("Failed to clone '%s'. Retry scheduled"),
|
||||
ce->name);
|
||||
strbuf_addch(err, '\n');
|
||||
@ -2261,7 +2263,7 @@ static int update_clone_task_finished(int result,
|
||||
suc->failed_clones[suc->failed_clones_nr++] = ce;
|
||||
return 0;
|
||||
} else {
|
||||
idx -= suc->list.nr;
|
||||
idx -= suc->update_data->list.nr;
|
||||
ce = suc->failed_clones[idx];
|
||||
strbuf_addf(err, _("Failed to clone '%s' a second time, aborting"),
|
||||
ce->name);
|
||||
@ -2325,83 +2327,76 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
|
||||
|
||||
static int run_update_command(struct update_data *ud, int subforce)
|
||||
{
|
||||
struct strvec args = STRVEC_INIT;
|
||||
struct strvec child_env = STRVEC_INIT;
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
char *oid = oid_to_hex(&ud->oid);
|
||||
int must_die_on_failure = 0;
|
||||
int git_cmd;
|
||||
|
||||
switch (ud->update_strategy.type) {
|
||||
case SM_UPDATE_CHECKOUT:
|
||||
git_cmd = 1;
|
||||
strvec_pushl(&args, "checkout", "-q", NULL);
|
||||
cp.git_cmd = 1;
|
||||
strvec_pushl(&cp.args, "checkout", "-q", NULL);
|
||||
if (subforce)
|
||||
strvec_push(&args, "-f");
|
||||
strvec_push(&cp.args, "-f");
|
||||
break;
|
||||
case SM_UPDATE_REBASE:
|
||||
git_cmd = 1;
|
||||
strvec_push(&args, "rebase");
|
||||
cp.git_cmd = 1;
|
||||
strvec_push(&cp.args, "rebase");
|
||||
if (ud->quiet)
|
||||
strvec_push(&args, "--quiet");
|
||||
strvec_push(&cp.args, "--quiet");
|
||||
must_die_on_failure = 1;
|
||||
break;
|
||||
case SM_UPDATE_MERGE:
|
||||
git_cmd = 1;
|
||||
strvec_push(&args, "merge");
|
||||
cp.git_cmd = 1;
|
||||
strvec_push(&cp.args, "merge");
|
||||
if (ud->quiet)
|
||||
strvec_push(&args, "--quiet");
|
||||
strvec_push(&cp.args, "--quiet");
|
||||
must_die_on_failure = 1;
|
||||
break;
|
||||
case SM_UPDATE_COMMAND:
|
||||
git_cmd = 0;
|
||||
strvec_push(&args, ud->update_strategy.command);
|
||||
cp.use_shell = 1;
|
||||
strvec_push(&cp.args, ud->update_strategy.command);
|
||||
must_die_on_failure = 1;
|
||||
break;
|
||||
default:
|
||||
BUG("unexpected update strategy type: %s",
|
||||
submodule_strategy_to_string(&ud->update_strategy));
|
||||
}
|
||||
strvec_push(&args, oid);
|
||||
strvec_push(&cp.args, oid);
|
||||
|
||||
prepare_submodule_repo_env(&child_env);
|
||||
if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,
|
||||
ud->sm_path, child_env.v)) {
|
||||
cp.dir = xstrdup(ud->sm_path);
|
||||
prepare_submodule_repo_env(&cp.env_array);
|
||||
if (run_command(&cp)) {
|
||||
switch (ud->update_strategy.type) {
|
||||
case SM_UPDATE_CHECKOUT:
|
||||
printf(_("Unable to checkout '%s' in submodule path '%s'"),
|
||||
oid, ud->displaypath);
|
||||
die_message(_("Unable to checkout '%s' in submodule path '%s'"),
|
||||
oid, ud->displaypath);
|
||||
break;
|
||||
case SM_UPDATE_REBASE:
|
||||
printf(_("Unable to rebase '%s' in submodule path '%s'"),
|
||||
oid, ud->displaypath);
|
||||
die_message(_("Unable to rebase '%s' in submodule path '%s'"),
|
||||
oid, ud->displaypath);
|
||||
break;
|
||||
case SM_UPDATE_MERGE:
|
||||
printf(_("Unable to merge '%s' in submodule path '%s'"),
|
||||
oid, ud->displaypath);
|
||||
die_message(_("Unable to merge '%s' in submodule path '%s'"),
|
||||
oid, ud->displaypath);
|
||||
break;
|
||||
case SM_UPDATE_COMMAND:
|
||||
printf(_("Execution of '%s %s' failed in submodule path '%s'"),
|
||||
ud->update_strategy.command, oid, ud->displaypath);
|
||||
die_message(_("Execution of '%s %s' failed in submodule path '%s'"),
|
||||
ud->update_strategy.command, oid, ud->displaypath);
|
||||
break;
|
||||
default:
|
||||
BUG("unexpected update strategy type: %s",
|
||||
submodule_strategy_to_string(&ud->update_strategy));
|
||||
}
|
||||
/*
|
||||
* NEEDSWORK: We are currently printing to stdout with error
|
||||
* return so that the shell caller handles the error output
|
||||
* properly. Once we start handling the error messages within
|
||||
* C, we should use die() instead.
|
||||
*/
|
||||
if (must_die_on_failure)
|
||||
return 2;
|
||||
/*
|
||||
* This signifies to the caller in shell that the command
|
||||
* failed without dying
|
||||
*/
|
||||
exit(128);
|
||||
|
||||
/* the command failed, but update must continue */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ud->quiet)
|
||||
return 0;
|
||||
|
||||
switch (ud->update_strategy.type) {
|
||||
case SM_UPDATE_CHECKOUT:
|
||||
printf(_("Submodule path '%s': checked out '%s'\n"),
|
||||
@ -2427,7 +2422,7 @@ static int run_update_command(struct update_data *ud, int subforce)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_run_update_procedure(struct update_data *ud)
|
||||
static int run_update_procedure(struct update_data *ud)
|
||||
{
|
||||
int subforce = is_null_oid(&ud->suboid) || ud->force;
|
||||
|
||||
@ -2457,235 +2452,6 @@ static int do_run_update_procedure(struct update_data *ud)
|
||||
return run_update_command(ud, subforce);
|
||||
}
|
||||
|
||||
/*
|
||||
* NEEDSWORK: As we convert "git submodule update" to C,
|
||||
* update_submodule2() will invoke more and more functions, making it
|
||||
* difficult to preserve the function ordering without forward
|
||||
* declarations.
|
||||
*
|
||||
* When the conversion is complete, this forward declaration will be
|
||||
* unnecessary and should be removed.
|
||||
*/
|
||||
static int update_submodule2(struct update_data *update_data);
|
||||
static void update_submodule(struct update_clone_data *ucd)
|
||||
{
|
||||
fprintf(stdout, "dummy %s %d\t%s\n",
|
||||
oid_to_hex(&ucd->oid),
|
||||
ucd->just_cloned,
|
||||
ucd->sub->path);
|
||||
}
|
||||
|
||||
static int update_submodules(struct submodule_update_clone *suc)
|
||||
{
|
||||
int i;
|
||||
|
||||
run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
|
||||
update_clone_start_failure,
|
||||
update_clone_task_finished, suc, "submodule",
|
||||
"parallel/update");
|
||||
|
||||
/*
|
||||
* We saved the output and put it out all at once now.
|
||||
* That means:
|
||||
* - the listener does not have to interleave their (checkout)
|
||||
* work with our fetching. The writes involved in a
|
||||
* checkout involve more straightforward sequential I/O.
|
||||
* - the listener can avoid doing any work if fetching failed.
|
||||
*/
|
||||
if (suc->quickstop)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < suc->update_clone_nr; i++)
|
||||
update_submodule(&suc->update_clone[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_clone(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *update = NULL;
|
||||
struct pathspec pathspec;
|
||||
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
|
||||
struct list_objects_filter_options filter_options;
|
||||
int ret;
|
||||
|
||||
struct option module_update_clone_options[] = {
|
||||
OPT_BOOL(0, "init", &suc.init,
|
||||
N_("initialize uninitialized submodules before update")),
|
||||
OPT_STRING(0, "prefix", &prefix,
|
||||
N_("path"),
|
||||
N_("path into the working tree")),
|
||||
OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
|
||||
N_("path"),
|
||||
N_("path into the working tree, across nested "
|
||||
"submodule boundaries")),
|
||||
OPT_STRING(0, "update", &update,
|
||||
N_("string"),
|
||||
N_("rebase, merge, checkout or none")),
|
||||
OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
|
||||
N_("reference repository")),
|
||||
OPT_BOOL(0, "dissociate", &suc.dissociate,
|
||||
N_("use --reference only while cloning")),
|
||||
OPT_STRING(0, "depth", &suc.depth, "<depth>",
|
||||
N_("create a shallow clone truncated to the "
|
||||
"specified number of revisions")),
|
||||
OPT_INTEGER('j', "jobs", &suc.max_jobs,
|
||||
N_("parallel jobs")),
|
||||
OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
|
||||
N_("whether the initial clone should follow the shallow recommendation")),
|
||||
OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
|
||||
OPT_BOOL(0, "progress", &suc.progress,
|
||||
N_("force cloning progress")),
|
||||
OPT_BOOL(0, "require-init", &suc.require_init,
|
||||
N_("disallow cloning into non-empty directory")),
|
||||
OPT_BOOL(0, "single-branch", &suc.single_branch,
|
||||
N_("clone only one branch, HEAD or --branch")),
|
||||
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
const char *const git_submodule_helper_usage[] = {
|
||||
N_("git submodule [--quiet] update"
|
||||
" [--init [--filter=<filter-spec>]] [--remote]"
|
||||
" [-N|--no-fetch] [-f|--force]"
|
||||
" [--checkout|--merge|--rebase]"
|
||||
" [--[no-]recommend-shallow] [--reference <repository>]"
|
||||
" [--recursive] [--[no-]single-branch] [--] [<path>...]"),
|
||||
NULL
|
||||
};
|
||||
suc.prefix = prefix;
|
||||
|
||||
update_clone_config_from_gitmodules(&suc.max_jobs);
|
||||
git_config(git_update_clone_config, &suc.max_jobs);
|
||||
|
||||
memset(&filter_options, 0, sizeof(filter_options));
|
||||
argc = parse_options(argc, argv, prefix, module_update_clone_options,
|
||||
git_submodule_helper_usage, 0);
|
||||
|
||||
if (filter_options.choice && !suc.init) {
|
||||
/*
|
||||
* NEEDSWORK: Don't use usage_with_options() because the
|
||||
* usage string is for "git submodule update", but the
|
||||
* options are for "git submodule--helper update-clone".
|
||||
*
|
||||
* This will no longer be an issue when "update-clone"
|
||||
* is replaced by "git submodule--helper update".
|
||||
*/
|
||||
usage(git_submodule_helper_usage[0]);
|
||||
}
|
||||
|
||||
suc.filter_options = &filter_options;
|
||||
|
||||
if (update)
|
||||
if (parse_submodule_update_strategy(update, &suc.update) < 0)
|
||||
die(_("bad value for update parameter"));
|
||||
|
||||
if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0) {
|
||||
list_objects_filter_release(&filter_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pathspec.nr)
|
||||
suc.warn_if_uninitialized = 1;
|
||||
|
||||
if (suc.init) {
|
||||
struct module_list list = MODULE_LIST_INIT;
|
||||
struct init_cb info = INIT_CB_INIT;
|
||||
|
||||
if (module_list_compute(argc, argv, suc.prefix,
|
||||
&pathspec, &list) < 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If there are no path args and submodule.active is set then,
|
||||
* by default, only initialize 'active' modules.
|
||||
*/
|
||||
if (!argc && git_config_get_value_multi("submodule.active"))
|
||||
module_list_active(&list);
|
||||
|
||||
info.prefix = suc.prefix;
|
||||
info.superprefix = suc.recursive_prefix;
|
||||
if (suc.quiet)
|
||||
info.flags |= OPT_QUIET;
|
||||
|
||||
for_each_listed_submodule(&list, init_submodule_cb, &info);
|
||||
}
|
||||
|
||||
ret = update_submodules(&suc);
|
||||
list_objects_filter_release(&filter_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int run_update_procedure(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
char *prefixed_path, *update = NULL;
|
||||
struct update_data update_data = UPDATE_DATA_INIT;
|
||||
|
||||
struct option options[] = {
|
||||
OPT__QUIET(&update_data.quiet,
|
||||
N_("suppress output for update by rebase or merge")),
|
||||
OPT__FORCE(&update_data.force, N_("force checkout updates"),
|
||||
0),
|
||||
OPT_BOOL('N', "no-fetch", &update_data.nofetch,
|
||||
N_("don't fetch new objects from the remote site")),
|
||||
OPT_BOOL(0, "just-cloned", &update_data.just_cloned,
|
||||
N_("overrides update mode in case the repository is a fresh clone")),
|
||||
OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
|
||||
OPT_STRING(0, "prefix", &prefix,
|
||||
N_("path"),
|
||||
N_("path into the working tree")),
|
||||
OPT_STRING(0, "update", &update,
|
||||
N_("string"),
|
||||
N_("rebase, merge, checkout or none")),
|
||||
OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"),
|
||||
N_("path into the working tree, across nested "
|
||||
"submodule boundaries")),
|
||||
OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
|
||||
N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
|
||||
parse_opt_object_id),
|
||||
OPT_BOOL(0, "remote", &update_data.remote,
|
||||
N_("use SHA-1 of submodule's remote tracking branch")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
const char *const usage[] = {
|
||||
N_("git submodule--helper run-update-procedure [<options>] <path>"),
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, usage, 0);
|
||||
|
||||
if (argc != 1)
|
||||
usage_with_options(usage, options);
|
||||
|
||||
update_data.sm_path = argv[0];
|
||||
|
||||
if (update_data.recursive_prefix)
|
||||
prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
|
||||
else
|
||||
prefixed_path = xstrdup(update_data.sm_path);
|
||||
|
||||
update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
|
||||
|
||||
determine_submodule_update_strategy(the_repository, update_data.just_cloned,
|
||||
update_data.sm_path, update,
|
||||
&update_data.update_strategy);
|
||||
|
||||
free(prefixed_path);
|
||||
return update_submodule2(&update_data);
|
||||
}
|
||||
|
||||
static int resolve_relative_path(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
if (argc != 3)
|
||||
die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
|
||||
|
||||
printf("%s", relative_path(argv[1], argv[2], &sb));
|
||||
strbuf_release(&sb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *remote_submodule_branch(const char *path)
|
||||
{
|
||||
const struct submodule *sub;
|
||||
@ -2724,6 +2490,318 @@ static const char *remote_submodule_branch(const char *path)
|
||||
return branch;
|
||||
}
|
||||
|
||||
static void ensure_core_worktree(const char *path)
|
||||
{
|
||||
const char *cw;
|
||||
struct repository subrepo;
|
||||
|
||||
if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
|
||||
die(_("could not get a repository handle for submodule '%s'"), path);
|
||||
|
||||
if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
|
||||
char *cfg_file, *abs_path;
|
||||
const char *rel_path;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
cfg_file = repo_git_path(&subrepo, "config");
|
||||
|
||||
abs_path = absolute_pathdup(path);
|
||||
rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
|
||||
|
||||
git_config_set_in_file(cfg_file, "core.worktree", rel_path);
|
||||
|
||||
free(cfg_file);
|
||||
free(abs_path);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_data_to_args(struct update_data *update_data, struct strvec *args)
|
||||
{
|
||||
strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
|
||||
strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
|
||||
if (update_data->recursive_prefix)
|
||||
strvec_pushl(args, "--recursive-prefix",
|
||||
update_data->recursive_prefix, NULL);
|
||||
if (update_data->quiet)
|
||||
strvec_push(args, "--quiet");
|
||||
if (update_data->force)
|
||||
strvec_push(args, "--force");
|
||||
if (update_data->init)
|
||||
strvec_push(args, "--init");
|
||||
if (update_data->remote)
|
||||
strvec_push(args, "--remote");
|
||||
if (update_data->nofetch)
|
||||
strvec_push(args, "--no-fetch");
|
||||
if (update_data->dissociate)
|
||||
strvec_push(args, "--dissociate");
|
||||
if (update_data->progress)
|
||||
strvec_push(args, "--progress");
|
||||
if (update_data->require_init)
|
||||
strvec_push(args, "--require-init");
|
||||
if (update_data->depth)
|
||||
strvec_pushf(args, "--depth=%d", update_data->depth);
|
||||
if (update_data->update_default)
|
||||
strvec_pushl(args, "--update", update_data->update_default, NULL);
|
||||
if (update_data->references.nr) {
|
||||
struct string_list_item *item;
|
||||
for_each_string_list_item(item, &update_data->references)
|
||||
strvec_pushl(args, "--reference", item->string, NULL);
|
||||
}
|
||||
if (update_data->filter_options && update_data->filter_options->choice)
|
||||
strvec_pushf(args, "--filter=%s",
|
||||
expand_list_objects_filter_spec(
|
||||
update_data->filter_options));
|
||||
if (update_data->recommend_shallow == 0)
|
||||
strvec_push(args, "--no-recommend-shallow");
|
||||
else if (update_data->recommend_shallow == 1)
|
||||
strvec_push(args, "--recommend-shallow");
|
||||
if (update_data->single_branch >= 0)
|
||||
strvec_push(args, update_data->single_branch ?
|
||||
"--single-branch" :
|
||||
"--no-single-branch");
|
||||
}
|
||||
|
||||
static int update_submodule(struct update_data *update_data)
|
||||
{
|
||||
char *prefixed_path;
|
||||
|
||||
ensure_core_worktree(update_data->sm_path);
|
||||
|
||||
if (update_data->recursive_prefix)
|
||||
prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
|
||||
update_data->sm_path);
|
||||
else
|
||||
prefixed_path = xstrdup(update_data->sm_path);
|
||||
|
||||
update_data->displaypath = get_submodule_displaypath(prefixed_path,
|
||||
update_data->prefix);
|
||||
free(prefixed_path);
|
||||
|
||||
determine_submodule_update_strategy(the_repository, update_data->just_cloned,
|
||||
update_data->sm_path, update_data->update_default,
|
||||
&update_data->update_strategy);
|
||||
|
||||
if (update_data->just_cloned)
|
||||
oidcpy(&update_data->suboid, null_oid());
|
||||
else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
|
||||
die(_("Unable to find current revision in submodule path '%s'"),
|
||||
update_data->displaypath);
|
||||
|
||||
if (update_data->remote) {
|
||||
char *remote_name = get_default_remote_submodule(update_data->sm_path);
|
||||
const char *branch = remote_submodule_branch(update_data->sm_path);
|
||||
char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
|
||||
|
||||
if (!update_data->nofetch) {
|
||||
if (fetch_in_submodule(update_data->sm_path, update_data->depth,
|
||||
0, NULL))
|
||||
die(_("Unable to fetch in submodule path '%s'"),
|
||||
update_data->sm_path);
|
||||
}
|
||||
|
||||
if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
|
||||
die(_("Unable to find %s revision in submodule path '%s'"),
|
||||
remote_ref, update_data->sm_path);
|
||||
|
||||
free(remote_ref);
|
||||
}
|
||||
|
||||
if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
|
||||
if (run_update_procedure(update_data))
|
||||
return 1;
|
||||
|
||||
if (update_data->recursive) {
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
struct update_data next = *update_data;
|
||||
int res;
|
||||
|
||||
if (update_data->recursive_prefix)
|
||||
prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
|
||||
update_data->sm_path);
|
||||
else
|
||||
prefixed_path = xstrfmt("%s/", update_data->sm_path);
|
||||
|
||||
next.recursive_prefix = get_submodule_displaypath(prefixed_path,
|
||||
update_data->prefix);
|
||||
next.prefix = NULL;
|
||||
oidcpy(&next.oid, null_oid());
|
||||
oidcpy(&next.suboid, null_oid());
|
||||
|
||||
cp.dir = update_data->sm_path;
|
||||
cp.git_cmd = 1;
|
||||
prepare_submodule_repo_env(&cp.env_array);
|
||||
update_data_to_args(&next, &cp.args);
|
||||
|
||||
/* die() if child process die()'d */
|
||||
res = run_command(&cp);
|
||||
if (!res)
|
||||
return 0;
|
||||
die_message(_("Failed to recurse into submodule path '%s'"),
|
||||
update_data->displaypath);
|
||||
if (res == 128)
|
||||
exit(res);
|
||||
else if (res)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_submodules(struct update_data *update_data)
|
||||
{
|
||||
int i, res = 0;
|
||||
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
|
||||
|
||||
suc.update_data = update_data;
|
||||
run_processes_parallel_tr2(suc.update_data->max_jobs, update_clone_get_next_task,
|
||||
update_clone_start_failure,
|
||||
update_clone_task_finished, &suc, "submodule",
|
||||
"parallel/update");
|
||||
|
||||
/*
|
||||
* We saved the output and put it out all at once now.
|
||||
* That means:
|
||||
* - the listener does not have to interleave their (checkout)
|
||||
* work with our fetching. The writes involved in a
|
||||
* checkout involve more straightforward sequential I/O.
|
||||
* - the listener can avoid doing any work if fetching failed.
|
||||
*/
|
||||
if (suc.quickstop) {
|
||||
res = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < suc.update_clone_nr; i++) {
|
||||
struct update_clone_data ucd = suc.update_clone[i];
|
||||
|
||||
oidcpy(&update_data->oid, &ucd.oid);
|
||||
update_data->just_cloned = ucd.just_cloned;
|
||||
update_data->sm_path = ucd.sub->path;
|
||||
|
||||
if (update_submodule(update_data))
|
||||
res = 1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
string_list_clear(&update_data->references, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int module_update(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct pathspec pathspec;
|
||||
struct update_data opt = UPDATE_DATA_INIT;
|
||||
struct list_objects_filter_options filter_options;
|
||||
int ret;
|
||||
|
||||
struct option module_update_options[] = {
|
||||
OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
|
||||
OPT_BOOL(0, "init", &opt.init,
|
||||
N_("initialize uninitialized submodules before update")),
|
||||
OPT_BOOL(0, "remote", &opt.remote,
|
||||
N_("use SHA-1 of submodule's remote tracking branch")),
|
||||
OPT_BOOL(0, "recursive", &opt.recursive,
|
||||
N_("traverse submodules recursively")),
|
||||
OPT_BOOL('N', "no-fetch", &opt.nofetch,
|
||||
N_("don't fetch new objects from the remote site")),
|
||||
OPT_STRING(0, "prefix", &opt.prefix,
|
||||
N_("path"),
|
||||
N_("path into the working tree")),
|
||||
OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
|
||||
N_("path"),
|
||||
N_("path into the working tree, across nested "
|
||||
"submodule boundaries")),
|
||||
OPT_STRING(0, "update", &opt.update_default,
|
||||
N_("string"),
|
||||
N_("rebase, merge, checkout or none")),
|
||||
OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
|
||||
N_("reference repository")),
|
||||
OPT_BOOL(0, "dissociate", &opt.dissociate,
|
||||
N_("use --reference only while cloning")),
|
||||
OPT_INTEGER(0, "depth", &opt.depth,
|
||||
N_("create a shallow clone truncated to the "
|
||||
"specified number of revisions")),
|
||||
OPT_INTEGER('j', "jobs", &opt.max_jobs,
|
||||
N_("parallel jobs")),
|
||||
OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
|
||||
N_("whether the initial clone should follow the shallow recommendation")),
|
||||
OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
|
||||
OPT_BOOL(0, "progress", &opt.progress,
|
||||
N_("force cloning progress")),
|
||||
OPT_BOOL(0, "require-init", &opt.require_init,
|
||||
N_("disallow cloning into non-empty directory")),
|
||||
OPT_BOOL(0, "single-branch", &opt.single_branch,
|
||||
N_("clone only one branch, HEAD or --branch")),
|
||||
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
const char *const git_submodule_helper_usage[] = {
|
||||
N_("git submodule [--quiet] update"
|
||||
" [--init [--filter=<filter-spec>]] [--remote]"
|
||||
" [-N|--no-fetch] [-f|--force]"
|
||||
" [--checkout|--merge|--rebase]"
|
||||
" [--[no-]recommend-shallow] [--reference <repository>]"
|
||||
" [--recursive] [--[no-]single-branch] [--] [<path>...]"),
|
||||
NULL
|
||||
};
|
||||
|
||||
update_clone_config_from_gitmodules(&opt.max_jobs);
|
||||
git_config(git_update_clone_config, &opt.max_jobs);
|
||||
|
||||
memset(&filter_options, 0, sizeof(filter_options));
|
||||
argc = parse_options(argc, argv, prefix, module_update_options,
|
||||
git_submodule_helper_usage, 0);
|
||||
|
||||
if (filter_options.choice && !opt.init) {
|
||||
usage_with_options(git_submodule_helper_usage,
|
||||
module_update_options);
|
||||
}
|
||||
|
||||
opt.filter_options = &filter_options;
|
||||
|
||||
if (opt.update_default)
|
||||
if (parse_submodule_update_strategy(opt.update_default,
|
||||
&opt.update_strategy) < 0)
|
||||
die(_("bad value for update parameter"));
|
||||
|
||||
if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0) {
|
||||
list_objects_filter_release(&filter_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pathspec.nr)
|
||||
opt.warn_if_uninitialized = 1;
|
||||
|
||||
if (opt.init) {
|
||||
struct module_list list = MODULE_LIST_INIT;
|
||||
struct init_cb info = INIT_CB_INIT;
|
||||
|
||||
if (module_list_compute(argc, argv, opt.prefix,
|
||||
&pathspec, &list) < 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If there are no path args and submodule.active is set then,
|
||||
* by default, only initialize 'active' modules.
|
||||
*/
|
||||
if (!argc && git_config_get_value_multi("submodule.active"))
|
||||
module_list_active(&list);
|
||||
|
||||
info.prefix = opt.prefix;
|
||||
info.superprefix = opt.recursive_prefix;
|
||||
if (opt.quiet)
|
||||
info.flags |= OPT_QUIET;
|
||||
|
||||
for_each_listed_submodule(&list, init_submodule_cb, &info);
|
||||
}
|
||||
|
||||
ret = update_submodules(&opt);
|
||||
list_objects_filter_release(&filter_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int push_check(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct remote *remote;
|
||||
@ -2801,32 +2879,6 @@ static int push_check(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ensure_core_worktree(const char *path)
|
||||
{
|
||||
const char *cw;
|
||||
struct repository subrepo;
|
||||
|
||||
if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
|
||||
die(_("could not get a repository handle for submodule '%s'"), path);
|
||||
|
||||
if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
|
||||
char *cfg_file, *abs_path;
|
||||
const char *rel_path;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
cfg_file = repo_git_path(&subrepo, "config");
|
||||
|
||||
abs_path = absolute_pathdup(path);
|
||||
rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
|
||||
|
||||
git_config_set_in_file(cfg_file, "core.worktree", rel_path);
|
||||
|
||||
free(cfg_file);
|
||||
free(abs_path);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
}
|
||||
|
||||
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@ -3048,41 +3100,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
|
||||
static int update_submodule2(struct update_data *update_data)
|
||||
{
|
||||
ensure_core_worktree(update_data->sm_path);
|
||||
if (update_data->just_cloned)
|
||||
oidcpy(&update_data->suboid, null_oid());
|
||||
else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
|
||||
die(_("Unable to find current revision in submodule path '%s'"),
|
||||
update_data->displaypath);
|
||||
|
||||
if (update_data->remote) {
|
||||
char *remote_name = get_default_remote_submodule(update_data->sm_path);
|
||||
const char *branch = remote_submodule_branch(update_data->sm_path);
|
||||
char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
|
||||
|
||||
if (!update_data->nofetch) {
|
||||
if (fetch_in_submodule(update_data->sm_path, update_data->depth,
|
||||
0, NULL))
|
||||
die(_("Unable to fetch in submodule path '%s'"),
|
||||
update_data->sm_path);
|
||||
}
|
||||
|
||||
if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
|
||||
die(_("Unable to find %s revision in submodule path '%s'"),
|
||||
remote_ref, update_data->sm_path);
|
||||
|
||||
free(remote_ref);
|
||||
}
|
||||
|
||||
if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
|
||||
return do_run_update_procedure(update_data);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
struct add_data {
|
||||
const char *prefix;
|
||||
const char *branch;
|
||||
@ -3471,9 +3488,7 @@ static struct cmd_struct commands[] = {
|
||||
{"name", module_name, 0},
|
||||
{"clone", module_clone, 0},
|
||||
{"add", module_add, SUPPORT_SUPER_PREFIX},
|
||||
{"update-clone", update_clone, 0},
|
||||
{"run-update-procedure", run_update_procedure, 0},
|
||||
{"relative-path", resolve_relative_path, 0},
|
||||
{"update", module_update, 0},
|
||||
{"resolve-relative-url-test", resolve_relative_url_test, 0},
|
||||
{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
|
||||
{"init", module_init, SUPPORT_SUPER_PREFIX},
|
||||
|
105
git-submodule.sh
105
git-submodule.sh
@ -51,14 +51,6 @@ jobs=
|
||||
recommend_shallow=
|
||||
filter=
|
||||
|
||||
die_if_unmatched ()
|
||||
{
|
||||
if test "$1" = "#unmatched"
|
||||
then
|
||||
exit ${2:-1}
|
||||
fi
|
||||
}
|
||||
|
||||
isnumber()
|
||||
{
|
||||
n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
|
||||
@ -356,109 +348,28 @@ cmd_update()
|
||||
shift
|
||||
done
|
||||
|
||||
{
|
||||
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
|
||||
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update \
|
||||
${GIT_QUIET:+--quiet} \
|
||||
${force:+--force} \
|
||||
${progress:+"--progress"} \
|
||||
${remote:+--remote} \
|
||||
${recursive:+--recursive} \
|
||||
${init:+--init} \
|
||||
${nofetch:+--no-fetch} \
|
||||
${wt_prefix:+--prefix "$wt_prefix"} \
|
||||
${prefix:+--recursive-prefix "$prefix"} \
|
||||
${update:+--update "$update"} \
|
||||
${reference:+"$reference"} \
|
||||
${dissociate:+"--dissociate"} \
|
||||
${depth:+--depth "$depth"} \
|
||||
${depth:+"$depth"} \
|
||||
${require_init:+--require-init} \
|
||||
${dissociate:+"--dissociate"} \
|
||||
$single_branch \
|
||||
$recommend_shallow \
|
||||
$jobs \
|
||||
$filter \
|
||||
-- \
|
||||
"$@" || echo "#unmatched" $?
|
||||
} | {
|
||||
err=
|
||||
while read -r quickabort sha1 just_cloned sm_path
|
||||
do
|
||||
die_if_unmatched "$quickabort" "$sha1"
|
||||
|
||||
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
|
||||
|
||||
if test $just_cloned -eq 0
|
||||
then
|
||||
just_cloned=
|
||||
fi
|
||||
|
||||
out=$(git submodule--helper run-update-procedure \
|
||||
${wt_prefix:+--prefix "$wt_prefix"} \
|
||||
${GIT_QUIET:+--quiet} \
|
||||
${force:+--force} \
|
||||
${just_cloned:+--just-cloned} \
|
||||
${nofetch:+--no-fetch} \
|
||||
${depth:+"$depth"} \
|
||||
${update:+--update "$update"} \
|
||||
${prefix:+--recursive-prefix "$prefix"} \
|
||||
${sha1:+--oid "$sha1"} \
|
||||
${remote:+--remote} \
|
||||
"--" \
|
||||
"$sm_path")
|
||||
|
||||
# exit codes for run-update-procedure:
|
||||
# 0: update was successful, say command output
|
||||
# 1: update procedure failed, but should not die
|
||||
# 2 or 128: subcommand died during execution
|
||||
# 3: no update procedure was run
|
||||
res="$?"
|
||||
case $res in
|
||||
0)
|
||||
say "$out"
|
||||
;;
|
||||
1)
|
||||
err="${err};fatal: $out"
|
||||
continue
|
||||
;;
|
||||
2|128)
|
||||
die_with_status $res "fatal: $out"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -n "$recursive"
|
||||
then
|
||||
(
|
||||
prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
|
||||
wt_prefix=
|
||||
sanitize_submodule_env
|
||||
cd "$sm_path" &&
|
||||
eval cmd_update
|
||||
)
|
||||
res=$?
|
||||
if test $res -gt 0
|
||||
then
|
||||
die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
|
||||
if test $res -ne 2
|
||||
then
|
||||
err="${err};$die_msg"
|
||||
continue
|
||||
else
|
||||
die_with_status $res "$die_msg"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "$err"
|
||||
then
|
||||
OIFS=$IFS
|
||||
IFS=';'
|
||||
for e in $err
|
||||
do
|
||||
if test -n "$e"
|
||||
then
|
||||
echo >&2 "$e"
|
||||
fi
|
||||
done
|
||||
IFS=$OIFS
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
"$@"
|
||||
}
|
||||
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user