From: Stefan Beller <sbeller@google.com>
To: git@vger.kernel.org
Cc: jacob.keller@gmail.com, peff@peff.net, gitster@pobox.com,
jrnieder@gmail.com, johannes.schindelin@gmail.com,
Jens.Lehmann@web.de, vlovich@gmail.com,
Stefan Beller <sbeller@google.com>
Subject: [PATCHv3 13/13] Rewrite submodule update in C
Date: Mon, 21 Sep 2015 15:39:19 -0700 [thread overview]
Message-ID: <1442875159-13027-14-git-send-email-sbeller@google.com> (raw)
In-Reply-To: <1442875159-13027-1-git-send-email-sbeller@google.com>
This will make parallelisation easier in a followup patch. This is just
a translation from shell to C, hopefully not introducing any bugs.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
builtin/submodule--helper.c | 247 ++++++++++++++++++++++++++++++++++++++++++++
git-submodule.sh | 135 +-----------------------
run-command.h | 2 +
3 files changed, 252 insertions(+), 132 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f4c3eff..baa7563 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -255,6 +255,252 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
+struct module_update_data {
+ struct module_list list;
+ int count;
+
+ struct pathspec pathspec;
+
+ int no_fetch;
+ int force;
+ int update;
+ int quiet;
+ int recursive;
+ int remote;
+ char *prefix;
+ char *reference;
+ char *depth;
+
+ struct argv_array args;
+
+ int result;
+};
+
+static void module_update_data_init(struct module_update_data *mud)
+{
+ mud->list.entries = NULL;
+ mud->list.alloc = 0;
+ mud->list.nr = 0;
+
+ memset(&mud->pathspec, 0, sizeof(mud->pathspec));
+
+ mud->count = 0;
+ mud->no_fetch = 0;
+ mud->force = 0;
+ mud->update = 0;
+ mud->quiet = 0;
+ mud->remote = 0;
+ mud->recursive = 0;
+ mud->result = 0;
+
+ mud->prefix = NULL;
+ mud->reference = NULL;
+ mud->depth = NULL;
+
+ argv_array_init(&mud->args);
+}
+
+static int update_next_task(void *data,
+ struct child_process *cp,
+ struct strbuf *err)
+{
+ int i;
+ struct module_update_data *mud = data;
+ struct strbuf sb = STRBUF_INIT;
+ const char *displaypath;
+
+ for (; mud->count < mud->list.nr; mud->count++) {
+ const char *update_module;
+ const char *sm_gitdir;
+ const struct submodule *sub;
+ const struct cache_entry *ce = mud->list.entries[mud->count];
+
+ displaypath = relative_path(ce->name, mud->prefix, &sb);
+ strbuf_reset(&sb);
+
+ if (ce_stage(ce)) {
+ strbuf_addf(err, "Skipping unmerged submodule %s",
+ displaypath);
+ continue;
+ }
+
+ sub = submodule_from_path(null_sha1, ce->name);
+ if (!sub) {
+ mud->result = 1;
+ return 0;
+ }
+
+ switch (mud->update) {
+ case 'r':
+ update_module = "rebase";
+ break;
+ case 'c':
+ update_module = "checkout";
+ break;
+ case 'm':
+ update_module = "merge";
+ break;
+ case 0:
+ /* not specified by command line */
+ if (sub->update)
+ update_module = sub->update;
+ else
+ update_module = "checkout";
+ break;
+ default:
+ die("BUG: update mode not covered");
+ }
+
+ if (!strcmp(update_module, "none")) {
+ strbuf_addf(err, "Skipping submodule '%s'", displaypath);
+ continue;
+ }
+
+ if (!sub->url) {
+ /*
+ * Only mention uninitialized submodules when its
+ * path have been specified
+ */
+ if (!mud->pathspec.nr)
+ continue;
+
+ strbuf_addf(err,
+ _("Submodule path '%s' not initialized \n"
+ "Maybe you want to use 'update --init'?"),
+ displaypath);
+ continue;
+ }
+
+ strbuf_addf(&sb, "%s/.git", ce->name);
+ sm_gitdir = strbuf_detach(&sb, NULL);
+
+ child_process_init(cp);
+ for (i = 0; local_repo_env[i]; i++)
+ argv_array_pushf(&cp->env_array, "%s", local_repo_env[i]);
+
+ argv_array_pushf(&cp->env_array, "displaypath=%s", displaypath);
+ argv_array_pushf(&cp->env_array, "sm_path=%s", sub->path);
+ argv_array_pushf(&cp->env_array, "name=%s", sub->name);
+ argv_array_pushf(&cp->env_array, "url=%s", sub->url);
+ argv_array_pushf(&cp->env_array, "update_module=%s", update_module);
+
+ cp->git_cmd = 1;
+ cp->stdout_to_stderr = 1;
+ argv_array_push(&cp->args, "submodule");
+ if (!file_exists(sm_gitdir))
+ argv_array_push(&cp->args, "update_clone");
+ else
+ argv_array_push(&cp->args, "update_fetch");
+
+ argv_array_pushf(&cp->args, "%s", ce->name);
+ mud->count++;
+ return 1;
+ }
+ return 0;
+}
+
+void update_subcommand_failure(void *data,
+ struct child_process *cp,
+ struct strbuf *err)
+{
+ struct module_update_data *mud = data;
+ strbuf_addf(err, _("Could not start child process"));
+ mud->result = 1;
+}
+
+void update_child_return(void *data,
+ struct child_process *cp,
+ int result)
+{
+ struct module_update_data *mud = data;
+ mud->result = 1;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix)
+{
+ int init;
+ struct module_update_data mud;
+
+ struct option module_list_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT_BOOL('i', "init", &init,
+ N_("Initialize the submodule if not yet done")),
+ OPT_BOOL(0, "remote", &mud.remote,
+ N_("Update the submodule to the remote branch instead "
+ "of the superprojects specification")),
+ OPT_BOOL('N', "no-fetch", &mud.no_fetch,
+ N_("Don’t fetch new objects from the remote site.")),
+ OPT_BOOL('f', "force", &mud.force,
+ N_("Ignore local changes in submodules")),
+ OPT_CMDMODE('r', "rebase", &mud.update,
+ N_("Rebase local changes in submodules"), 'r'),
+ OPT_CMDMODE('m', "merge", &mud.update,
+ N_("Merge local changes in submodules"), 'm'),
+ OPT_CMDMODE(0, "checkout", &mud.update,
+ N_("Checkout to a detached HEAD in submodules"), 'c'),
+ OPT_BOOL(0, "recursive", &mud.recursive,
+ N_("Update nested submodules")),
+ OPT_STRING(0, "reference", &mud.reference, "<repository>",
+ N_("Use the local reference repository "
+ "instead of a full clone")),
+ OPT_STRING(0, "depth", &mud.depth, "<depth>",
+ N_("Create a shallow clone truncated to the "
+ "specified number of revisions")),
+ OPT__QUIET(&mud.quiet, N_("be quiet")),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper list [--prefix=<path>] [<path>...]"),
+ NULL
+ };
+
+ module_update_data_init(&mud);
+ gitmodules_config();
+
+ argc = parse_options(argc, argv, prefix, module_list_options,
+ git_submodule_helper_usage, 0);
+
+ if (mud.force)
+ argv_array_push(&mud.args, "force=1");
+ if (mud.quiet)
+ argv_array_push(&mud.args, "GIT_QUIET=1");
+ if (mud.recursive)
+ argv_array_push(&mud.args, "recursive=1");
+ if (mud.prefix)
+ argv_array_pushf(&mud.args, "prefix=%s", mud.prefix);
+ if (mud.reference)
+ argv_array_pushf(&mud.args, "reference=%s", mud.reference);
+ if (mud.depth)
+ argv_array_pushf(&mud.args, "depth=%s", mud.depth);
+
+ if (module_list_compute(argc, argv, prefix, &mud.pathspec, &mud.list) < 0)
+ return 1;
+
+ if (init) {
+ const char **argv_init = xmalloc((2 + mud.list.nr) * sizeof(char*));
+ int argc = 0, i, code;
+ argv_init[argc++] = "submodule";
+ argv_init[argc++] = "init";
+
+ for (i = 0; i < mud.list.nr; i++) {
+ const struct cache_entry *ce = mud.list.entries[i];
+ argv_init[argc++] = ce->name;
+ }
+ code = run_command_v_opt(argv_init, RUN_GIT_CMD);
+ if (code)
+ return code;
+ }
+
+ run_processes_parallel(1, &mud,
+ update_next_task,
+ update_subcommand_failure,
+ update_child_return);
+ return 0;
+}
+
struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, const char *);
@@ -264,6 +510,7 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
+ {"update", module_update}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index a1bc8d5..63e9b3b 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -640,6 +640,7 @@ cmd_update_fetch()
die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
fi
remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
+ branch=$(get_submodule_config "$name" branch master)
sha1=$(clear_local_git_env; cd "$sm_path" &&
git rev-parse --verify "${remote_name}/${branch}") ||
die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
@@ -715,137 +716,7 @@ cmd_update_fetch()
#
cmd_update()
{
- # parse $args after "submodule ... update".
- while test $# -ne 0
- do
- case "$1" in
- -q|--quiet)
- GIT_QUIET=1
- ;;
- -i|--init)
- init=1
- ;;
- --remote)
- remote=1
- ;;
- -N|--no-fetch)
- nofetch=1
- ;;
- -f|--force)
- force=$1
- ;;
- -r|--rebase)
- update="rebase"
- ;;
- --reference)
- case "$2" in '') usage ;; esac
- reference="--reference=$2"
- shift
- ;;
- --reference=*)
- reference="$1"
- ;;
- -m|--merge)
- update="merge"
- ;;
- --recursive)
- recursive=1
- ;;
- --checkout)
- update="checkout"
- ;;
- --depth)
- case "$2" in '') usage ;; esac
- depth="--depth=$2"
- shift
- ;;
- --depth=*)
- depth=$1
- ;;
- --)
- shift
- break
- ;;
- -*)
- usage
- ;;
- *)
- break
- ;;
- esac
- shift
- done
-
- if test -n "$init"
- then
- cmd_init "--" "$@" || return
- fi
-
- git submodule--helper list --prefix "$wt_prefix" "$@" | {
- err=
- while read mode sha1 stage sm_path
- do
- die_if_unmatched "$mode"
- if test "$stage" = U
- then
- echo >&2 "Skipping unmerged submodule $prefix$sm_path"
- continue
- fi
- name=$(git submodule--helper name "$sm_path") || exit
- url=$(git config submodule."$name".url)
- branch=$(get_submodule_config "$name" branch master)
- 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
-
- displaypath=$(relative_path "$prefix$sm_path")
-
- if test "$update_module" = "none"
- then
- echo "Skipping submodule '$displaypath'"
- continue
- fi
-
- if test -z "$url"
- then
- # Only mention uninitialized submodules when its
- # path have been specified
- test "$#" != "0" &&
- say "$(eval_gettext "Submodule path '\$displaypath' not initialized
-Maybe you want to use 'update --init'?")"
- continue
- fi
-
- if ! test -d "$sm_path"/.git && ! test -f "$sm_path"/.git
- then
- cmd_update_clone
- else
- cmd_update_fetch
- 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
- }
+ git submodule--helper update ${prefix:+--prefix "$prefix"} "$@"
}
set_name_rev () {
@@ -1243,7 +1114,7 @@ cmd_sync()
while test $# != 0 && test -z "$command"
do
case "$1" in
- add | foreach | init | deinit | update | status | summary | sync)
+ add | foreach | init | deinit | update | update_fetch | update_clone | status | summary | sync)
command=$1
;;
-q|--quiet)
diff --git a/run-command.h b/run-command.h
index 3807fd1..0c1b363 100644
--- a/run-command.h
+++ b/run-command.h
@@ -155,4 +155,6 @@ int run_processes_parallel(int n, void *data,
start_failure_fn,
return_value_fn);
+void run_processes_parallel_schedule_error(struct strbuf *err);
+
#endif
--
2.5.0.275.ge015d2a
prev parent reply other threads:[~2015-09-21 22:39 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-21 22:39 [PATCHv3 00/13] fetch submodules in parallel and a preview on parallel "submodule update" Stefan Beller
2015-09-21 22:39 ` [PATCHv3 01/13] Sending "Fetching submodule <foo>" output to stderr Stefan Beller
2015-09-21 23:47 ` Junio C Hamano
2015-09-21 22:39 ` [PATCHv3 02/13] xread: poll on non blocking fds Stefan Beller
2015-09-21 23:55 ` Junio C Hamano
2015-09-22 4:55 ` Torsten Bögershausen
2015-09-22 6:23 ` Jacob Keller
2015-09-22 18:40 ` Torsten Bögershausen
2015-09-22 19:45 ` Junio C Hamano
2015-09-22 19:49 ` Jeff King
2015-09-22 20:00 ` Junio C Hamano
2015-09-23 0:14 ` Stefan Beller
2015-09-23 0:43 ` Junio C Hamano
2015-09-23 1:51 ` Jeff King
2015-09-21 23:56 ` Eric Sunshine
2015-09-22 15:58 ` Junio C Hamano
2015-09-22 17:38 ` Stefan Beller
2015-09-22 18:21 ` Junio C Hamano
2015-09-22 18:41 ` Stefan Beller
2015-09-21 22:39 ` [PATCHv3 03/13] xread_nonblock: add functionality to read from fds nonblockingly Stefan Beller
2015-09-22 0:02 ` Junio C Hamano
2015-09-22 0:10 ` Junio C Hamano
2015-09-22 6:26 ` Jacob Keller
2015-09-22 6:27 ` Jacob Keller
2015-09-22 15:59 ` Junio C Hamano
2015-09-21 22:39 ` [PATCHv3 04/13] strbuf: add strbuf_read_once to read without blocking Stefan Beller
2015-09-22 0:17 ` Junio C Hamano
2015-09-22 6:29 ` Jacob Keller
2015-09-21 22:39 ` [PATCHv3 05/13] run-command: factor out return value computation Stefan Beller
2015-09-22 0:38 ` Junio C Hamano
2015-09-21 22:39 ` [PATCHv3 06/13] run-command: add an asynchronous parallel child processor Stefan Beller
2015-09-22 1:08 ` Junio C Hamano
2015-09-22 18:28 ` Stefan Beller
2015-09-22 19:53 ` Junio C Hamano
2015-09-22 21:31 ` Stefan Beller
2015-09-22 21:41 ` Junio C Hamano
2015-09-22 21:54 ` Stefan Beller
2015-09-22 22:23 ` Junio C Hamano
2015-09-21 22:39 ` [PATCHv3 07/13] fetch_populated_submodules: use new parallel job processing Stefan Beller
2015-09-22 16:28 ` Junio C Hamano
2015-09-21 22:39 ` [PATCHv3 08/13] submodules: allow parallel fetching, add tests and documentation Stefan Beller
2015-09-21 22:39 ` [PATCHv3 09/13] submodule config: keep update strategy around Stefan Beller
2015-09-22 0:56 ` Eric Sunshine
2015-09-22 15:50 ` Stefan Beller
2015-09-21 22:39 ` [PATCHv3 10/13] git submodule update: cmd_update_recursive Stefan Beller
2015-09-21 22:39 ` [PATCHv3 11/13] git submodule update: cmd_update_clone Stefan Beller
2015-09-21 22:39 ` [PATCHv3 12/13] git submodule update: cmd_update_fetch Stefan Beller
2015-09-21 22:39 ` Stefan Beller [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1442875159-13027-14-git-send-email-sbeller@google.com \
--to=sbeller@google.com \
--cc=Jens.Lehmann@web.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jacob.keller@gmail.com \
--cc=johannes.schindelin@gmail.com \
--cc=jrnieder@gmail.com \
--cc=peff@peff.net \
--cc=vlovich@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).