Skip to content

Commit 4d6d6ef

Browse files
committed
Merge branch 'sb/submodule-update-in-c'
"git submodule update" is getting rewritten piece-by-piece into C. * sb/submodule-update-in-c: submodule--helper: introduce new update-module-mode helper submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree builtin/submodule--helper: factor out method to update a single submodule builtin/submodule--helper: store update_clone information in a struct builtin/submodule--helper: factor out submodule updating git-submodule.sh: rename unused variables git-submodule.sh: align error reporting for update mode to use path
2 parents 3900689 + ee69b2a commit 4d6d6ef

File tree

2 files changed

+164
-52
lines changed

2 files changed

+164
-52
lines changed

builtin/submodule--helper.c

Lines changed: 158 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,72 @@ static int module_clone(int argc, const char **argv, const char *prefix)
14431443
return 0;
14441444
}
14451445

1446+
static void determine_submodule_update_strategy(struct repository *r,
1447+
int just_cloned,
1448+
const char *path,
1449+
const char *update,
1450+
struct submodule_update_strategy *out)
1451+
{
1452+
const struct submodule *sub = submodule_from_path(r, &null_oid, path);
1453+
char *key;
1454+
const char *val;
1455+
1456+
key = xstrfmt("submodule.%s.update", sub->name);
1457+
1458+
if (update) {
1459+
trace_printf("parsing update");
1460+
if (parse_submodule_update_strategy(update, out) < 0)
1461+
die(_("Invalid update mode '%s' for submodule path '%s'"),
1462+
update, path);
1463+
} else if (!repo_config_get_string_const(r, key, &val)) {
1464+
if (parse_submodule_update_strategy(val, out) < 0)
1465+
die(_("Invalid update mode '%s' configured for submodule path '%s'"),
1466+
val, path);
1467+
} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
1468+
trace_printf("loaded thing");
1469+
out->type = sub->update_strategy.type;
1470+
out->command = sub->update_strategy.command;
1471+
} else
1472+
out->type = SM_UPDATE_CHECKOUT;
1473+
1474+
if (just_cloned &&
1475+
(out->type == SM_UPDATE_MERGE ||
1476+
out->type == SM_UPDATE_REBASE ||
1477+
out->type == SM_UPDATE_NONE))
1478+
out->type = SM_UPDATE_CHECKOUT;
1479+
1480+
free(key);
1481+
}
1482+
1483+
static int module_update_module_mode(int argc, const char **argv, const char *prefix)
1484+
{
1485+
const char *path, *update = NULL;
1486+
int just_cloned;
1487+
struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
1488+
1489+
if (argc < 3 || argc > 4)
1490+
die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
1491+
1492+
just_cloned = git_config_int("just_cloned", argv[1]);
1493+
path = argv[2];
1494+
1495+
if (argc == 4)
1496+
update = argv[3];
1497+
1498+
determine_submodule_update_strategy(the_repository,
1499+
just_cloned, path, update,
1500+
&update_strategy);
1501+
fputs(submodule_strategy_to_string(&update_strategy), stdout);
1502+
1503+
return 0;
1504+
}
1505+
1506+
struct update_clone_data {
1507+
const struct submodule *sub;
1508+
struct object_id oid;
1509+
unsigned just_cloned;
1510+
};
1511+
14461512
struct submodule_update_clone {
14471513
/* index into 'list', the list of submodules to look into for cloning */
14481514
int current;
@@ -1462,20 +1528,23 @@ struct submodule_update_clone {
14621528
const char *recursive_prefix;
14631529
const char *prefix;
14641530

1465-
/* Machine-readable status lines to be consumed by git-submodule.sh */
1466-
struct string_list projectlines;
1531+
/* to be consumed by git-submodule.sh */
1532+
struct update_clone_data *update_clone;
1533+
int update_clone_nr; int update_clone_alloc;
14671534

14681535
/* If we want to stop as fast as possible and return an error */
14691536
unsigned quickstop : 1;
14701537

14711538
/* failed clones to be retried again */
14721539
const struct cache_entry **failed_clones;
14731540
int failed_clones_nr, failed_clones_alloc;
1541+
1542+
int max_jobs;
14741543
};
14751544
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
14761545
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
14771546
NULL, NULL, NULL, \
1478-
STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
1547+
NULL, 0, 0, 0, NULL, 0, 0, 0}
14791548

