expose a helper function peel_to_type().
[gitweb.git] / builtin-fetch-pack.c
index 8753840a825d35249fa74ee80867f2dfd542708b..f40135248a5a1e2012c4cb01667f037407aae800 100644 (file)
@@ -7,6 +7,8 @@
 #include "pack.h"
 #include "sideband.h"
 #include "fetch-pack.h"
+#include "remote.h"
+#include "run-command.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -31,7 +33,7 @@ static const char fetch_pack_usage[] =
 #define MAX_IN_VAIN 256
 
 static struct commit_list *rev_list;
-static int non_common_revs, multi_ack, use_thin_pack, use_sideband;
+static int non_common_revs, multi_ack, use_sideband;
 
 static void rev_list_push(struct commit *commit, int mark)
 {
@@ -177,7 +179,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                                     (multi_ack ? " multi_ack" : ""),
                                     (use_sideband == 2 ? " side-band-64k" : ""),
                                     (use_sideband == 1 ? " side-band" : ""),
-                                    (use_thin_pack ? " thin-pack" : ""),
+                                    (args.use_thin_pack ? " thin-pack" : ""),
                                     (args.no_progress ? " no-progress" : ""),
                                     " ofs-delta");
                else
@@ -457,59 +459,46 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
        return retval;
 }
 
