git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC PATCH v4 10/26] remote-helpers: Support custom transport options

From
Shawn O. Pearce <spearce@spearce.org>
Date
Oct 29, 2009, 00:00 UTC
Message-ID
<1256774448-7625-11-git-send-email-spearce@spearce.org>
In-Reply-To
<1256774448-7625-1-git-send-email-spearce@spearce.org>

Some transports, like the native pack transport implemented by fetch-pack, support useful features like depth or include tags. These should be exposed if the underlying helper knows how to use them.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
CC: Daniel Barkalow <barkalow@iabervon.org>
---
 Documentation/git-remote-helpers.txt |   38 +++++++++++++++
 remote-curl.c                        |   74 ++++++++++++++++++++++++++++-
 transport-helper.c                   |   88 +++++++++++++++++++++++++++++++++-
 3 files changed, 198 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index e44d821..1133f04 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/git-remote-helpers.txt
@@ -35,6 +35,16 @@ Commands are given by the caller on the helper's standard input, one per line.
 	the name; unrecognized attributes are ignored. After the
 	complete list, outputs a blank line.
 
+'option' <name> <value>::
+	Set the transport helper option <name> to <value>.  Outputs a
+	single line containing one of 'ok' (option successfully set),
+	'unsupported' (option not recognized) or 'error <msg>'
+	(option <name> is supported but <value> is not correct
+	for it).  Options should be set before other commands,
+	and may how those commands behave.
++
+Supported if the helper has the "option" capability.
+
 'fetch' <sha1> <name>::
 	Fetches the given object, writing the necessary objects
 	to the database.  Fetch commands are sent in a batch, one
@@ -63,11 +73,39 @@ CAPABILITIES
 'fetch'::
 	This helper supports the 'fetch' command.
 
+'option'::
+	This helper supports the option command.
+
 REF LIST ATTRIBUTES
 -------------------
 
 None are defined yet, but the caller must accept any which are supplied.
 
+OPTIONS
+-------
+'option verbosity' <N>::
+	Change the level of messages displayed by the helper.
+	When N is 0 the end-user has asked the process to be
+	quiet, and the helper should produce only error output.
+	N of 1 is the default level of verbosity, higher values
+	of N correspond to the number of -v flags passed on the
+	command line.
+
+'option progress' \{'true'|'false'\}::
+	Enable (or disable) progress messages displayed by the
+	transport helper during a command.
+
+'option depth' <depth>::
+	Deepen the history of a shallow repository.
+
+'option followtags' \{'true'|'false'\}::
+	If enabled the helper should automatically fetch annotated
+	tag objects if the object the tag points at was transferred
+	during the fetch command.  If the tag is not fetched by
+	the helper a second fetch command will usually be sent to
+	ask for the tag specifically.  Some helpers may be able to
+	use this option to avoid a second network connection.
+
 Documentation
 -------------
 Documentation by Daniel Barkalow.
diff --git a/remote-curl.c b/remote-curl.c
index 22cd5c5..0951f11 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -9,12 +9,61 @@ static struct remote *remote;
 static const char *url;
 static struct walker *walker;
 
+struct options {
+	int verbosity;
+	unsigned long depth;
+	unsigned progress : 1,
+		followtags : 1;
+};
+static struct options options;
+
 static void init_walker(void)
 {
 	if (!walker)
 		walker = get_http_walker(url, remote);
 }
 
+static int set_option(const char *name, const char *value)
+{
+	if (!strcmp(name, "verbosity")) {
+		char *end;
+		int v = strtol(value, &end, 10);
+		if (value == end || *end)
+			return -1;
+		options.verbosity = v;
+		return 0;
+	}
+	else if (!strcmp(name, "progress")) {
+		if (!strcmp(value, "true"))
+			options.progress = 1;
+		else if (!strcmp(value, "false"))
+			options.progress = 0;
+		else
+			return -1;
+		return 1 /* TODO implement later */;
+	}
+	else if (!strcmp(name, "depth")) {
+		char *end;
+		unsigned long v = strtoul(value, &end, 10);
+		if (value == end || *end)
+			return -1;
+		options.depth = v;
+		return 1 /* TODO implement later */;
+	}
+	else if (!strcmp(name, "followtags")) {
+		if (!strcmp(value, "true"))
+			options.followtags = 1;
+		else if (!strcmp(value, "false"))
+			options.followtags = 0;
+		else
+			return -1;
+		return 1 /* TODO implement later */;
+	}
+	else {
+		return 1 /* unsupported */;
+	}
+}
+
 static struct ref *get_refs(void)
 {
 	struct strbuf buffer = STRBUF_INIT;
@@ -99,7 +148,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
 	walker->get_all = 1;
 	walker->get_tree = 1;
 	walker->get_history = 1;
-	walker->get_verbosely = 0;
+	walker->get_verbosely = options.verbosity >= 3;
 	walker->get_recover = 0;
 	ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
 
@@ -173,6 +222,9 @@ int main(int argc, const char **argv)
 		return 1;
 	}
 