14801549

14811550
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@@ -1569,11 +1638,12 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
15691638
strbuf_addf(&sb, "%s/.git", ce->name);
15701639
needs_cloning = !file_exists(sb.buf);
15711640

1572-
strbuf_reset(&sb);
1573-
strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
1574-
oid_to_hex(&ce->oid), ce_stage(ce),
1575-
needs_cloning, ce->name);
1576-
string_list_append(&suc->projectlines, sb.buf);
1641+
ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
1642+
suc->update_clone_alloc);
1643+
oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
1644+
suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
1645+
suc->update_clone[suc->update_clone_nr].sub = sub;
1646+
suc->update_clone_nr++;
15771647

15781648
if (!needs_cloning)
15791649
goto cleanup;
@@ -1714,11 +1784,44 @@ static int git_update_clone_config(const char *var, const char *value,
17141784
return 0;
17151785
}
17161786

1787+
static void update_submodule(struct update_clone_data *ucd)
1788+
{
1789+
fprintf(stdout, "dummy %s %d\t%s\n",
1790+
oid_to_hex(&ucd->oid),
1791+
ucd->just_cloned,
1792+
ucd->sub->path);
1793+
}
1794+
1795+
static int update_submodules(struct submodule_update_clone *suc)
1796+
{
1797+
int i;
1798+
1799+
run_processes_parallel(suc->max_jobs,
1800+
update_clone_get_next_task,
1801+
update_clone_start_failure,
1802+
update_clone_task_finished,
1803+
suc);
1804+
1805+
/*
1806+
* We saved the output and put it out all at once now.
1807+
* That means:
1808+
* - the listener does not have to interleave their (checkout)
1809+
* work with our fetching. The writes involved in a
1810+
* checkout involve more straightforward sequential I/O.
1811+
* - the listener can avoid doing any work if fetching failed.
1812+
*/
1813+
if (suc->quickstop)
1814+
return 1;
1815+
1816+
for (i = 0; i < suc->update_clone_nr; i++)
1817+
update_submodule(&suc->update_clone[i]);
1818+
1819+
return 0;
1820+
}
1821+
17171822
static int update_clone(int argc, const char **argv, const char *prefix)
17181823
{
17191824
const char *update = NULL;
1720-
int max_jobs = 1;
1721-
struct string_list_item *item;
17221825
struct pathspec pathspec;
17231826
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
17241827

@@ -1740,7 +1843,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
17401843
OPT_STRING(0, "depth", &suc.depth, "<depth>",
17411844
N_("Create a shallow clone truncated to the "
17421845
"specified number of revisions")),
1743-
OPT_INTEGER('j', "jobs", &max_jobs,
1846+
OPT_INTEGER('j', "jobs", &suc.max_jobs,
17441847
N_("parallel jobs")),
17451848
OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
17461849
N_("whether the initial clone should follow the shallow recommendation")),
@@ -1756,8 +1859,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
17561859
};
17571860
suc.prefix = prefix;
17581861

1759-
update_clone_config_from_gitmodules(&max_jobs);
1760-
git_config(git_update_clone_config, &max_jobs);
1862+
update_clone_config_from_gitmodules(&suc.max_jobs);
1863+
git_config(git_update_clone_config, &suc.max_jobs);
17611864

17621865
argc = parse_options(argc, argv, prefix, module_update_clone_options,
17631866
git_submodule_helper_usage, 0);
@@ -1772,27 +1875,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
17721875
if (pathspec.nr)
17731876
suc.warn_if_uninitialized = 1;
17741877

