Subject: [PATCH] Let index-pack help with connectivity check on cloning via smart http

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Sun, 21 Jul 2013 15:18:05 +0700

This is an extension of c6807a4 (clone: open a shortcut for
connectivity check - 2013-05-26) to reduce the cost of connectivity
check at clone time, this time with smart http protocol.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 Documentation/git-fetch-pack.txt    |  4 ++++
 Documentation/gitremote-helpers.txt | 10 ++++++++++
 builtin/fetch-pack.c                |  9 +++++++++
 remote-curl.c                       | 15 ++++++++++++++-
 transport-helper.c                  | 10 ++++++++++
 5 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index 1e71754..444b805 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -90,6 +90,10 @@ be in a separate packet, and the list must end with a flush packet.
 --no-progress::
 	Do not show the progress.
 
+--check-self-contained-and-connected::
+	Output "connectivity-ok" if the received pack is
+	self-contained and connected.
+
 -v::
 	Run verbosely.
 
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index 0827f69..bc069c2 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -143,6 +143,10 @@ Supported commands: 'list', 'fetch'.
 +
 Supported commands: 'list', 'import'.
 
+'check-connectivity'::
+	Can guarantee that when a clone is requested, the received
+	pack is self contained and is connected.
+
 If a helper advertises 'connect', Git will use it if possible and
 fall back to another capability if the helper requests so when
 connecting (see the 'connect' command under COMMANDS).
@@ -270,6 +274,9 @@ Optionally may output a 'lock <file>' line indicating a file under
 GIT_DIR/objects/pack which is keeping a pack until refs can be
 suitably updated.
 +
+If option 'check-connectivity' is requested, the helper must output
+'connectivity-ok' if the clone is self-contained and connected.
++
 Supported if the helper has the "fetch" capability.
 
 'push' +<src>:<dst>::
@@ -416,6 +423,9 @@ set by Git if the remote helper has the 'option' capability.
 	must not rely on this option being set before
 	connect request occurs.
 
+'option check-connectivity' \{'true'|'false'\}::
+	Request the helper to check connectivity of a clone.
+
 SEE ALSO
 --------
 linkgit:git-remote[1]
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index aba4465..3e19d71 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -100,6 +100,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 			pack_lockfile_ptr = &pack_lockfile;
 			continue;
 		}
+		if (!strcmp("--check-self-contained-and-connected", arg)) {
+			args.check_self_contained_and_connected = 1;
+			continue;
+		}
 		usage(fetch_pack_usage);
 	}
 
@@ -152,6 +156,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 		printf("lock %s\n", pack_lockfile);
 		fflush(stdout);
 	}
+	if (args.check_self_contained_and_connected &&
+	    args.self_contained_and_connected) {
+		printf("connectivity-ok\n");
+		fflush(stdout);
+	}
 	close(fd[0]);
 	close(fd[1]);
 	if (finish_connect(conn))
diff --git a/remote-curl.c b/remote-curl.c
index 5b3ce9e..6918668 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -16,6 +16,7 @@ struct options {
 	int verbosity;
 	unsigned long depth;
 	unsigned progress : 1,
+		check_self_contained_and_connected : 1,
 		followtags : 1,
 		dry_run : 1,
 		thin : 1;
@@ -67,6 +68,15 @@ static int set_option(const char *name, const char *value)
 			return -1;
 		return 0;
 	}
+	else if (!strcmp(name, "check-connectivity")) {
+		if (!strcmp(value, "true"))
+			options.check_self_contained_and_connected = 1;
+		else if (!strcmp(value, "false"))
+			options.check_self_contained_and_connected = 0;
+		else
+			return -1;
+		return 0;
+	}
 	else {
 		return 1 /* unsupported */;
 	}
@@ -654,7 +664,7 @@ static int fetch_git(struct discovery *heads,
 	struct strbuf preamble = STRBUF_INIT;
 	char *depth_arg = NULL;
 	int argc = 0, i, err;
-	const char *argv[15];
+	const char *argv[16];
 
 	argv[argc++] = "fetch-pack";
 	argv[argc++] = "--stateless-rpc";
@@ -668,6 +678,8 @@ static int fetch_git(struct discovery *heads,
 		argv[argc++] = "-v";
 		argv[argc++] = "-v";
 	}
+	if (options.check_self_contained_and_connected)
+		argv[argc++] = "--check-self-contained-and-connected";
 	if (!options.progress)
 		argv[argc++] = "--no-progress";
 	if (options.depth) {
@@ -939,6 +951,7 @@ int main(int argc, const char **argv)
 			printf("fetch\n");
 			printf("option\n");
 			printf("push\n");
+			printf("check-connectivity\n");
 			printf("\n");
 			fflush(stdout);
 		} else {
diff --git a/transport-helper.c b/transport-helper.c
index db9bd18..e39b032 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -27,6 +27,7 @@ struct helper_data {
 		push : 1,
 		connect : 1,
 		signed_tags : 1,
+		check_connectivity : 1,
 		no_disconnect_req : 1;
 	char *export_marks;
 	char *import_marks;
@@ -186,6 +187,8 @@ static struct child_process *get_helper(struct transport *transport)
 			data->bidi_import = 1;
 		else if (!strcmp(capname, "export"))
 			data->export = 1;
+		else if (!strcmp(capname, "check-connectivity"))
+			data->check_connectivity = 1;
 		else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
 			ALLOC_GROW(refspecs,
 				   refspec_nr + 1,
@@ -349,6 +352,9 @@ static int fetch_with_fetch(struct transport *transport,
 	struct strbuf buf = STRBUF_INIT;
 
 	standard_options(transport);
+	if (data->check_connectivity &&
+	    data->transport_options.check_self_contained_and_connected)
+		set_helper_option(transport, "check-connectivity", "true");
 
 	for (i = 0; i < nr_heads; i++) {
 		const struct ref *posn = to_fetch[i];
@@ -372,6 +378,10 @@ static int fetch_with_fetch(struct transport *transport,
 			else
 				transport->pack_lockfile = xstrdup(name);
 		}
+		else if (data->check_connectivity &&
+			 data->transport_options.check_self_contained_and_connected &&
+			 !strcmp(buf.buf, "connectivity-ok"))
+			data->transport_options.self_contained_and_connected = 1;
 		else if (!buf.len)
 			break;
 		else
-- 
1.8.2.83.gc99314b