Skip to content

Commit b3c5f5c

Browse files
tfidfwastakengitster
authored andcommitted
submodule: move core cmd_update() logic to C
This patch completes the conversion past the flag parsing of `submodule update` by introducing a helper subcommand called `submodule--helper update`. The behaviour of `submodule update` should remain the same after this patch. Prior to this patch, `submodule update` was implemented by piping the output of `update-clone` (which clones all missing submodules, then prints relevant information for all submodules) into `run-update-procedure` (which reads the information and updates the submodule tree). With `submodule--helper update`, we iterate over the submodules and update the submodule tree in the same process. This reuses most of existing code structure, except that `update_submodule()` now updates the submodule tree (instead of printing submodule information to be consumed by another process). Recursing on a submodule is done by calling a subprocess that launches `submodule--helper update`, with a modified `--recursive-prefix` and `--prefix` parameter. Mentored-by: Christian Couder <[email protected]> Mentored-by: Shourya Shukla <[email protected]> Signed-off-by: Atharva Raykar <[email protected]> Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Glen Choo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 75df9df commit b3c5f5c

File tree

2 files changed

+131
-202
lines changed

2 files changed

+131
-202
lines changed

builtin/submodule--helper.c

Lines changed: 124 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,7 +1976,7 @@ struct submodule_update_clone {
19761976
/* configuration parameters which are passed on to the children */
19771977
struct update_data *update_data;
19781978

1979-
/* to be consumed by git-submodule.sh */
1979+
/* to be consumed by update_submodule() */
19801980
struct update_clone_data *update_clone;
19811981
int update_clone_nr; int update_clone_alloc;
19821982

@@ -1992,10 +1992,8 @@ struct submodule_update_clone {
19921992
struct update_data {
19931993
const char *prefix;
19941994
const char *recursive_prefix;
1995-
const char *sm_path;
19961995
const char *displaypath;
19971996
const char *update_default;
1998-
struct object_id oid;
19991997
struct object_id suboid;
20001998
struct string_list references;
20011999
struct submodule_update_strategy update_strategy;
@@ -2009,12 +2007,17 @@ struct update_data {
20092007
unsigned int force;
20102008
unsigned int quiet;
20112009
unsigned int nofetch;
2012-
unsigned int just_cloned;
20132010
unsigned int remote;
20142011
unsigned int progress;
20152012
unsigned int dissociate;
20162013
unsigned int init;
20172014
unsigned int warn_if_uninitialized;
2015+
unsigned int recursive;
2016+
2017+
/* copied over from update_clone_data */
2018+
struct object_id oid;
2019+
unsigned int just_cloned;
2020+
const char *sm_path;
20182021
};
20192022
#define UPDATE_DATA_INIT { \
20202023
.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
@@ -2419,7 +2422,7 @@ static int run_update_command(struct update_data *ud, int subforce)
24192422
return 0;
24202423
}
24212424

2422-
static int do_run_update_procedure(struct update_data *ud)
2425+
static int run_update_procedure(struct update_data *ud)
24232426
{
24242427
int subforce = is_null_oid(&ud->suboid) || ud->force;
24252428

@@ -2449,27 +2452,10 @@ static int do_run_update_procedure(struct update_data *ud)
24492452
return run_update_command(ud, subforce);
24502453
}
24512454

2452-
/*
2453-
* NEEDSWORK: As we convert "git submodule update" to C,
2454-
* update_submodule2() will invoke more and more functions, making it
2455-
* difficult to preserve the function ordering without forward
2456-
* declarations.
2457-
*
2458-
* When the conversion is complete, this forward declaration will be
2459-
* unnecessary and should be removed.
2460-
*/
2461-
static int update_submodule2(struct update_data *update_data);
2462-
static void update_submodule(struct update_clone_data *ucd)
2463-
{
2464-
fprintf(stdout, "dummy %s %d\t%s\n",
2465-
oid_to_hex(&ucd->oid),
2466-
ucd->just_cloned,
2467-
ucd->sub->path);
2468-
}
2469-
2455+
static int update_submodule(struct update_data *update_data);
24702456
static int update_submodules(struct update_data *update_data)
24712457
{
2472-
int i;
2458+
int i, res = 0;
24732459
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
24742460

24752461
suc.update_data = update_data;
@@ -2486,25 +2472,44 @@ static int update_submodules(struct update_data *update_data)
24862472
* checkout involve more straightforward sequential I/O.
24872473
* - the listener can avoid doing any work if fetching failed.
24882474
*/
2489-
if (suc.quickstop)
2490-
return 1;
2475+
if (suc.quickstop) {
2476+
res = 1;
2477+
goto cleanup;
2478+
}
24912479

2492-
for (i = 0; i < suc.update_clone_nr; i++)
2493-
update_submodule(&suc.update_clone[i]);
2480+
for (i = 0; i < suc.update_clone_nr; i++) {
2481+
struct update_clone_data ucd = suc.update_clone[i];
24942482

2495-
return 0;
2483+
oidcpy(&update_data->oid, &ucd.oid);
2484+
update_data->just_cloned = ucd.just_cloned;
2485+
update_data->sm_path = ucd.sub->path;
2486+
2487+
if (update_submodule(update_data))
2488+
res = 1;
2489+
}
2490+
2491+
cleanup:
2492+
string_list_clear(&update_data->references, 0);
2493+
return res;
24962494
}
24972495

2498-
static int update_clone(int argc, const char **argv, const char *prefix)
2496+
static int module_update(int argc, const char **argv, const char *prefix)
24992497
{
25002498
struct pathspec pathspec;
25012499
struct update_data opt = UPDATE_DATA_INIT;
25022500
struct list_objects_filter_options filter_options;
25032501
int ret;
25042502

2505-
struct option module_update_clone_options[] = {
2503+
struct option module_update_options[] = {
2504+
OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
25062505
OPT_BOOL(0, "init", &opt.init,
25072506
N_("initialize uninitialized submodules before update")),
2507+
OPT_BOOL(0, "remote", &opt.remote,
2508+
N_("use SHA-1 of submodule's remote tracking branch")),
2509+
OPT_BOOL(0, "recursive", &opt.recursive,
2510+
N_("traverse submodules recursively")),
2511+
OPT_BOOL('N', "no-fetch", &opt.nofetch,
2512+
N_("don't fetch new objects from the remote site")),
25082513
OPT_STRING(0, "prefix", &opt.prefix,
25092514
N_("path"),
25102515
N_("path into the working tree")),
@@ -2551,19 +2556,12 @@ static int update_clone(int argc, const char **argv, const char *prefix)
25512556
git_config(git_update_clone_config, &opt.max_jobs);
25522557

25532558
memset(&filter_options, 0, sizeof(filter_options));
2554-
argc = parse_options(argc, argv, prefix, module_update_clone_options,
2559+
argc = parse_options(argc, argv, prefix, module_update_options,
25552560
git_submodule_helper_usage, 0);
25562561

25572562
if (filter_options.choice && !opt.init) {
2558-
/*
2559-
* NEEDSWORK: Don't use usage_with_options() because the
2560-
* usage string is for "git submodule update", but the
2561-
* options are for "git submodule--helper update-clone".
2562-
*
2563-
* This will no longer be an issue when "update-clone"
2564-
* is replaced by "git submodule--helper update".
2565-
*/
2566-
usage(git_submodule_helper_usage[0]);
2563+
usage_with_options(git_submodule_helper_usage,
2564+
module_update_options);
25672565
}
25682566

25692567
opt.filter_options = &filter_options;
@@ -2609,63 +2607,6 @@ static int update_clone(int argc, const char **argv, const char *prefix)
26092607
return ret;
26102608
}
26112609

2612-
static int run_update_procedure(int argc, const char **argv, const char *prefix)
2613-
{
2614-
struct update_data update_data = UPDATE_DATA_INIT;
2615-
2616-
struct option options[] = {
2617-
OPT__QUIET(&update_data.quiet,
2618-
N_("suppress output for update by rebase or merge")),
2619-
OPT__FORCE(&update_data.force, N_("force checkout updates"),
2620-
0),
2621-
OPT_BOOL('N', "no-fetch", &update_data.nofetch,
2622-
N_("don't fetch new objects from the remote site")),
2623-
OPT_BOOL(0, "just-cloned", &update_data.just_cloned,
2624-
N_("overrides update mode in case the repository is a fresh clone")),
2625-
OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
2626-
OPT_STRING(0, "prefix", &prefix,
2627-
N_("path"),
2628-
N_("path into the working tree")),
2629-
OPT_STRING(0, "update", &update_data.update_default,
2630-
N_("string"),
2631-
N_("rebase, merge, checkout or none")),
2632-
OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"),
2633-
N_("path into the working tree, across nested "
2634-
"submodule boundaries")),
2635-
OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
2636-
N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
2637-
parse_opt_object_id),
2638-
OPT_BOOL(0, "remote", &update_data.remote,
2639-
N_("use SHA-1 of submodule's remote tracking branch")),
2640-
OPT_END()
2641-
};
2642-
2643-
const char *const usage[] = {
2644-
N_("git submodule--helper run-update-procedure [<options>] <path>"),
2645-
NULL
2646-
};
2647-
2648-
argc = parse_options(argc, argv, prefix, options, usage, 0);
2649-
2650-
if (argc != 1)
2651-
usage_with_options(usage, options);
2652-
2653-
update_data.sm_path = argv[0];
2654-
2655-
return update_submodule2(&update_data);
2656-
}
2657-
2658-
static int resolve_relative_path(int argc, const char **argv, const char *prefix)
2659-
{
2660-
struct strbuf sb = STRBUF_INIT;
2661-
if (argc != 3)
2662-
die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
2663-
2664-
printf("%s", relative_path(argv[1], argv[2], &sb));
2665-
strbuf_release(&sb);
2666-
return 0;
2667-
}
2668-
26692610
static const char *remote_submodule_branch(const char *path)
26702611
{
26712612
const struct submodule *sub;
@@ -3028,8 +2969,53 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
30282969
return 0;
30292970
}
30302971

3031-
/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
3032-
static int update_submodule2(struct update_data *update_data)
2972+
static void update_data_to_args(struct update_data *update_data, struct strvec *args)
2973+
{
2974+
strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
2975+
strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
2976+
if (update_data->recursive_prefix)
2977+
strvec_pushl(args, "--recursive-prefix",
2978+
update_data->recursive_prefix, NULL);
2979+
if (update_data->quiet)
2980+
strvec_push(args, "--quiet");
2981+
if (update_data->force)
2982+
strvec_push(args, "--force");
2983+
if (update_data->init)
2984+
strvec_push(args, "--init");
2985+
if (update_data->remote)
2986+
strvec_push(args, "--remote");
2987+
if (update_data->nofetch)
2988+
strvec_push(args, "--no-fetch");
2989+
if (update_data->dissociate)
2990+
strvec_push(args, "--dissociate");
2991+
if (update_data->progress)
2992+
strvec_push(args, "--progress");
2993+
if (update_data->require_init)
2994+
strvec_push(args, "--require-init");
2995+
if (update_data->depth)
2996+
strvec_pushf(args, "--depth=%d", update_data->depth);
2997+
if (update_data->update_default)
2998+
strvec_pushl(args, "--update", update_data->update_default, NULL);
2999+
if (update_data->references.nr) {
3000+
struct string_list_item *item;
3001+
for_each_string_list_item(item, &update_data->references)
3002+
strvec_pushl(args, "--reference", item->string, NULL);
3003+
}
3004+
if (update_data->filter_options && update_data->filter_options->choice)
3005+
strvec_pushf(args, "--filter=%s",
3006+
expand_list_objects_filter_spec(
3007+
update_data->filter_options));
3008+
if (update_data->recommend_shallow == 0)
3009+
strvec_push(args, "--no-recommend-shallow");
3010+
else if (update_data->recommend_shallow == 1)
3011+
strvec_push(args, "--recommend-shallow");
3012+
if (update_data->single_branch >= 0)
3013+
strvec_push(args, update_data->single_branch ?
3014+
"--single-branch" :
3015+
"--no-single-branch");
3016+
}
3017+
3018+
static int update_submodule(struct update_data *update_data)
30333019
{
30343020
char *prefixed_path;
30353021

@@ -3075,9 +3061,44 @@ static int update_submodule2(struct update_data *update_data)
30753061
}
30763062

30773063
if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
3078-
return do_run_update_procedure(update_data);
3064+
if (run_update_procedure(update_data))
3065+
return 1;
3066+
3067+
if (update_data->recursive) {
3068+
struct child_process cp = CHILD_PROCESS_INIT;
3069+
struct update_data next = *update_data;
3070+
int res;
3071+
3072+
if (update_data->recursive_prefix)
3073+
prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
3074+
update_data->sm_path);
3075+
else
3076+
prefixed_path = xstrfmt("%s/", update_data->sm_path);
3077+
3078+
next.recursive_prefix = get_submodule_displaypath(prefixed_path,
3079+
update_data->prefix);
3080+
next.prefix = NULL;
3081+
oidcpy(&next.oid, null_oid());
3082+
oidcpy(&next.suboid, null_oid());
3083+
3084+
cp.dir = update_data->sm_path;
3085+
cp.git_cmd = 1;
3086+
prepare_submodule_repo_env(&cp.env_array);
3087+
update_data_to_args(&next, &cp.args);
30793088

3080-
return 3;
3089+
/* die() if child process die()'d */
3090+
res = run_command(&cp);
3091+
if (!res)
3092+
return 0;
3093+
die_message(_("Failed to recurse into submodule path '%s'"),
3094+
update_data->displaypath);
3095+
if (res == 128)
3096+
exit(res);
3097+
else if (res)
3098+
return 1;
3099+
}
3100+
3101+
return 0;
30813102
}
30823103

30833104
struct add_data {
@@ -3468,9 +3489,7 @@ static struct cmd_struct commands[] = {
34683489
{"name", module_name, 0},
34693490
{"clone", module_clone, 0},
34703491
{"add", module_add, SUPPORT_SUPER_PREFIX},
3471-
{"update-clone", update_clone, 0},
3472-
{"run-update-procedure", run_update_procedure, 0},
3473-
{"relative-path", resolve_relative_path, 0},
3492+
{"update", module_update, 0},
34743493
{"resolve-relative-url-test", resolve_relative_url_test, 0},
34753494
{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
34763495
{"init", module_init, SUPPORT_SUPER_PREFIX},

0 commit comments

Comments
 (0)