{"thread":{"id":"25297","subject":"[PATCH v2 0/3] git-remote-fd & git-remote-ext","startedAt":"2010-09-30T11:52:56Z","lastAt":"2010-10-01T00:30:22Z","messageCount":13,"participants":["Ilari Liusvaara","Ævar Arnfjörð Bjarmason","Jonathan Nieder","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"152126","messageId":"1285847579-21954-1-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"25297","inReplyTo":null,"subject":"[PATCH v2 0/3] git-remote-fd & git-remote-ext","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-09-30T11:52:56Z","receivedAt":"2010-09-30T11:52:56Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"This adds two new remote helpers.\n\n* git-remote-fd, which connects to git service on given file descriptor(s),\nuseful for graphical user interfaces that want to use internal ssh client.\n\n* git-remote-ext, which connect to git service using external program. Useful\nfor connecting using odd one-off ssh options, to services in abstract\nnamespace, using unix domain sockets, using TLS, etc...\n\n\nDifferences from last time:\n\n* The mingw build patch is now included.\n* Include some documentation.\n* Patches squashed into more logical chunks instead of base and discrete\nfixes.\n\nIlari Liusvaara (3):\n  Add bidirectional_transfer_loop()\n  git-remote-fd\n  git-remote-ext\n\n Documentation/git-remote-ext.txt |   87 +++++++++++++\n Documentation/git-remote-fd.txt  |   57 +++++++++\n Makefile                         |    2 +\n builtin.h                        |    2 +\n builtin/remote-fd.c              |   88 +++++++++++++\n compat/mingw.h                   |    5 +\n git.c                            |    2 +\n transport-helper.c               |  254 ++++++++++++++++++++++++++++++++++++++\n transport.h                      |    1 +\n 9 files changed, 498 insertions(+), 0 deletions(-)\n create mode 100644 Documentation/git-remote-ext.txt\n create mode 100644 Documentation/git-remote-fd.txt\n create mode 100644 builtin/remote-fd.c\n\n-- \n1.7.2.3.401.g919b6e\n"},{"id":"152128","messageId":"1285847579-21954-2-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"25297","inReplyTo":"1285847579-21954-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"[PATCH v2 1/3] Add bidirectional_transfer_loop()","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-09-30T11:52:57Z","receivedAt":"2010-09-30T11:52:57Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"This helper function copies bidirectional stream of data between\nstdin/stdout and specified file descriptors.\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\n compat/mingw.h     |    5 +\n transport-helper.c |  254 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n transport.h        |    1 +\n 3 files changed, 260 insertions(+), 0 deletions(-)\n\ndiff --git a/compat/mingw.h b/compat/mingw.h\nindex 3b2477b..f27a7b6 100644\n--- a/compat/mingw.h\n+++ b/compat/mingw.h\n@@ -23,6 +23,9 @@ typedef int pid_t;\n #define WEXITSTATUS(x) ((x) & 0xff)\n #define WTERMSIG(x) SIGTERM\n \n+#define EWOULDBLOCK EAGAIN\n+#define SHUT_WR SD_SEND\n+\n #define SIGHUP 1\n #define SIGQUIT 3\n #define SIGKILL 9\n@@ -50,6 +53,8 @@ struct pollfd {\n };\n #define POLLIN 1\n #define POLLHUP 2\n+#define POLLOUT 4\n+#define POLLNVAL 8\n #endif\n \n typedef void (__cdecl *sig_handler_t)(int);\ndiff --git a/transport-helper.c b/transport-helper.c\nindex acfc88e..1ebcebc 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -862,3 +862,257 @@ int transport_helper_init(struct transport *transport, const char *name)\n \ttransport->smart_options = &(data->transport_options);\n \treturn 0;\n }\n+\n+\n+#define BUFFERSIZE 4096\n+#define PBUFFERSIZE 8192\n+\n+/* Print bidirectional transfer loop debug message. */\n+static void transfer_debug(const char *fmt, ...)\n+{\n+\tva_list args;\n+\tchar msgbuf[PBUFFERSIZE];\n+\tstatic int debug_enabled = -1;\n+\n+\tif (debug_enabled < 0)\n+\t\tdebug_enabled = getenv(\"GIT_TRANSLOOP_DEBUG\") ? 1 : 0;\n+\tif (!debug_enabled)\n+\t\treturn;\n+\n+\tsprintf(msgbuf, \"Transfer loop debugging: \");\n+\tva_start(args, fmt);\n+\tvsprintf(msgbuf + strlen(msgbuf), fmt, args);\n+\tva_end(args);\n+\tfprintf(stderr, \"%s\\n\", msgbuf);\n+}\n+\n+/* Load the parameters into poll structure. Return number of entries loaded */\n+static int load_poll_params(struct pollfd *polls, size_t inbufuse,\n+\tsize_t outbufuse, int in_hup, int out_hup, int in_closed,\n+\tint out_closed, int socket_mode, int input_fd, int output_fd)\n+{\n+\tint stdin_index = -1;\n+\tint stdout_index = -1;\n+\tint input_index = -1;\n+\tint output_index = -1;\n+\tint nextindex = 0;\n+\tint i;\n+\n+\t/*\n+\t * Inputs can't be waited at all if buffer is full since we can't\n+\t * do read on 0 bytes as it could do strange things.\n+\t */\n+\tif (!in_hup && inbufuse < BUFFERSIZE) {\n+\t\tstdin_index = nextindex++;\n+\t\tpolls[stdin_index].fd = 0;\n+\t\ttransfer_debug(\"Adding stdin to fds to wait for\");\n+\t}\n+\tif (!out_hup && outbufuse < BUFFERSIZE) {\n+\t\tinput_index = nextindex++;\n+\t\tpolls[input_index].fd = input_fd;\n+\t\ttransfer_debug(\"Adding remote input to fds to wait for\");\n+\t}\n+\tif (!out_closed && outbufuse > 0) {\n+\t\tstdout_index = nextindex++;\n+\t\tpolls[stdout_index].fd = 1;\n+\t\ttransfer_debug(\"Adding stdout to fds to wait for\");\n+\t}\n+\tif (!in_closed && inbufuse > 0) {\n+\t\tif (socket_mode && input_index >= 0)\n+\t\t\toutput_index = input_index;\n+\t\telse {\n+\t\t\toutput_index = nextindex++;\n+\t\t\tpolls[output_index].fd = output_fd;\n+\t\t}\n+\t\ttransfer_debug(\"Adding remote output to fds to wait for\");\n+\t}\n+\n+\tfor (i = 0; i < nextindex; i++)\n+\t\tpolls[i].events = polls[i].revents = 0;\n+\n+\tif (stdin_index >= 0) {\n+\t\tpolls[stdin_index].events |= POLLIN;\n+\t\ttransfer_debug(\"Waiting for stdin to become readable\");\n+\t}\n+\tif (input_index >= 0) {\n+\t\tpolls[input_index].events |= POLLIN;\n+\t\ttransfer_debug(\"Waiting for remote input to become readable\");\n+\t}\n+\tif (stdout_index >= 0) {\n+\t\tpolls[stdout_index].events |= POLLOUT;\n+\t\ttransfer_debug(\"Waiting for stdout to become writable\");\n+\t}\n+\tif (output_index >= 0) {\n+\t\tpolls[output_index].events |= POLLOUT;\n+\t\ttransfer_debug(\"Waiting for remote output to become writable\");\n+\t}\n+\n+\t/* Return number of indexes assigned. */\n+\treturn nextindex;\n+}\n+\n+static int transfer_handle_events(struct pollfd* polls, char *in_buffer,\n+\tchar *out_buffer, size_t *in_buffer_use, size_t *out_buffer_use,\n+\tint *in_hup, int *out_hup, int *in_closed, int *out_closed,\n+\tint socket_mode, int poll_count, int input, int output)\n+{\n+\tint i, r;\n+\tfor(i = 0; i < poll_count; i++) {\n+\t\t/* Handle stdin. */\n+\t\tif (polls[i].fd == 0 && polls[i].revents & (POLLIN | POLLHUP)) {\n+\t\t\ttransfer_debug(\"stdin is readable\");\n+\t\t\tr = read(0, in_buffer + *in_buffer_use, BUFFERSIZE -\n+\t\t\t\t*in_buffer_use);\n+\t\t\tif (r < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&\n+\t\t\t\terrno != EINTR) {\n+\t\t\t\tperror(\"read(git) failed\");\n+\t\t\t\treturn 1;\n+\t\t\t} else if (r == 0) {\n+\t\t\t\ttransfer_debug(\"stdin EOF\");\n+\t\t\t\t*in_hup = 1;\n+\t\t\t\tif (!*in_buffer_use) {\n+\t\t\t\t\tif (socket_mode)\n+\t\t\t\t\t\tshutdown(output, SHUT_WR);\n+\t\t\t\t\telse\n+\t\t\t\t\t\tclose(output);\n+\t\t\t\t\t*in_closed = 1;\n+\t\t\t\t\ttransfer_debug(\"Closed remote output\");\n+\t\t\t\t} else\n+\t\t\t\t\ttransfer_debug(\"Delaying remote output close because input buffer has data\");\n+\t\t\t} else if (r > 0) {\n+\t\t\t\t*in_buffer_use += r;\n+\t\t\t\ttransfer_debug(\"Read %i bytes from stdin (buffer now at %i)\", r, (int)*in_buffer_use);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Handle remote end input. */\n+\t\tif (polls[i].fd == input &&\n+\t\t\tpolls[i].revents & (POLLIN | POLLHUP)) {\n+\t\t\ttransfer_debug(\"remote input is readable\");\n+\t\t\tr = read(input, out_buffer + *out_buffer_use,\n+\t\t\t\tBUFFERSIZE - *out_buffer_use);\n+\t\t\tif (r < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&\n+\t\t\t\terrno != EINTR) {\n+\t\t\t\tperror(\"read(connection) failed\");\n+\t\t\t\treturn 1;\n+\t\t\t} else if (r == 0) {\n+\t\t\t\ttransfer_debug(\"remote input EOF\");\n+\t\t\t\t*out_hup = 1;\n+\t\t\t\tif (!*out_buffer_use) {\n+\t\t\t\t\tclose(1);\n+\t\t\t\t\t*out_closed = 1;\n+\t\t\t\t\ttransfer_debug(\"Closed stdout\");\n+\t\t\t\t} else\n+\t\t\t\t\ttransfer_debug(\"Delaying stdout close because output buffer has data\");\n+\n+\t\t\t} else if (r > 0) {\n+\t\t\t\t*out_buffer_use += r;\n+\t\t\t\ttransfer_debug(\"Read %i bytes from remote input (buffer now at %i)\", r, (int)*out_buffer_use);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Handle stdout. */\n+\t\tif (polls[i].fd == 1 && polls[i].revents & POLLNVAL) {\n+\t\t\terror(\"Write pipe to Git unexpectedly closed.\");\n+\t\t\treturn 1;\n+\t\t}\n+\t\tif (polls[i].fd == 1 && polls[i].revents & POLLOUT) {\n+\t\t\ttransfer_debug(\"stdout is writable\");\n+\t\t\tr = write(1, out_buffer, *out_buffer_use);\n+\t\t\tif (r < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&\n+\t\t\t\terrno != EINTR) {\n+\t\t\t\tperror(\"write(git) failed\");\n+\t\t\t\treturn 1;\n+\t\t\t} else if (r > 0){\n+\t\t\t\t*out_buffer_use -= r;\n+\t\t\t\ttransfer_debug(\"Wrote %i bytes to stdout (buffer now at %i)\", r, (int)*out_buffer_use);\n+\t\t\t\tif (*out_buffer_use > 0)\n+\t\t\t\t\tmemmove(out_buffer, out_buffer + r,\n+\t\t\t\t\t\t*out_buffer_use);\n+\t\t\t\tif (*out_hup && !*out_buffer_use) {\n+\t\t\t\t\tclose(1);\n+\t\t\t\t\t*out_closed = 1;\n+\t\t\t\t\ttransfer_debug(\"Closed stdout\");\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Handle remote end output. */\n+\t\tif (polls[i].fd == output && polls[i].revents & POLLNVAL) {\n+\t\t\terror(\"Write pipe to remote end unexpectedly closed.\");\n+\t\t\treturn 1;\n+\t\t}\n+\t\tif (polls[i].fd == output && polls[i].revents & POLLOUT) {\n+\t\t\ttransfer_debug(\"remote output is writable\");\n+\t\t\tr = write(output, in_buffer, *in_buffer_use);\n+\t\t\tif (r < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&\n+\t\t\t\terrno != EINTR) {\n+\t\t\t\tperror(\"write(connection) failed\");\n+\t\t\t\treturn 1;\n+\t\t\t} else if (r > 0) {\n+\t\t\t\t*in_buffer_use -= r;\n+\t\t\t\ttransfer_debug(\"Wrote %i bytes to remote output (buffer now at %i)\", r, (int)*in_buffer_use);\n+\t\t\t\tif (*in_buffer_use > 0)\n+\t\t\t\t\tmemmove(in_buffer, in_buffer + r,\n+\t\t\t\t\t\t*in_buffer_use);\n+\t\t\t\tif (*in_hup && !*in_buffer_use) {\n+\t\t\t\t\tif (socket_mode)\n+\t\t\t\t\t\tshutdown(output, SHUT_WR);\n+\t\t\t\t\telse\n+\t\t\t\t\t\tclose(output);\n+\t\t\t\t\t*in_closed = 1;\n+\t\t\t\t\ttransfer_debug(\"Closed remote output\");\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/* Copy data from stdin to output and from input to stdout. */\n+int bidirectional_transfer_loop(int input, int output)\n+{\n+\tstruct pollfd polls[4];\n+\tchar in_buffer[BUFFERSIZE];\n+\tchar out_buffer[BUFFERSIZE];\n+\tsize_t in_buffer_use = 0;\n+\tsize_t out_buffer_use = 0;\n+\tint in_hup = 0;\n+\tint out_hup = 0;\n+\tint in_closed = 0;\n+\tint out_closed = 0;\n+\tint socket_mode = 0;\n+\tint poll_count = 4;\n+\n+\tif (input == output)\n+\t\tsocket_mode = 1;\n+\n+\twhile (1) {\n+\t\tint r;\n+\t\tpoll_count = load_poll_params(polls, in_buffer_use,\n+\t\t\tout_buffer_use, in_hup, out_hup, in_closed, out_closed,\n+\t\t\tsocket_mode, input, output);\n+\t\tif (!poll_count) {\n+\t\t\ttransfer_debug(\"Transfer done\");\n+\t\t\tbreak;\n+\t\t}\n+\t\ttransfer_debug(\"Waiting for %i file descriptors\", poll_count);\n+\t\tr = poll(polls, poll_count, -1);\n+\t\tif (r < 0) {\n+\t\t\tif (errno == EWOULDBLOCK || errno == EAGAIN ||\n+\t\t\t\terrno == EINTR)\n+\t\t\t\tcontinue;\n+\t\t\tperror(\"poll failed\");\n+\t\t\treturn 1;\n+\t\t} else if (r == 0)\n+\t\t\tcontinue;\n+\n+\t\tr = transfer_handle_events(polls, in_buffer, out_buffer,\n+\t\t\t&in_buffer_use, &out_buffer_use, &in_hup, &out_hup,\n+\t\t\t&in_closed, &out_closed, socket_mode, poll_count,\n+\t\t\tinput, output);\n+\t\tif (r)\n+\t\t\treturn r;\n+\t}\n+\treturn 0;\n+}\ndiff --git a/transport.h b/transport.h\nindex c59d973..e803c0e 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -154,6 +154,7 @@ int transport_connect(struct transport *transport, const char *name,\n \n /* Transport methods defined outside transport.c */\n int transport_helper_init(struct transport *transport, const char *name);\n+int bidirectional_transfer_loop(int input, int output);\n \n /* common methods used by transport.c and builtin-send-pack.c */\n void transport_verify_remote_names(int nr_heads, const char **heads);\n-- \n1.7.2.3.401.g919b6e\n"},{"id":"152129","messageId":"1285847579-21954-3-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"25297","inReplyTo":"1285847579-21954-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"[PATCH v2 2/3] git-remote-fd","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-09-30T11:52:58Z","receivedAt":"2010-09-30T11:52:58Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"This remote helper reflects raw smart remote transport stream back to the\ncalling program. This is useful for example if some UI wants to handle\nssh itself and not use hacks via GIT_SSH.\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\n Documentation/git-remote-fd.txt |   57 +++++++++++++++++++++++++\n Makefile                        |    1 +\n builtin.h                       |    1 +\n builtin/remote-fd.c             |   88 +++++++++++++++++++++++++++++++++++++++\n git.c                           |    1 +\n 5 files changed, 148 insertions(+), 0 deletions(-)\n create mode 100644 Documentation/git-remote-fd.txt\n create mode 100644 builtin/remote-fd.c\n\ndiff --git a/Documentation/git-remote-fd.txt b/Documentation/git-remote-fd.txt\nnew file mode 100644\nindex 0000000..12e588a\n--- /dev/null\n+++ b/Documentation/git-remote-fd.txt\n@@ -0,0 +1,57 @@\n+git-remote-fd(1)\n+=================\n+\n+NAME\n+----\n+git-remote-fd - Reflect smart transport back to caller.\n+\n+\n+SYNOPSIS\n+--------\n+\"fd::<fd>[/<anything>]\" or \"fd::<infd>,<outfd>[/<anything>]\" (as URL)\n+\n+DESCRIPTION\n+-----------\n+This command uses specified file descriptors to connect to remote git server.\n+\n+If just <fd> is specified, <fd> is assumed to be socket that is\n+transparently connected to git server program.\n+\n+If <infd> and <outfd> are specified, <infd> is assumed to be pipe from\n+git server program and <outfd> is assumed to be pipe to git server program.\n+\n+It is assumed that any handshaking procedures have already been completed\n+(such as sending service request for git://).\n+\n+<anything> can be any string. It is ignored. It is meant for provoding\n+information to user in form of \"URL\".\n+\n+ENVIRONMENT VARIABLES:\n+----------------------\n+\n+$GIT_TRANSLOOP_DEBUG (passed to git)::\n+\tIf set, prints debugging information about various reads/writes.\n+\n+\n+EXAMPLES:\n+---------\n+\"fd::17\"::\n+\tConnect using socket in file descriptor #17.\n+\n+\"fd::17/foo\"::\n+\tSame as above.\n+\n+\"fd::7,8\"::\n+\tConnect using pipes in file descriptors #7 and #8. The incoming\n+\tpipe is at fd #7 and the outgoing pipe at fd #8.\n+\n+\"fd::7,8/bar\"::\n+\tSame as above.\n+\n+Documentation\n+--------------\n+Documentation by Ilari Liusvaara.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 8a56b9a..7da54d7 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -728,6 +728,7 @@ BUILTIN_OBJS += builtin/read-tree.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\n BUILTIN_OBJS += builtin/remote.o\n+BUILTIN_OBJS += builtin/remote-fd.o\n BUILTIN_OBJS += builtin/replace.o\n BUILTIN_OBJS += builtin/rerere.o\n BUILTIN_OBJS += builtin/reset.o\ndiff --git a/builtin.h b/builtin.h\nindex f2a25a0..748cc13 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -140,5 +140,6 @@ extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_show_ref(int argc, const char **argv, const char *prefix);\n extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);\n extern int cmd_replace(int argc, const char **argv, const char *prefix);\n+extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);\n \n #endif\ndiff --git a/builtin/remote-fd.c b/builtin/remote-fd.c\nnew file mode 100644\nindex 0000000..08ff522\n--- /dev/null\n+++ b/builtin/remote-fd.c\n@@ -0,0 +1,88 @@\n+#include \"git-compat-util.h\"\n+#include \"transport.h\"\n+#include <errno.h>\n+#include <stdlib.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include <unistd.h>\n+\n+\n+/*\n+ * URL syntax:\n+ *\t'fd::<inoutfd>[/<anything>]'\t\tRead/write socket pair\n+ *\t\t\t\t\t\t<inoutfd>.\n+ *\t'fd::<infd>,<outfd>[/<anything>]'\tRead pipe <infd> and write\n+ *\t\t\t\t\t\tpipe <outfd>.\n+ *\t[foo] indicates 'foo' is optional. <anything> is any string.\n+ *\n+ * The data output to <outfd>/<inoutfd> should be passed unmolested to\n+ * git-receive-pack/git-upload-pack/git-upload-archive and output of\n+ * git-receive-pack/git-upload-pack/git-upload-archive should be passed\n+ * unmolested to <infd>/<inoutfd>.\n+ *\n+ */\n+\n+int input_fd = -1;\n+int output_fd = -1;\n+\n+#define MAXCOMMAND 4096\n+\n+static int command_loop()\n+{\n+\tchar buffer[MAXCOMMAND];\n+\n+\twhile (1) {\n+\t\tif (!fgets(buffer, MAXCOMMAND - 1, stdin))\n+\t\t\texit(0);\n+\t\t//Strip end of line characters.\n+\t\twhile (isspace((unsigned char)buffer[strlen(buffer) - 1]))\n+\t\t\tbuffer[strlen(buffer) - 1] = 0;\n+\n+\t\tif (!strcmp(buffer, \"capabilities\")) {\n+\t\t\tprintf(\"*connect\\n\\n\");\n+\t\t\tfflush(stdout);\n+\t\t} else if (!strncmp(buffer, \"connect \", 8)) {\n+\t\t\tprintf(\"\\n\");\n+\t\t\tfflush(stdout);\n+\t\t\treturn bidirectional_transfer_loop(input_fd,\n+\t\t\t\toutput_fd);\n+\t\t} else {\n+\t\t\tfprintf(stderr, \"Bad command\");\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+}\n+\n+int cmd_remote_fd(int argc, const char **argv, const char *prefix)\n+{\n+\tchar* end;\n+\tunsigned long r;\n+\n+\tif (argc < 3) {\n+\t\tfprintf(stderr, \"Error: URL missing\");\n+\t\texit(1);\n+\t}\n+\n+\tr = strtoul(argv[2], &end, 10);\n+\tinput_fd = (int)r;\n+\n+\tif ((*end != ',' && *end !='/' && *end) || end == argv[2]) {\n+\t\tfprintf(stderr, \"Error: Bad URL syntax\");\n+\t\texit(1);\n+\t}\n+\n+\tif (*end == '/' || !*end) {\n+\t\toutput_fd = input_fd;\n+\t} else {\n+\t\tchar* end2;\n+\t\tr = strtoul(end + 1, &end2, 10);\n+\t\toutput_fd = (int)r;\n+\n+\t\tif ((*end2 !='/' && *end2) || end2 == end + 1) {\n+\t\t\tfprintf(stderr, \"Error: Bad URL syntax\");\n+\t\t\texit(1);\n+\t\t}\n+\t}\n+\n+\treturn command_loop();\n+}\ndiff --git a/git.c b/git.c\nindex 50a1401..250ecc5 100644\n--- a/git.c\n+++ b/git.c\n@@ -374,6 +374,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"receive-pack\", cmd_receive_pack },\n \t\t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t\t{ \"remote\", cmd_remote, RUN_SETUP },\n+\t\t{ \"remote-fd\", cmd_remote_fd, 0 },\n \t\t{ \"replace\", cmd_replace, RUN_SETUP },\n \t\t{ \"repo-config\", cmd_config, RUN_SETUP_GENTLY },\n \t\t{ \"rerere\", cmd_rerere, RUN_SETUP },\n-- \n1.7.2.3.401.g919b6e\n"},{"id":"152127","messageId":"1285847579-21954-4-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"25297","inReplyTo":"1285847579-21954-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"[PATCH v2 3/3] git-remote-ext","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-09-30T11:52:59Z","receivedAt":"2010-09-30T11:52:59Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"This remote helper invokes external command and passes raw smart transport\nstream through it. This is useful for instance for invoking ssh with\none-off odd options, connecting to git services in unix domain\nsockets, in abstract namespace, using TLS or other secure protocols,\netc...\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\n Documentation/git-remote-ext.txt |   87 ++++++++++++++++++++++++++++++++++++++\n Makefile                         |    1 +\n builtin.h                        |    1 +\n git.c                            |    1 +\n 4 files changed, 90 insertions(+), 0 deletions(-)\n create mode 100644 Documentation/git-remote-ext.txt\n\ndiff --git a/Documentation/git-remote-ext.txt b/Documentation/git-remote-ext.txt\nnew file mode 100644\nindex 0000000..e2d40d9\n--- /dev/null\n+++ b/Documentation/git-remote-ext.txt\n@@ -0,0 +1,87 @@\n+git-remote-ext(1)\n+=================\n+\n+NAME\n+----\n+git-remote-ext - Bridge smart transport to external command.\n+\n+\n+SYNOPSIS\n+--------\n+\"ext::<command>[ <arguments>...]\" (as URL)\n+\n+DESCRIPTION\n+-----------\n+This command uses specified command to connect to remote git server.\n+\n+Between <command> and <arguments> (if present) is space. Also space\n+splits different arguments.\n+\n+The following sequences have special meaning:\n+\n+'\\ '::\n+\tDon't interpret the space as command/argument separator.\n+\n+'\\\\'::\n+\tLiteral backslash\n+\n+'\\s' (as argument)::\n+\tReplaced by short name (receive-pack, upload-pack, upload-archive)\n+\tof service git wants to invoke.\n+\n+'\\S' (as argument)::\n+\tReplaced by long name (git-receive-pack, git-upload-pack,\n+\tgit-upload-archive) of service git wants to invoke.\n+\n+'\\G<repository>' (as argument)::\n+\tThis argument will not be passed to command. Instead, git will send\n+\tin-line git:// service request for <repository>. Default is not to\n+\tsend in-line request.\n+\n+'\\V<host>' (as argument)::\n+\tSet the vhost used in in-line git:// service request. Default is\n+\tto omit vhost.\n+\n+\n+ENVIRONMENT VARIABLES:\n+----------------------\n+\n+$GIT_EXT_SERVICE (passed to command)::\n+\tInitialzed to long name of service git wants to invoke.\n+\n+$GIT_EXT_SERVICE_NOPREFIX (passed to command)::\n+\tInitialzed to short name of service git wants to invoke.\n+\n+$GIT_TRANSLOOP_DEBUG (passed to git)::\n+\tIf set, prints debugging information about various reads/writes.\n+\n+\n+EXAMPLES:\n+---------\n+\"ext::ssh -i /home/foo/.ssh/somekey user@host.example \\S \\'foo/repo'\"::\n+\tUse  /home/foo/.ssh/somekey as key when connecting to host.example\n+\tand request repo foo/repo.\n+\n+\"ext::socat -t3600 - ABSTRACT-CONNECT:/git-server \\G/somerepo\"::\n+\tConnect to git:// server named '/git-server' in abstract namespace\n+\tand request '/somerepo' from it.\n+\n+\"ext::git-server-alias foo \\G/repo\"::\n+\tConnect to wherever 'git-server-alias foo' connects to and send\n+\tgit:// request there for '/repo'.\n+\n+\"ext::git-server-alias foo \\G/repo \\Vfoo\"::\n+\tConnect to wherever 'git-server-alias foo' connects to and send\n+\tgit:// request there for '/repo' using vhost 'foo'.\n+\n+\"ext::git-ssl foo.example /bar\"::\n+\tConnect to whatever repo 'git-ssl foo.example /bar' goes.\n+\n+\n+Documentation\n+--------------\n+Documentation by Ilari Liusvaara.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 7da54d7..9909ca1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -728,6 +728,7 @@ BUILTIN_OBJS += builtin/read-tree.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\n BUILTIN_OBJS += builtin/remote.o\n+BUILTIN_OBJS += builtin/remote-ext.o\n BUILTIN_OBJS += builtin/remote-fd.o\n BUILTIN_OBJS += builtin/replace.o\n BUILTIN_OBJS += builtin/rerere.o\ndiff --git a/builtin.h b/builtin.h\nindex 748cc13..b15b486 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -141,5 +141,6 @@ extern int cmd_show_ref(int argc, const char **argv, const char *prefix);\n extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);\n extern int cmd_replace(int argc, const char **argv, const char *prefix);\n extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);\n+extern int cmd_remote_ext(int argc, const char **argv, const char *prefix);\n \n #endif\ndiff --git a/git.c b/git.c\nindex 250ecc5..867d8cf 100644\n--- a/git.c\n+++ b/git.c\n@@ -374,6 +374,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"receive-pack\", cmd_receive_pack },\n \t\t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t\t{ \"remote\", cmd_remote, RUN_SETUP },\n+\t\t{ \"remote-ext\", cmd_remote_ext, 0 },\n \t\t{ \"remote-fd\", cmd_remote_fd, 0 },\n \t\t{ \"replace\", cmd_replace, RUN_SETUP },\n \t\t{ \"repo-config\", cmd_config, RUN_SETUP_GENTLY },\n-- \n1.7.2.3.401.g919b6e\n"},{"id":"152131","messageId":"AANLkTimegoGAV3vVbOVnNLLcMjuPh6dK33siRxNoWRmM@mail.gmail.com","threadId":"25297","inReplyTo":"1285847579-21954-3-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2 2/3] git-remote-fd","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-09-30T12:04:31Z","receivedAt":"2010-09-30T12:04:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Thu, Sep 30, 2010 at 11:52, Ilari Liusvaara\n<ilari.liusvaara@elisanet.fi> wrote:\n\n> +               //Strip end of line characters.\n\nDon't use a C++/C99 comment.\n"},{"id":"152133","messageId":"20100930131440.GE4850@burratino","threadId":"25297","inReplyTo":"1285847579-21954-3-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2 2/3] git-remote-fd","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-09-30T13:14:40Z","receivedAt":"2010-09-30T13:14:40Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi Ilari,\n\nIlari Liusvaara wrote:\n\n> This remote helper reflects raw smart remote transport stream back to the\n> calling program. This is useful for example if some UI wants to handle\n> ssh itself and not use hacks via GIT_SSH.\n\nDo you ever use this directly, or is it a \"because we can\" sort of thing?\nWhenever I try to come up with an example, ext:: seems to be easier.\n\nAn example (ideally a test) would be nice.\n\n> +++ b/Documentation/git-remote-fd.txt\n> @@ -0,0 +1,57 @@\n[...]\n> +\"fd::<fd>[/<anything>]\" or \"fd::<infd>,<outfd>[/<anything>]\" (as URL)\n[...]\n> +<anything> can be any string. It is ignored. It is meant for provoding\n> +information to user in form of \"URL\".\n\nIs this meant for future expansion?  Why not just use a comment in\n.git/config?\n\n> @@ -0,0 +1,57 @@\n> +ENVIRONMENT VARIABLES:\n> +----------------------\n> +\n> +$GIT_TRANSLOOP_DEBUG (passed to git)::\n> +\tIf set, prints debugging information about various reads/writes.\n\nFor the curious: introduced by patch 1.\n\n> +EXAMPLES:\n> +---------\n> +\"fd::17\"::\n> +\tConnect using socket in file descriptor #17.\n\nMaybe with more context?\n\n\tsocat ... \"git push fd::3 HEAD\" ...\n\n> +Documentation\n> +--------------\n> +Documentation by Ilari Liusvaara.\n\nI think one tends to write \"Documentation by <person> and the git list\n<git@vger.kernel.org>\" these days.\n\nWhy is this section needed at all?  Doesn't the changelog already\nrecord the relevant information?\n\n> --- /dev/null\n> +++ b/builtin/remote-fd.c\n> @@ -0,0 +1,88 @@\n> +#include \"git-compat-util.h\"\n> +#include \"transport.h\"\n> +#include <errno.h>\n> +#include <stdlib.h>\n> +#include <string.h>\n> +#include <stdio.h>\n> +#include <unistd.h>\n\nDoesn't git-compat-util.h imply these?\n\n> + * The data output to <outfd>/<inoutfd> should be passed unmolested to\n> + * git-receive-pack/git-upload-pack/git-upload-archive and output of\n> + * git-receive-pack/git-upload-pack/git-upload-archive should be passed\n> + * unmolested to <infd>/<inoutfd>.\n\nMaybe worth mentioning in the manual?\n\n> +static int command_loop()\n\nSimple, I like it. :)\n\n> +int cmd_remote_fd(int argc, const char **argv, const char *prefix)\n> +{\n> +\tchar* end;\n> +\tunsigned long r;\n> +\n> +\tif (argc < 3) {\n> +\t\tfprintf(stderr, \"Error: URL missing\");\n> +\t\texit(1);\n\nWhy not use usage() or die()?  (Just curious.)\n"},{"id":"152134","messageId":"20100930134404.GA22521@LK-Perkele-V2.elisa-laajakaista.fi","threadId":"25297","inReplyTo":"20100930131440.GE4850@burratino","subject":"Re: [PATCH v2 2/3] git-remote-fd","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-09-30T13:44:04Z","receivedAt":"2010-09-30T13:44:04Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"On Thu, Sep 30, 2010 at 08:14:40AM -0500, Jonathan Nieder wrote:\n> Hi Ilari,\n> \n> Ilari Liusvaara wrote:\n> \n> > This remote helper reflects raw smart remote transport stream back to the\n> > calling program. This is useful for example if some UI wants to handle\n> > ssh itself and not use hacks via GIT_SSH.\n> \n> Do you ever use this directly, or is it a \"because we can\" sort of thing?\n> Whenever I try to come up with an example, ext:: seems to be easier.\n\nI don't have any UIs that would want to override SSH, git:// or something\nlike that, so no. ext:: sees lots of internal use.\n\n> > +<anything> can be any string. It is ignored. It is meant for provoding\n> > +information to user in form of \"URL\".\n> \n> Is this meant for future expansion?  Why not just use a comment in\n> .git/config?\n\nThese URLs are not meant to go into .git/config.\n \n> > +EXAMPLES:\n> > +---------\n> > +\"fd::17\"::\n> > +\tConnect using socket in file descriptor #17.\n> \n> Maybe with more context?\n> \n> \tsocat ... \"git push fd::3 HEAD\" ...\n\nMore like something execing git, having open connection to some git repo.\n\nIf you want stuff like that (using socat to establish connections), use\next::\n\n-Ilari\n"},{"id":"152152","messageId":"20100930134552.GF4850@burratino","threadId":"25297","inReplyTo":"1285847579-21954-4-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2 3/3] git-remote-ext","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-09-30T13:45:52Z","receivedAt":"2010-09-30T13:45:52Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ilari Liusvaara wrote:\n\n> This remote helper invokes external command and passes raw smart transport\n> stream through it. This is useful for instance for invoking ssh with\n> one-off odd options, connecting to git services in unix domain\n> sockets, in abstract namespace, using TLS or other secure protocols,\n> etc...\n\nTunneling, too (e.g., native git protocol passing through draconian\nfirewall), right?\n\n>  Documentation/git-remote-ext.txt |   87 ++++++++++++++++++++++++++++++++++++++\n>  Makefile                         |    1 +\n>  builtin.h                        |    1 +\n>  git.c                            |    1 +\n>  4 files changed, 90 insertions(+), 0 deletions(-)\n>  create mode 100644 Documentation/git-remote-ext.txt\n\nWhere is the implementation?\n\n> +++ b/Documentation/git-remote-ext.txt\n> @@ -0,0 +1,87 @@\n> +git-remote-ext(1)\n> +=================\n> +\n> +NAME\n> +----\n> +git-remote-ext - Bridge smart transport to external command.\n> +\n> +\n> +SYNOPSIS\n> +--------\n> +\"ext::<command>[ <arguments>...]\" (as URL)\n\nMaybe:\n\n\tgit remote add nick \"ext::<program>[ <arguments>...]\"\n\nas a concrete example.\n\n> +\n> +DESCRIPTION\n> +-----------\n> +This command uses specified command to connect to remote git server.\n\n - Most users won't invoke remote-ext directly, right?\n - Missing articles ('the' and 'a').\n - Missing formatting ('command' is passed on the command line).\n\nSo maybe:\n\n\tThis remote helper uses the specified 'program' to connect\n\tto a remote git server.\n\n> +\n> +Between <command> and <arguments> (if present) is space. Also space\n> +splits different arguments.\n\n\tArguments should be separated by a single unescaped space.\n\nDo I understand correctly?\n\n> +\n> +The following sequences have special meaning:\n\nMissing article:\n\n\t... have a special meaning:\n\n> +\n> +'\\ '::\n> +\tDon't interpret the space as command/argument separator.\n\n'\\ '::\n\tLiteral space in 'program' or an argument.\n\n> +\n> +'\\\\'::\n> +\tLiteral backslash\n\nMissing period.\n\n> +'\\s' (as argument)::\n> +\tReplaced by short name (receive-pack, upload-pack, upload-archive)\n> +\tof service git wants to invoke.\n\n'\\s'::\n\tName (receive-pack, upload-pack, or upload-archive) of the\n\tservice git wants to invoke.  Can only be used as an entire\n\targument (like \"ext::foo \\s\", not \"ext::foo BLAH\\sBLAH\"),\n\nIs that right?\n\n> +'\\S' (as argument)::\n> +\tReplaced by long name (git-receive-pack, git-upload-pack,\n> +\tgit-upload-archive) of service git wants to invoke.\n\n'\\S'::\n\tLong name (git-receive-pack, ...\n\nDoes this really mean \"name + 'git-'\", or does it respect the\nfetch-pack --upload-pack et al options?\n\n> +'\\G<repository>' (as argument)::\n> +\tThis argument will not be passed to command. Instead, git will send\n> +\tin-line git:// service request for <repository>. Default is not to\n> +\tsend in-line request.\n\n'\\G<repository>'::\n\tThis argument will not be passed to 'program'. Instead, ...\n\nHuh?  What is an in-line git://service request?\n\n> +'\\V<host>' (as argument)::\n> +\tSet the vhost used in in-line git:// service request. Default is\n> +\tto omit vhost.\n\nLikewise.\n\n> +ENVIRONMENT VARIABLES:\n> +----------------------\n> +\n> +$GIT_EXT_SERVICE (passed to command)::\n> +\tInitialzed to long name of service git wants to invoke.\n\nThe existing manual pages tend to use 'italics' and leave out the $\nhere.\n\nMaybe the environment passed to the command deserves its own section?\nJust nitpicking.\n\ns/Initialzed/Initialized/?  s/long name/the long name/? etc.\n\n> +EXAMPLES:\n> +---------\n\nMaybe some introductory text would help.  E.g:\n\n\tThis remote helper is transparently used by git when\n\tyou use commands such as \"git fetch <URL>\" where <URL>\n\tbegins with `ext::`.  Examples:\n\n> +\"ext::ssh -i /home/foo/.ssh/somekey user@host.example \\S \\'foo/repo'\"::\n> +\tUse  /home/foo/.ssh/somekey as key when connecting to host.example\n> +\tand request repo foo/repo.\n\nProbably worth mentioning this avoids adding a nickname and stanza\nfor this remote in ~/.ssh/config?\n\nAn address doesn't really request anything on its own.  Maybe saying\nwhat they point to would be clearer?\n\n\tRepresents a repository accessible at host.example:foo/repo\n\twhen connecting as user \"user\" with private key \"~foo/.ssh/somekey\".\n\n> +\"ext::socat -t3600 - ABSTRACT-CONNECT:/git-server \\G/somerepo\"::\n> +\tConnect to git:// server named '/git-server' in abstract namespace\n> +\tand request '/somerepo' from it.\n\n\tRepresents a repository with path /somerepo accessible over\n\tgit protocol at Unix-domain socket address \"/git-server\".\n\n> +\"ext::git-server-alias foo \\G/repo\"::\n> +\tConnect to wherever 'git-server-alias foo' connects to and send\n> +\tgit:// request there for '/repo'.\n\n\tRepresents a repository with path /repo accessed using the\n\thelper program \"git-server-alias foo\".  The path to the\n\trepository and type of request are not passed on the command\n\tline but as part of the protocol stream, as usual with git://\n\tprotocol.\n\n> +\"ext::git-server-alias foo \\G/repo \\Vfoo\"::\n> +\tConnect to wherever 'git-server-alias foo' connects to and send\n> +\tgit:// request there for '/repo' using vhost 'foo'.\n\n\tRepresents a repository with path /repo accessed using the\n\thelper program \"git-server-alias foo\".  The hostname for the\n\tremote server passed in the protocol stream will be \"foo\"\n\t(this allows multiple virtual git servers to share a\n\tlink-level address).\n\n> +\"ext::git-ssl foo.example /bar\"::\n> +\tConnect to whatever repo 'git-ssl foo.example /bar' goes.\n\n\tRepresents a repository accessed using the helper program\n\t\"git-ssl foo.example /bar\".  The type of request can be\n\tdetermined by the helper using environment variables (see\n\tabove).\n\n> --- a/Makefile\n> +++ b/Makefile\n[...]\n> --- a/builtin.h\n> +++ b/builtin.h\n[...]\nThis boilerplate looks good, but where's the command?\n\n> --- a/git.c\n> +++ b/git.c\n> @@ -374,6 +374,7 @@ static void handle_internal_command(int argc, const char **argv)\n>  \t\t{ \"receive-pack\", cmd_receive_pack },\n>  \t\t{ \"reflog\", cmd_reflog, RUN_SETUP },\n>  \t\t{ \"remote\", cmd_remote, RUN_SETUP },\n> +\t\t{ \"remote-ext\", cmd_remote_ext, 0 },\n>  \t\t{ \"remote-fd\", cmd_remote_fd, 0 },\n\nThe style of surrounding entries is to leave off the \"0\" where it can\nbe inferred like this.\n\nThanks for a pleasant read.\n"},{"id":"152153","messageId":"20100930135502.GG4850@burratino","threadId":"25297","inReplyTo":"1285847579-21954-2-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2 1/3] Add bidirectional_transfer_loop()","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-09-30T13:55:02Z","receivedAt":"2010-09-30T13:55:02Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ilari Liusvaara wrote:\n\n> --- a/transport-helper.c\n> +++ b/transport-helper.c\n[...]\n> +\tif (!in_hup && inbufuse < BUFFERSIZE) {\n> +\t\tstdin_index = nextindex++;\n> +\t\tpolls[stdin_index].fd = 0;\n> +\t\ttransfer_debug(\"Adding stdin to fds to wait for\");\n\nWhy not:\n\n\t\ttrace_printf(\"trace: adding stdin to ...\");\n\n?  That would give the user control of where tracing output goes\n(settings like GIT_TRACE=17).\n\nIf trace is too noisy (I don't think it is), maybe we should\nmake it more nuanced, like GIT_TRACE=17:transport?\n"},{"id":"152166","messageId":"20100930155145.GA23320@LK-Perkele-V2.elisa-laajakaista.fi","threadId":"25297","inReplyTo":"20100930135502.GG4850@burratino","subject":"Re: [PATCH v2 1/3] Add bidirectional_transfer_loop()","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-09-30T15:51:45Z","receivedAt":"2010-09-30T15:51:45Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"On Thu, Sep 30, 2010 at 08:55:02AM -0500, Jonathan Nieder wrote:\n> Ilari Liusvaara wrote:\n> \n> Why not:\n> \n> \t\ttrace_printf(\"trace: adding stdin to ...\");\n> \n> ?  That would give the user control of where tracing output goes\n> (settings like GIT_TRACE=17).\n> \n> If trace is too noisy (I don't think it is), maybe we should\n> make it more nuanced, like GIT_TRACE=17:transport?\n\nThe debugging output is hellishly noisy. I just (successfully) tried to clone\ngit repo from local copy. The result was no less than 106 773 debugging\nmessages...\n\n-Ilari\n"},{"id":"152167","messageId":"20100930155155.GI4850@burratino","threadId":"25297","inReplyTo":"20100930155145.GA23320@LK-Perkele-V2.elisa-laajakaista.fi","subject":"Re: [PATCH v2 1/3] Add bidirectional_transfer_loop()","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-09-30T15:51:55Z","receivedAt":"2010-09-30T15:51:55Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ilari Liusvaara wrote:\n\n> The debugging output is hellishly noisy. I just (successfully) tried to clone\n> git repo from local copy. The result was no less than 106 773 debugging\n> messages...\n\nAh, okay.  I suppose there is no need to teach this to share tracing\ninfrastructure (e.g., generalizing get_trace_fd()) now; that can\nbe done later if someone decides they need the flexibility.\n"},{"id":"152190","messageId":"7vfwwrhud1.fsf@alter.siamese.dyndns.org","threadId":"25297","inReplyTo":"20100930134552.GF4850@burratino","subject":"Re: [PATCH v2 3/3] git-remote-ext","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-09-30T20:03:22Z","receivedAt":"2010-09-30T20:03:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Ilari Liusvaara wrote:\n>\n>> This remote helper invokes external command and passes raw smart transport\n>> stream through it. This is useful for instance for invoking ssh with\n>> one-off odd options, connecting to git services in unix domain\n>> sockets, in abstract namespace, using TLS or other secure protocols,\n>> etc...\n>\n> Tunneling, too (e.g., native git protocol passing through draconian\n> firewall), right?\n>\n>>  Documentation/git-remote-ext.txt |   87 ++++++++++++++++++++++++++++++++++++++\n>>  Makefile                         |    1 +\n>>  builtin.h                        |    1 +\n>>  git.c                            |    1 +\n>>  4 files changed, 90 insertions(+), 0 deletions(-)\n>>  create mode 100644 Documentation/git-remote-ext.txt\n>\n> Where is the implementation?\n>\n>> +++ b/Documentation/git-remote-ext.txt\n>> @@ -0,0 +1,87 @@\n>> +git-remote-ext(1)\n>> +=================\n>> +\n>> +NAME\n>> +----\n>> +git-remote-ext - Bridge smart transport to external command.\n\nIs \"remote-ext\" a git subcommand that \"git help --all\" would want to show?\n\n>> +SYNOPSIS\n>> +--------\n>> +\"ext::<command>[ <arguments>...]\" (as URL)\n>\n> Maybe:\n>\n> \tgit remote add nick \"ext::<program>[ <arguments>...]\"\n>\n> as a concrete example.\n\nAhh.  I wasted minutes and hears scratching my head to figure out what\nthat \"(as URL)\" was about.\n\n>> +\n>> +DESCRIPTION\n>> +-----------\n>> +This command uses specified command to connect to remote git server.\n>\n>  - Most users won't invoke remote-ext directly, right?\n>  - Missing articles ('the' and 'a').\n>  - Missing formatting ('command' is passed on the command line).\n>\n> So maybe:\n>\n> \tThis remote helper uses the specified 'program' to connect\n> \tto a remote git server.\n>\n>> +\n>> +Between <command> and <arguments> (if present) is space. Also space\n>> +splits different arguments.\n>\n> \tArguments should be separated by a single unescaped space.\n>\n> Do I understand correctly?\n>\n>> +\n>> +The following sequences have special meaning:\n>\n> Missing article:\n>\n> \t... have a special meaning:\n>\n>> +\n>> +'\\ '::\n>> +\tDon't interpret the space as command/argument separator.\n\nIs it just me who finds the placeholders with backslashes somewhat out of\nplace where most other placeholders in git are per-cent prefixed?\n"},{"id":"152207","messageId":"20101001003022.GA16234@burratino","threadId":"25297","inReplyTo":"7vfwwrhud1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 3/3] git-remote-ext","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-01T00:30:22Z","receivedAt":"2010-10-01T00:30:22Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n\n> Is it just me who finds the placeholders with backslashes somewhat out of\n> place where most other placeholders in git are per-cent prefixed?\n\n\"\\ \" and \"\\\\\" seemed sane to me but the other ones left me more\npuzzled.\n\nIt would be nicer when reading the code if it used strbuf_expand(),\ntoo.\n"}]}