fetch-pack.con commit Commit first cut at "git-fetch-pack" (def88e9)
   1#include "cache.h"
   2#include "pkt-line.h"
   3
   4static const char fetch_pack_usage[] = "git-fetch-pack [host:]directory [heads]* < mycommitlist";
   5static const char *exec = "git-upload-pack";
   6
   7static int get_ack(int fd, unsigned char *result_sha1)
   8{
   9        static char line[1000];
  10        int len = packet_read_line(fd, line, sizeof(line));
  11
  12        if (!len)
  13                die("git-fetch-pack: expected ACK/NAK, got EOF");
  14        if (line[len-1] == '\n')
  15                line[--len] = 0;
  16        if (!strcmp(line, "NAK"))
  17                return 0;
  18        if (!strncmp(line, "ACK ", 3)) {
  19                if (!get_sha1_hex(line+4, result_sha1))
  20                        return 1;
  21        }
  22        die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
  23}
  24
  25static int find_common(int fd[2], unsigned char *result_sha1)
  26{
  27        static char line[1000];
  28        int count = 0, flushes = 0;
  29
  30        while (fgets(line, sizeof(line), stdin) != NULL) {
  31                unsigned char sha1[20];
  32                if (get_sha1_hex(line, sha1))
  33                        die("git-fetch-pack: expected object name, got crud");
  34                packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
  35                if (!(31 & ++count)) {
  36                        packet_flush(fd[1]);
  37                        flushes++;
  38
  39                        /*
  40                         * We keep one window "ahead" of the other side, and
  41                         * will wait for an ACK only on the next one
  42                         */
  43                        if (count == 32)
  44                                continue;
  45                        if (get_ack(fd[0], result_sha1))
  46                                return 0;
  47                        flushes--;
  48                }
  49        }
  50        flushes++;
  51        packet_flush(fd[1]);
  52        while (flushes) {
  53                flushes--;
  54                if (get_ack(fd[0], result_sha1))
  55                        return 0;
  56        }
  57        return -1;
  58}
  59
  60static int get_remote_heads(int fd, int nr_match, char **match)
  61{
  62        for (;;) {
  63                static char line[1000];
  64                unsigned char sha1[20];
  65                char *refname;
  66                int len;
  67
  68                len = packet_read_line(fd, line, sizeof(line));
  69                if (!len)
  70                        break;
  71                if (line[len-1] == '\n')
  72                        line[--len] = 0;
  73                if (len < 42 || get_sha1_hex(line, sha1))
  74                        die("git-fetch-pack: protocol error - expected ref descriptor, got '%sรค'", line);
  75                refname = line+41;
  76                if (nr_match && !path_match(refname, nr_match, match))
  77                        continue;
  78                printf("%s %s\n", sha1_to_hex(sha1), refname);
  79        }
  80        return 0;
  81}
  82
  83static int fetch_pack(int fd[2], int nr_match, char **match)
  84{
  85        unsigned char sha1[20];
  86
  87        get_remote_heads(fd[0], nr_match, match);
  88        if (find_common(fd, sha1) < 0)
  89                die("git-fetch-pack: no common commits");
  90        printf("common commit: %s\n", sha1_to_hex(sha1));
  91        return 0;
  92}
  93
  94int main(int argc, char **argv)
  95{
  96        int i, ret, nr_heads;
  97        char *dest = NULL, **heads;
  98        int fd[2];
  99        pid_t pid;
 100
 101        nr_heads = 0;
 102        heads = NULL;
 103        for (i = 1; i < argc; i++) {
 104                char *arg = argv[i];
 105
 106                if (*arg == '-') {
 107                        /* Arguments go here */
 108                        usage(fetch_pack_usage);
 109                }
 110                dest = arg;
 111                heads = argv + i + 1;
 112                nr_heads = argc - i - 1;
 113                break;
 114        }
 115        if (!dest)
 116                usage(fetch_pack_usage);
 117        pid = git_connect(fd, dest, exec);
 118        if (pid < 0)
 119                return 1;
 120        ret = fetch_pack(fd, nr_heads, heads);
 121        close(fd[0]);
 122        close(fd[1]);
 123        finish_connect(pid);
 124        return ret;
 125}