fetch-pack.con commit Merge git-tools repository under "tools" subdirectory (98e031f)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include <sys/wait.h>
   5
   6static int quiet;
   7static const char fetch_pack_usage[] = "git-fetch-pack [-q] [--exec=upload-pack] [host:]directory [heads]* < mycommitlist";
   8static const char *exec = "git-upload-pack";
   9
  10static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *remote)
  11{
  12        static char line[1000];
  13        int count = 0, flushes = 0, retval;
  14        FILE *revs;
  15
  16        revs = popen("git-rev-list $(git-rev-parse --all)", "r");
  17        if (!revs)
  18                die("unable to run 'git-rev-list'");
  19        packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
  20        packet_flush(fd[1]);
  21        flushes = 1;
  22        retval = -1;
  23        while (fgets(line, sizeof(line), revs) != NULL) {
  24                unsigned char sha1[20];
  25                if (get_sha1_hex(line, sha1))
  26                        die("git-fetch-pack: expected object name, got crud");
  27                packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
  28                if (!(31 & ++count)) {
  29                        packet_flush(fd[1]);
  30                        flushes++;
  31
  32                        /*
  33                         * We keep one window "ahead" of the other side, and
  34                         * will wait for an ACK only on the next one
  35                         */
  36                        if (count == 32)
  37                                continue;
  38                        if (get_ack(fd[0], result_sha1)) {
  39                                flushes = 0;
  40                                retval = 0;
  41                                break;
  42                        }
  43                        flushes--;
  44                }
  45        }
  46        pclose(revs);
  47        packet_write(fd[1], "done\n");
  48        while (flushes) {
  49                flushes--;
  50                if (get_ack(fd[0], result_sha1))
  51                        return 0;
  52        }
  53        return retval;
  54}
  55
  56static int get_remote_heads(int fd, int nr_match, char **match, unsigned char *result)
  57{
  58        int count = 0;
  59
  60        for (;;) {
  61                static char line[1000];
  62                unsigned char sha1[20];
  63                char *refname;
  64                int len;
  65
  66                len = packet_read_line(fd, line, sizeof(line));
  67                if (!len)
  68                        break;
  69                if (line[len-1] == '\n')
  70                        line[--len] = 0;
  71                if (len < 42 || get_sha1_hex(line, sha1))
  72                        die("git-fetch-pack: protocol error - expected ref descriptor, got '%s'", line);
  73                refname = line+41;
  74                if (nr_match && !path_match(refname, nr_match, match))
  75                        continue;
  76                count++;
  77                memcpy(result, sha1, 20);
  78        }
  79        return count;
  80}
  81
  82static int fetch_pack(int fd[2], int nr_match, char **match)
  83{
  84        unsigned char sha1[20], remote[20];
  85        int heads, status;
  86        pid_t pid;
  87
  88        heads = get_remote_heads(fd[0], nr_match, match, remote);
  89        if (heads != 1) {
  90                packet_flush(fd[1]);
  91                die(heads ? "multiple remote heads" : "no matching remote head");
  92        }
  93        if (find_common(fd, sha1, remote) < 0)
  94                die("git-fetch-pack: no common commits");
  95        pid = fork();
  96        if (pid < 0)
  97                die("git-fetch-pack: unable to fork off git-unpack-objects");
  98        if (!pid) {
  99                dup2(fd[0], 0);
 100                close(fd[0]);
 101                close(fd[1]);
 102                execlp("git-unpack-objects", "git-unpack-objects",
 103                       quiet ? "-q" : NULL, NULL);
 104                die("git-unpack-objects exec failed");
 105        }
 106        close(fd[0]);
 107        close(fd[1]);
 108        while (waitpid(pid, &status, 0) < 0) {
 109                if (errno != EINTR)
 110                        die("waiting for git-unpack-objects: %s", strerror(errno));
 111        }
 112        if (WIFEXITED(status)) {
 113                int code = WEXITSTATUS(status);
 114                if (code)
 115                        die("git-unpack-objects died with error code %d", code);
 116                puts(sha1_to_hex(remote));
 117                return 0;
 118        }
 119        if (WIFSIGNALED(status)) {
 120                int sig = WTERMSIG(status);
 121                die("git-unpack-objects died of signal %d", sig);
 122        }
 123        die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
 124}
 125
 126int main(int argc, char **argv)
 127{
 128        int i, ret, nr_heads;
 129        char *dest = NULL, **heads;
 130        int fd[2];
 131        pid_t pid;
 132
 133        nr_heads = 0;
 134        heads = NULL;
 135        for (i = 1; i < argc; i++) {
 136                char *arg = argv[i];
 137
 138                if (*arg == '-') {
 139                        if (!strncmp("--exec=", arg, 7)) {
 140                                exec = arg + 7;
 141                                continue;
 142                        }
 143                        usage(fetch_pack_usage);
 144                }
 145                dest = arg;
 146                heads = argv + i + 1;
 147                nr_heads = argc - i - 1;
 148                break;
 149        }
 150        if (!dest)
 151                usage(fetch_pack_usage);
 152        pid = git_connect(fd, dest, exec);
 153        if (pid < 0)
 154                return 1;
 155        ret = fetch_pack(fd, nr_heads, heads);
 156        close(fd[0]);
 157        close(fd[1]);
 158        finish_connect(pid);
 159        return ret;
 160}