-static pid_t setup_sideband(int fd[2], int xd[2])
+static int sideband_demux(int fd, void *data)
 {
-       pid_t side_pid;
+       int *xd = data;
 
-       if (!use_sideband) {
-               fd[0] = xd[0];
-               fd[1] = xd[1];
-               return 0;
-       }
-       /* xd[] is talking with upload-pack; subprocess reads from
-        * xd[0], spits out band#2 to stderr, and feeds us band#1
-        * through our fd[0].
-        */
-       if (pipe(fd) < 0)
-               die("fetch-pack: unable to set up pipe");
-       side_pid = fork();
-       if (side_pid < 0)
-               die("fetch-pack: unable to fork off sideband demultiplexer");
-       if (!side_pid) {
-               /* subprocess */
-               close(fd[0]);
-               if (xd[0] != xd[1])
-                       close(xd[1]);
-               if (recv_sideband("fetch-pack", xd[0], fd[1], 2))
-                       exit(1);
-               exit(0);
-       }
-       close(xd[0]);
-       close(fd[1]);
-       fd[1] = xd[1];
-       return side_pid;
+       return recv_sideband("fetch-pack", xd[0], fd, 2);
 }
 
 static int get_pack(int xd[2], char **pack_lockfile)
 {
-       int status;
-       pid_t pid, side_pid;
-       int fd[2];
+       struct async demux;
        const char *argv[20];
        char keep_arg[256];
        char hdr_arg[256];
        const char **av;
        int do_keep = args.keep_pack;
-       int keep_pipe[2];
+       struct child_process cmd;
 
-       side_pid = setup_sideband(fd, xd);
+       memset(&demux, 0, sizeof(demux));
+       if (use_sideband) {
+               /* xd[] is talking with upload-pack; subprocess reads from
+                * xd[0], spits out band#2 to stderr, and feeds us band#1
+                * through demux->out.
+                */
+               demux.proc = sideband_demux;
+               demux.data = xd;
+               if (start_async(&demux))
+                       die("fetch-pack: unable to fork off sideband"
+                           " demultiplexer");
+       }
+       else
+               demux.out = xd[0];
 
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.argv = argv;
        av = argv;
        *hdr_arg = 0;
        if (!args.keep_pack && unpack_limit) {
                struct pack_header header;
 
-               if (read_pack_header(fd[0], &header))
+               if (read_pack_header(demux.out, &header))
                        die("protocol error: bad pack header");
                snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u",
                         ntohl(header.hdr_version), ntohl(header.hdr_entries));
@@ -520,8 +509,8 @@ static int get_pack(int xd[2], char **pack_lockfile)
        }
 
        if (do_keep) {
-               if (pack_lockfile && pipe(keep_pipe))
-                       die("fetch-pack: pipe setup failure: %s", strerror(errno));
+               if (pack_lockfile)
+                       cmd.out = -1;
                *av++ = "index-pack";
                *av++ = "--stdin";
                if (!args.quiet && !args.no_progress)
@@ -545,54 +534,29 @@ static int get_pack(int xd[2], char **pack_lockfile)
                *av++ = hdr_arg;
        *av++ = NULL;
 
-       pid = fork();
-       if (pid < 0)
+       cmd.in = demux.out;
+       cmd.git_cmd = 1;
+       if (start_command(&cmd))
                die("fetch-pack: unable to fork off %s", argv[0]);
-       if (!pid) {
-               dup2(fd[0], 0);
-               if (do_keep && pack_lockfile) {
-                       dup2(keep_pipe[1], 1);
-                       close(keep_pipe[0]);
-                       close(keep_pipe[1]);
-               }
-               close(fd[0]);
-               close(fd[1]);
-               execv_git_cmd(argv);
-               die("%s exec failed", argv[0]);
-       }
-       close(fd[0]);
-       close(fd[1]);
-       if (do_keep && pack_lockfile) {
-               close(keep_pipe[1]);
-               *pack_lockfile = index_pack_lockfile(keep_pipe[0]);
-               close(keep_pipe[0]);
-       }
-       while (waitpid(pid, &status, 0) < 0) {
-               if (errno != EINTR)
-                       die("waiting for %s: %s", argv[0], strerror(errno));
-       }
-       if (WIFEXITED(status)) {
-               int code = WEXITSTATUS(status);
-               if (code)
-                       die("%s died with error code %d", argv[0], code);
-               return 0;
-       }
-       if (WIFSIGNALED(status)) {
-               int sig = WTERMSIG(status);
-               die("%s died of signal %d", argv[0], sig);
-       }
-       die("%s died of unnatural causes %d", argv[0], status);
+       if (do_keep && pack_lockfile)
+               *pack_lockfile = index_pack_lockfile(cmd.out);
+
+       if (finish_command(&cmd))
+               die("%s failed", argv[0]);
+       if (use_sideband && finish_async(&demux))
+               die("error in sideband demultiplexer");
+       return 0;
 }
 
 static struct ref *do_fetch_pack(int fd[2],
+               const struct ref *orig_ref,
                int nr_match,
                char **match,
                char **pack_lockfile)
 {
-       struct ref *ref;
+       struct ref *ref = copy_ref_list(orig_ref);
        unsigned char sha1[20];
 
-       get_remote_heads(fd[0], &ref, 0, NULL, 0);
        if (is_repository_shallow() && !server_supports("shallow"))
                die("Server does not support shallow clients");
        if (server_supports("multi_ack")) {
@@ -610,10 +574,6 @@ static struct ref *do_fetch_pack(int fd[2],
                        fprintf(stderr, "Server supports side-band\n");
                use_sideband = 1;
        }
-       if (!ref) {
-               packet_flush(fd[1]);
-               die("no matching remote head");
-       }
        if (everything_local(&ref, nr_match, match)) {
                packet_flush(fd[1]);
                goto all_done;
@@ -687,8 +647,10 @@ static void fetch_pack_setup(void)
 int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 {
        int i, ret, nr_heads;
-       struct ref *ref;
+       struct ref *ref = NULL;
        char *dest = NULL, **heads;
+       int fd[2];
+       struct child_process *conn;
 
        nr_heads = 0;
        heads = NULL;
@@ -743,9 +705,33 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        if (!dest)
                usage(fetch_pack_usage);
 
-       ref = fetch_pack(&args, dest, nr_heads, heads, NULL);
+       conn = git_connect(fd, (char *)dest, args.uploadpack,
+                          args.verbose ? CONNECT_VERBOSE : 0);
+       if (conn) {
+               get_remote_heads(fd[0], &ref, 0, NULL, 0);
+
+               ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
+               close(fd[0]);
+               close(fd[1]);
+               if (finish_connect(conn))
+                       ref = NULL;
+       } else {
+               ref = NULL;
+       }
        ret = !ref;
 
+       if (!ret && nr_heads) {
+               /* If the heads to pull were given, we should have
+                * consumed all of them by matching the remote.
+                * Otherwise, 'git-fetch remote no-such-ref' would
+                * silently succeed without issuing an error.
+                */
+               for (i = 0; i < nr_heads; i++)
+                       if (heads[i] && heads[i][0]) {
+                               error("no such remote ref %s", heads[i]);
+                               ret = 1;
+                       }
+       }
        while (ref) {
                printf("%s %s\n",
                       sha1_to_hex(ref->old_sha1), ref->name);
@@ -756,16 +742,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 }
 
 struct ref *fetch_pack(struct fetch_pack_args *my_args,
+                      int fd[], struct child_process *conn,
+                      const struct ref *ref,
                const char *dest,
                int nr_heads,
                char **heads,
                char **pack_lockfile)
 {
-       int i, ret;
-       int fd[2];
-       pid_t pid;
-       struct ref *ref;
        struct stat st;
+       struct ref *ref_cpy;
 
        fetch_pack_setup();
        memcpy(&args, my_args, sizeof(args));
@@ -774,31 +759,15 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                        st.st_mtime = 0;
        }
 
-       pid = git_connect(fd, (char *)dest, args.uploadpack,
-                          args.verbose ? CONNECT_VERBOSE : 0);
-       if (pid < 0)
-               return NULL;
        if (heads && nr_heads)
                nr_heads = remove_duplicates(nr_heads, heads);
-       ref = do_fetch_pack(fd, nr_heads, heads, pack_lockfile);
-       close(fd[0]);
-       close(fd[1]);
-       ret = finish_connect(pid);
-
-       if (!ret && nr_heads) {
-               /* If the heads to pull were given, we should have
-                * consumed all of them by matching the remote.
-                * Otherwise, 'git-fetch remote no-such-ref' would
-                * silently succeed without issuing an error.
-                */
-               for (i = 0; i < nr_heads; i++)
-                       if (heads[i] && heads[i][0]) {
-                               error("no such remote ref %s", heads[i]);
-                               ret = 1;
-                       }
+       if (!ref) {
+               packet_flush(fd[1]);
+               die("no matching remote head");
        }
+       ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile);
 
-       if (!ret && args.depth > 0) {
+       if (args.depth > 0) {
                struct cache_time mtime;
                char *shallow = git_path("shallow");
                int fd;
@@ -822,13 +791,9 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                        unlink(shallow);
                        rollback_lock_file(&lock);
                } else {
-                       close(fd);
                        commit_lock_file(&lock);
                }
        }
 
-       if (ret)
-               ref = NULL;
-
-       return ref;
+       return ref_cpy;
 }