git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
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

      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).