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
This commit is contained in:
commit
4d6d6ef1fc
@ -1443,6 +1443,72 @@ static int module_clone(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void determine_submodule_update_strategy(struct repository *r,
|
||||
int just_cloned,
|
||||
const char *path,
|
||||
const char *update,
|
||||
struct submodule_update_strategy *out)
|
||||
{
|
||||
const struct submodule *sub = submodule_from_path(r, &null_oid, path);
|
||||
char *key;
|
||||
const char *val;
|
||||
|
||||
key = xstrfmt("submodule.%s.update", sub->name);
|
||||
|
||||
if (update) {
|
||||
trace_printf("parsing update");
|
||||
if (parse_submodule_update_strategy(update, out) < 0)
|
||||
die(_("Invalid update mode '%s' for submodule path '%s'"),
|
||||
update, path);
|
||||
} else if (!repo_config_get_string_const(r, key, &val)) {
|
||||
if (parse_submodule_update_strategy(val, out) < 0)
|
||||
die(_("Invalid update mode '%s' configured for submodule path '%s'"),
|
||||
val, path);
|
||||
} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
|
||||
trace_printf("loaded thing");
|
||||
out->type = sub->update_strategy.type;
|
||||
out->command = sub->update_strategy.command;
|
||||
} else
|
||||
out->type = SM_UPDATE_CHECKOUT;
|
||||
|
||||
if (just_cloned &&
|
||||
(out->type == SM_UPDATE_MERGE ||
|
||||
out->type == SM_UPDATE_REBASE ||
|
||||
out->type == SM_UPDATE_NONE))
|
||||
out->type = SM_UPDATE_CHECKOUT;
|
||||
|
||||
free(key);
|
||||
}
|
||||
|
||||
static int module_update_module_mode(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *path, *update = NULL;
|
||||
int just_cloned;
|
||||
struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
|
||||
|
||||
if (argc < 3 || argc > 4)
|
||||
die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
|
||||
|
||||
just_cloned = git_config_int("just_cloned", argv[1]);
|
||||
path = argv[2];
|
||||
|
||||
if (argc == 4)
|
||||
update = argv[3];
|
||||
|
||||
determine_submodule_update_strategy(the_repository,
|
||||
just_cloned, path, update,
|
||||
&update_strategy);
|
||||
fputs(submodule_strategy_to_string(&update_strategy), stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct update_clone_data {
|
||||
const struct submodule *sub;
|
||||
struct object_id oid;
|
||||
unsigned just_cloned;
|
||||
};
|
||||
|
||||
struct submodule_update_clone {
|
||||
/* index into 'list', the list of submodules to look into for cloning */
|
||||
int current;
|
||||
@ -1462,8 +1528,9 @@ struct submodule_update_clone {
|
||||
const char *recursive_prefix;
|
||||
const char *prefix;
|
||||
|
||||
/* Machine-readable status lines to be consumed by git-submodule.sh */
|
||||
struct string_list projectlines;
|
||||
/* to be consumed by git-submodule.sh */
|
||||
struct update_clone_data *update_clone;
|
||||
int update_clone_nr; int update_clone_alloc;
|
||||
|
||||
/* If we want to stop as fast as possible and return an error */
|
||||
unsigned quickstop : 1;
|
||||
@ -1471,11 +1538,13 @@ 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;
|
||||
};
|
||||
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
|
||||
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
|
||||
NULL, NULL, NULL, \
|
||||
STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
|
||||
NULL, 0, 0, 0, NULL, 0, 0, 0}
|
||||
|
||||
|
||||
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,
|
||||
strbuf_addf(&sb, "%s/.git", ce->name);
|
||||
needs_cloning = !file_exists(sb.buf);
|
||||
|
||||
strbuf_reset(&sb);
|
||||
strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
|
||||
oid_to_hex(&ce->oid), ce_stage(ce),
|
||||
needs_cloning, ce->name);
|
||||
string_list_append(&suc->projectlines, sb.buf);
|
||||
ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
|
||||
suc->update_clone_alloc);
|
||||
oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
|
||||
suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
|
||||
suc->update_clone[suc->update_clone_nr].sub = sub;
|
||||
suc->update_clone_nr++;
|
||||
|
||||
if (!needs_cloning)
|
||||
goto cleanup;
|
||||
@ -1714,11 +1784,44 @@ static int git_update_clone_config(const char *var, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(suc->max_jobs,
|
||||
update_clone_get_next_task,
|
||||
update_clone_start_failure,
|
||||
update_clone_task_finished,
|
||||
suc);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
int max_jobs = 1;
|
||||
struct string_list_item *item;
|
||||
struct pathspec pathspec;
|
||||
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
|
||||
|
||||
@ -1740,7 +1843,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
||||
OPT_STRING(0, "depth", &suc.depth, "<depth>",
|
||||
N_("Create a shallow clone truncated to the "
|
||||
"specified number of revisions")),
|
||||
OPT_INTEGER('j', "jobs", &max_jobs,
|
||||
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")),
|
||||
@ -1756,8 +1859,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
||||
};
|
||||
suc.prefix = prefix;
|
||||
|
||||
update_clone_config_from_gitmodules(&max_jobs);
|
||||
git_config(git_update_clone_config, &max_jobs);
|
||||
update_clone_config_from_gitmodules(&suc.max_jobs);
|
||||
git_config(git_update_clone_config, &suc.max_jobs);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, module_update_clone_options,
|
||||
git_submodule_helper_usage, 0);
|
||||
@ -1772,27 +1875,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
||||
if (pathspec.nr)
|
||||
suc.warn_if_uninitialized = 1;
|
||||
|
||||
run_processes_parallel(max_jobs,
|
||||
update_clone_get_next_task,
|
||||
update_clone_start_failure,
|
||||
update_clone_task_finished,
|
||||
&suc);
|
||||
|
||||
/*
|
||||
* 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_each_string_list_item(item, &suc.projectlines)
|
||||
fprintf(stdout, "%s", item->string);
|
||||
|
||||
return 0;
|
||||
return update_submodules(&suc);
|
||||
}
|
||||
|
||||
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)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const struct submodule *sub;
|
||||
const char *path;
|
||||
char *cw;
|
||||
struct repository subrepo;
|
||||
|
||||
if (argc != 2)
|
||||
BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
|
||||
|
||||
path = argv[1];
|
||||
|
||||
sub = submodule_from_path(the_repository, &null_oid, path);
|
||||
if (!sub)
|
||||
BUG("We could get the submodule handle before?");
|
||||
|
||||
if (repo_submodule_init(&subrepo, the_repository, path))
|
||||
die(_("could not get a repository handle for submodule '%s'"), path);
|
||||
|
||||
if (!repo_config_get_string(&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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@ -2015,7 +2137,9 @@ static struct cmd_struct commands[] = {
|
||||
{"list", module_list, 0},
|
||||
{"name", module_name, 0},
|
||||
{"clone", module_clone, 0},
|
||||
{"update-module-mode", module_update_module_mode, 0},
|
||||
{"update-clone", update_clone, 0},
|
||||
{"ensure-core-worktree", ensure_core_worktree, 0},
|
||||
{"relative-path", resolve_relative_path, 0},
|
||||
{"resolve-relative-url", resolve_relative_url, 0},
|
||||
{"resolve-relative-url-test", resolve_relative_url_test, 0},
|
||||
|
@ -534,31 +534,19 @@ cmd_update()
|
||||
"$@" || echo "#unmatched" $?
|
||||
} | {
|
||||
err=
|
||||
while read -r mode sha1 stage just_cloned sm_path
|
||||
while read -r quickabort sha1 just_cloned sm_path
|
||||
do
|
||||
die_if_unmatched "$mode" "$sha1"
|
||||
die_if_unmatched "$quickabort" "$sha1"
|
||||
|
||||
name=$(git submodule--helper name "$sm_path") || exit
|
||||
if ! test -z "$update"
|
||||
then
|
||||
update_module=$update
|
||||
else
|
||||
update_module=$(git config submodule."$name".update)
|
||||
if test -z "$update_module"
|
||||
then
|
||||
update_module="checkout"
|
||||
fi
|
||||
fi
|
||||
git submodule--helper ensure-core-worktree "$sm_path"
|
||||
|
||||
update_module=$(git submodule--helper update-module-mode $just_cloned "$sm_path" $update)
|
||||
|
||||
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
|
||||
|
||||
if test $just_cloned -eq 1
|
||||
then
|
||||
subsha1=
|
||||
case "$update_module" in
|
||||
merge | rebase | none)
|
||||
update_module=checkout ;;
|
||||
esac
|
||||
else
|
||||
subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
|
||||
git rev-parse --verify HEAD) ||
|
||||
@ -630,7 +618,7 @@ cmd_update()
|
||||
must_die_on_failure=yes
|
||||
;;
|
||||
*)
|
||||
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
|
||||
die "$(eval_gettext "Invalid update mode '$update_module' for submodule path '$path'")"
|
||||
esac
|
||||
|
||||
if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")
|
||||
|
Loading…
Reference in New Issue
Block a user