1775-
run_processes_parallel(max_jobs,
1776-
update_clone_get_next_task,
1777-
update_clone_start_failure,
1778-
update_clone_task_finished,
1779-
&suc);
1780-
1781-
/*
1782-
* We saved the output and put it out all at once now.
1783-
* That means:
1784-
* - the listener does not have to interleave their (checkout)
1785-
* work with our fetching. The writes involved in a
1786-
* checkout involve more straightforward sequential I/O.
1787-
* - the listener can avoid doing any work if fetching failed.
1788-
*/
1789-
if (suc.quickstop)
1790-
return 1;
1791-
1792-
for_each_string_list_item(item, &suc.projectlines)
1793-
fprintf(stdout, "%s", item->string);
1794-
1795-
return 0;
1878+
return update_submodules(&suc);
17961879
}
17971880

17981881
static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@ -1938,6 +2021,45 @@ static int push_check(int argc, const char **argv, const char *prefix)
19382021
return 0;
19392022
}
19402023

2024+
static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
2025+
{
2026+
const struct submodule *sub;
2027+
const char *path;
2028+
char *cw;
2029+
struct repository subrepo;
2030+
2031+
if (argc != 2)
2032+
BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
2033+
2034+
path = argv[1];
2035+
2036+
sub = submodule_from_path(the_repository, &null_oid, path);
2037+
if (!sub)
2038+
BUG("We could get the submodule handle before?");
2039+
2040+
if (repo_submodule_init(&subrepo, the_repository, path))
2041+
die(_("could not get a repository handle for submodule '%s'"), path);
2042+
2043+
if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
2044+
char *cfg_file, *abs_path;
2045+
const char *rel_path;
2046+
struct strbuf sb = STRBUF_INIT;
2047+
2048+
cfg_file = repo_git_path(&subrepo, "config");
2049+
2050+
abs_path = absolute_pathdup(path);
2051+
rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
2052+
2053+
git_config_set_in_file(cfg_file, "core.worktree", rel_path);
2054+
2055+
free(cfg_file);
2056+
free(abs_path);
2057+
strbuf_release(&sb);
2058+
}
2059+
2060+
return 0;
2061+
}
2062+
19412063
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
19422064
{
19432065
int i;
@@ -2015,7 +2137,9 @@ static struct cmd_struct commands[] = {
20152137
{"list", module_list, 0},
20162138
{"name", module_name, 0},
20172139
{"clone", module_clone, 0},
2140+
{"update-module-mode", module_update_module_mode, 0},
20182141
{"update-clone", update_clone, 0},
2142+
{"ensure-core-worktree", ensure_core_worktree, 0},
20192143
{"relative-path", resolve_relative_path, 0},
20202144
{"resolve-relative-url", resolve_relative_url, 0},
20212145
{"resolve-relative-url-test", resolve_relative_url_test, 0},

git-submodule.sh

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -534,31 +534,19 @@ cmd_update()
534534
"$@" || echo "#unmatched" $?
535535
} | {
536536
err=
537-
while read -r mode sha1 stage just_cloned sm_path
537+
while read -r quickabort sha1 just_cloned sm_path
538538
do
539-
die_if_unmatched "$mode" "$sha1"
539+
die_if_unmatched "$quickabort" "$sha1"
540540

541-
name=$(git submodule--helper name "$sm_path") || exit
542-
if ! test -z "$update"
543-
then
544-
update_module=$update
545-
else
546-
update_module=$(git config submodule."$name".update)
547-
if test -z "$update_module"
548-
then
549-
update_module="checkout"
550-
fi
551-
fi
541+
git submodule--helper ensure-core-worktree "$sm_path"
542+
543+
update_module=$(git submodule--helper update-module-mode $just_cloned "$sm_path" $update)
552544

553545
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
554546

555547
if test $just_cloned -eq 1
556548
then
557549
subsha1=
558-
case "$update_module" in
559-
merge | rebase | none)
560-
update_module=checkout ;;
561-
esac
562550
else
563551
subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
564552
git rev-parse --verify HEAD) ||
@@ -630,7 +618,7 @@ cmd_update()
630618
must_die_on_failure=yes
631619
;;
632620
*)
633-
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
621+
die "$(eval_gettext "Invalid update mode '$update_module' for submodule path '$path'")"
634622
esac
635623

636624
if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")

0 commit comments

Comments
 (0)