+	options.verbosity = 1;
+	options.progress = !!isatty(2);
+
 	remote = remote_get(argv[1]);
 
 	if (argc > 2) {
@@ -198,8 +250,28 @@ int main(int argc, const char **argv)
 			}
 			printf("\n");
 			fflush(stdout);
+		} else if (!prefixcmp(buf.buf, "option ")) {
+			char *name = buf.buf + strlen("option ");
+			char *value = strchr(name, ' ');
+			int result;
+
+			if (value)
+				*value++ = '\0';
+			else
+				value = "true";
+
+			result = set_option(name, value);
+			if (!result)
+				printf("ok\n");
+			else if (result < 0)
+				printf("error invalid value\n");
+			else
+				printf("unsupported\n");
+			fflush(stdout);
+
 		} else if (!strcmp(buf.buf, "capabilities")) {
 			printf("fetch\n");
+			printf("option\n");
 			printf("\n");
 			fflush(stdout);
 		} else {
diff --git a/transport-helper.c b/transport-helper.c
index 9de3408..577abc6 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -5,13 +5,15 @@
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
+#include "quote.h"
 
 struct helper_data
 {
 	const char *name;
 	struct child_process *helper;
 	FILE *out;
-	unsigned fetch : 1;
+	unsigned fetch : 1,
+		option : 1;
 };
 
 static struct child_process *get_helper(struct transport *transport)
@@ -48,6 +50,8 @@ static struct child_process *get_helper(struct transport *transport)
 			break;
 		if (!strcmp(buf.buf, "fetch"))
 			data->fetch = 1;
+		if (!strcmp(buf.buf, "option"))
+			data->option = 1;
 	}
 	return data->helper;
 }
@@ -65,9 +69,88 @@ static int disconnect_helper(struct transport *transport)
 		free(data->helper);
 		data->helper = NULL;
 	}
+	free(data);
 	return 0;
 }
 
