upload-archive: use start_command instead of fork

The POSIX-function fork is not supported on Windows. Use our start_command API instead, respawning ourselves in a special "writer" mode to follow the alternate code path. Remove the NOT_MINGW-prereq for t5000, as git-archive --remote now works. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Nov 19, 2011 at 02:40 UTC 1bc01efed17c751e98fd6c5f9889759bfa9a8e9b
4 files changed +19 -36
builtin.h
+1
@@ -133,6 +133,7 @@ extern int cmd_update_index(int argc, const char **argv, const char *prefix);
133 extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
134 extern int cmd_update_server_info(int argc, const char **argv, const char *prefix);
135 extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
136 +extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
137 extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
138 extern int cmd_var(int argc, const char **argv, const char *prefix);
139 extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
builtin/upload-archive.c
+12 -31
@@ -6,6 +6,7 @@
6 #include "archive.h"
7 #include "pkt-line.h"
8 #include "sideband.h"
9 +#include "run-command.h"
10
11 static const char upload_archive_usage[] =
12 "git upload-archive <repo>";
@@ -13,12 +14,9 @@ static const char upload_archive_usage[] =
14 static const char deadchild[] =
15 "git upload-archive: archiver died with error";
16
16 -static const char lostchild[] =
17 -"git upload-archive: archiver process was lost";
18 -
17 #define MAX_ARGS (64)
18
21 -static int run_upload_archive(int argc, const char **argv, const char *prefix)
19 +int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
20 {
21 const char *sent_argv[MAX_ARGS];
22 const char *arg_cmd = "argument ";
@@ -96,8 +94,8 @@ static ssize_t process_input(int child_fd, int band)
94
95 int cmd_upload_archive(int argc, const char **argv, const char *prefix)
96 {
99 - pid_t writer;
100 - int fd1[2], fd2[2];
97 + struct child_process writer = { argv };
98 +
99 /*
100 * Set up sideband subprocess.
101 *
@@ -105,39 +103,24 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
103 * multiplexed out to our fd#1. If the child dies, we tell the other
104 * end over channel #3.
105 */
108 - if (pipe(fd1) < 0 || pipe(fd2) < 0) {
109 - int err = errno;
110 - packet_write(1, "NACK pipe failed on the remote side\n");
111 - die("upload-archive: %s", strerror(err));
112 - }
113 - writer = fork();
114 - if (writer < 0) {
106 + argv[0] = "upload-archive--writer";
107 + writer.out = writer.err = -1;
108 + writer.git_cmd = 1;
109 + if (start_command(&writer)) {
110 int err = errno;
116 - packet_write(1, "NACK fork failed on the remote side\n");
111 + packet_write(1, "NACK unable to spawn subprocess\n");
112 die("upload-archive: %s", strerror(err));
113 }
119 - if (!writer) {
120 - /* child - connect fd#1 and fd#2 to the pipe */
121 - dup2(fd1[1], 1);
122 - dup2(fd2[1], 2);
123 - close(fd1[1]); close(fd2[1]);
124 - close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
125 -
126 - exit(run_upload_archive(argc, argv, prefix));
127 - }
114
129 - /* parent - read from child, multiplex and send out to fd#1 */
130 - close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
115 packet_write(1, "ACK\n");
116 packet_flush(1);
117
118 while (1) {
119 struct pollfd pfd[2];
136 - int status;
120
138 - pfd[0].fd = fd1[0];
121 + pfd[0].fd = writer.out;
122 pfd[0].events = POLLIN;
140 - pfd[1].fd = fd2[0];
123 + pfd[1].fd = writer.err;
124 pfd[1].events = POLLIN;
125 if (poll(pfd, 2, -1) < 0) {
126 if (errno != EINTR) {
@@ -156,9 +139,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
139 if (process_input(pfd[0].fd, 1))
140 continue;
141
159 - if (waitpid(writer, &status, 0) < 0)
160 - error_clnt("%s", lostchild);
161 - else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
142 + if (finish_command(&writer))
143 error_clnt("%s", deadchild);
144 packet_flush(1);
145 break;
git.c
+1
@@ -434,6 +434,7 @@ static void handle_internal_command(int argc, const char **argv)
434 { "update-ref", cmd_update_ref, RUN_SETUP },
435 { "update-server-info", cmd_update_server_info, RUN_SETUP },
436 { "upload-archive", cmd_upload_archive },
437 + { "upload-archive--writer", cmd_upload_archive_writer },
438 { "var", cmd_var, RUN_SETUP_GENTLY },
439 { "verify-pack", cmd_verify_pack },
440 { "verify-tag", cmd_verify_tag, RUN_SETUP },
t/t5000-tar-tree.sh
+5 -5
@@ -96,7 +96,7 @@ test_expect_success 'git archive with --output' \
96 'git archive --output=b4.tar HEAD &&
97 test_cmp b.tar b4.tar'
98
99 -test_expect_success NOT_MINGW 'git archive --remote' \
99 +test_expect_success 'git archive --remote' \
100 'git archive --remote=. HEAD >b5.tar &&
101 test_cmp b.tar b5.tar'
102
@@ -266,7 +266,7 @@ test_expect_success 'archive --list mentions user filter' '
266 grep "^bar\$" output
267 '
268
269 -test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '
269 +test_expect_success 'archive --list shows only enabled remote filters' '
270 git archive --list --remote=. >output &&
271 ! grep "^tar\.foo\$" output &&
272 grep "^bar\$" output
@@ -298,7 +298,7 @@ test_expect_success 'extension matching requires dot' '
298 test_cmp b.tar config-implicittar.foo
299 '
300
301 -test_expect_success NOT_MINGW 'only enabled filters are available remotely' '
301 +test_expect_success 'only enabled filters are available remotely' '
302 test_must_fail git archive --remote=. --format=tar.foo HEAD \
303 >remote.tar.foo &&
304 git archive --remote=. --format=bar >remote.bar HEAD &&
@@ -341,12 +341,12 @@ test_expect_success GZIP,GUNZIP 'extract tgz file' '
341 test_cmp b.tar j.tar
342 '
343
344 -test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '
344 +test_expect_success GZIP 'remote tar.gz is allowed by default' '
345 git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
346 test_cmp j.tgz remote.tar.gz
347 '
348
349 -test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '
349 +test_expect_success GZIP 'remote tar.gz can be disabled' '
350 git config tar.tar.gz.remote false &&
351 test_must_fail git archive --remote=. --format=tar.gz HEAD \
352 >remote.tar.gz