+static const char *unsupported_options[] = {
+	TRANS_OPT_UPLOADPACK,
+	TRANS_OPT_RECEIVEPACK,
+	TRANS_OPT_THIN,
+	TRANS_OPT_KEEP
+	};
+static const char *boolean_options[] = {
+	TRANS_OPT_THIN,
+	TRANS_OPT_KEEP,
+	TRANS_OPT_FOLLOWTAGS
+	};
+
+static int set_helper_option(struct transport *transport,
+			  const char *name, const char *value)
+{
+	struct helper_data *data = transport->data;
+	struct child_process *helper = get_helper(transport);
+	struct strbuf buf = STRBUF_INIT;
+	int i, ret, is_bool = 0;
+
+	if (!data->option)
+		return 1;
+
+	for (i = 0; i < ARRAY_SIZE(unsupported_options); i++) {
+		if (!strcmp(name, unsupported_options[i]))
+			return 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(boolean_options); i++) {
+		if (!strcmp(name, boolean_options[i])) {
+			is_bool = 1;
+			break;
+		}
+	}
+
+	strbuf_addf(&buf, "option %s ", name);
+	if (is_bool)
+		strbuf_addstr(&buf, value ? "true" : "false");
+	else
+		quote_c_style(value, &buf, NULL, 0);
+	strbuf_addch(&buf, '\n');
+
+	if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
+		die_errno("cannot send option to %s", data->name);
+
+	strbuf_reset(&buf);
+	if (strbuf_getline(&buf, data->out, '\n') == EOF)
+		exit(128); /* child died, message supplied already */
+
+	if (!strcmp(buf.buf, "ok"))
+		ret = 0;
+	else if (!prefixcmp(buf.buf, "error")) {
+		ret = -1;
+	} else if (!strcmp(buf.buf, "unsupported"))
+		ret = 1;
+	else {
+		warning("%s unexpectedly said: '%s'", data->name, buf.buf);
+		ret = 1;
+	}
+	strbuf_release(&buf);
+	return ret;
+}
+
+static void standard_options(struct transport *t)
+{
+	char buf[16];
+	int n;
+	int v = t->verbose;
+	int no_progress = v < 0 || (!t->progress && !isatty(1));
+
+	set_helper_option(t, "progress", !no_progress ? "true" : "false");
+
+	n = snprintf(buf, sizeof(buf), "%d", v + 1);
+	if (n >= sizeof(buf))
+		die("impossibly large verbosity value");
+	set_helper_option(t, "verbosity", buf);
+}
+
 static int fetch_with_fetch(struct transport *transport,
 			    int nr_heads, const struct ref **to_fetch)
 {
@@ -75,6 +158,8 @@ static int fetch_with_fetch(struct transport *transport,
 	int i;
 	struct strbuf buf = STRBUF_INIT;
 
+	standard_options(transport);
+
 	for (i = 0; i < nr_heads; i++) {
 		const struct ref *posn = to_fetch[i];
 		if (posn->status & REF_STATUS_UPTODATE)
@@ -178,6 +263,7 @@ int transport_helper_init(struct transport *transport, const char *name)
 	data->name = name;
 
 	transport->data = data;
+	transport->set_option = set_helper_option;
 	transport->get_refs_list = get_refs_list;
 	transport->fetch = fetch;
 	transport->disconnect = disconnect_helper;
-- 
1.6.5.2.181.gd6f41
Previous: Shawn O. PearceNext: Shawn O. Pearce
Message 24 of 60 in “Return of smart HTTP”
  1. 00/26 Return of smart HTTPShawn O. Pearce, Oct 29, 2009
  2. 01/26 http-push: fix check condition on http.c::finish_http_pack_request()Shawn O. Pearce, Oct 29, 2009
  3. 02/26 pkt-line: Add strbuf based functionsShawn O. Pearce, Oct 29, 2009
  4. 03/26 pkt-line: Make packet_read_line easier to debugShawn O. Pearce, Oct 29, 2009
  5. Junio C HamanoOct 29, 2009
  6. Shawn O. PearceOct 29, 2009
  7. Junio C HamanoOct 29, 2009
  8. Shawn O. PearceOct 29, 2009
  9. Jeff KingOct 30, 2009
  10. Shawn O. PearceOct 30, 2009
  11. Jeff KingOct 30, 2009
  12. David BrownOct 30, 2009
  13. Junio C HamanoOct 30, 2009
  14. 04/26 fetch-pack: Use a strbuf to compose the want listShawn O. Pearce, Oct 29, 2009
  15. 05/26 Move "get_ack()" back to fetch-packShawn O. Pearce, Oct 29, 2009
  16. Junio C HamanoOct 29, 2009
  17. Shawn O. PearceOct 29, 2009
  18. 06/26 Add multi_ack_detailed capability to fetch-pack/upload-packShawn O. Pearce, Oct 29, 2009
  19. Junio C HamanoOct 29, 2009
  20. Shawn O. PearceOct 29, 2009
  21. 07/26 remote-curl: Refactor walker initializationShawn O. Pearce, Oct 29, 2009
  22. 08/26 fetch: Allow transport -v -v -v to set verbosity to 3Shawn O. Pearce, Oct 29, 2009
  23. 09/26 remote-helpers: Fetch more than one ref in a batchShawn O. Pearce, Oct 29, 2009
  24. 10/26 remote-helpers: Support custom transport optionsShawn O. Pearce, Oct 29, 2009
  25. 11/26 Move WebDAV HTTP push under remote-curlShawn O. Pearce, Oct 29, 2009
  26. Tay Ray ChuanOct 30, 2009
  27. Shawn O. PearceOct 31, 2009
  28. Tay Ray ChuanOct 30, 2009
  29. Clemens BuchacherOct 30, 2009
  30. Tay Ray ChuanOct 30, 2009
  31. 12/26 remote-helpers: return successfully if everything up-to-dateShawn O. Pearce, Oct 29, 2009
  32. 13/26 Git-aware CGI to provide dumb HTTP transportShawn O. Pearce, Oct 29, 2009
  33. 14/26 Add stateless RPC options to upload-pack, receive-packShawn O. Pearce, Oct 29, 2009
  34. Junio C HamanoOct 29, 2009
  35. Shawn O. PearceOct 29, 2009
  36. Junio C HamanoOct 29, 2009
  37. Shawn O. PearceOct 30, 2009
  38. 15/26 Smart fetch and push over HTTP: server sideShawn O. Pearce, Oct 29, 2009
  39. 16/26 http-backend: add GIT_PROJECT_ROOT environment varShawn O. Pearce, Oct 29, 2009
  40. 17/26 http-backend: reword some documentationShawn O. Pearce, Oct 29, 2009
  41. 18/26 http-backend: use mod_alias instead of mod_rewriteShawn O. Pearce, Oct 29, 2009
  42. 19/26 http-backend: add example for gitweb on same URLShawn O. Pearce, Oct 29, 2009
  43. 20/26 http-backend: more explict LocationMatchShawn O. Pearce, Oct 29, 2009
  44. 21/26 Discover refs via smart HTTP server when availableShawn O. Pearce, Oct 29, 2009
  45. 22/26 Smart push over HTTP: client sideShawn O. Pearce, Oct 29, 2009
  46. 23/26 Smart fetch over HTTP: client sideShawn O. Pearce, Oct 29, 2009
  47. 24/26 Smart HTTP fetch: gzip requestsShawn O. Pearce, Oct 29, 2009
  48. 25/26 t5540-http-push: remove redundant fetchesShawn O. Pearce, Oct 29, 2009
  49. 26/26 test smart http fetch and pushShawn O. Pearce, Oct 29, 2009
  50. Clemens BuchacherOct 29, 2009
  51. Shawn O. PearceOct 29, 2009
  52. Junio C HamanoOct 29, 2009
  53. Shawn O. PearceOct 29, 2009
  54. Shawn O. PearceOct 29, 2009
  55. Junio C HamanoOct 30, 2009
  56. Shawn O. PearceOct 30, 2009
  57. Tay Ray ChuanOct 30, 2009
  58. Shawn O. PearceOct 31, 2009
  59. Jakub NarebskiOct 29, 2009
  60. Shawn O. PearceOct 29, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.