fetch-pack.con commit Merge branch 'fixes' (02b54b3)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include "commit.h"
   5#include "tag.h"
   6#include <time.h>
   7#include <sys/wait.h>
   8
   9static int quiet;
  10static int verbose;
  11static const char fetch_pack_usage[] =
  12"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
  13static const char *exec = "git-upload-pack";
  14
  15static int find_common(int fd[2], unsigned char *result_sha1,
  16                       struct ref *refs)
  17{
  18        int fetching;
  19        static char line[1000];
  20        int count = 0, flushes = 0, retval;
  21        FILE *revs;
  22
  23        revs = popen("git-rev-list $(git-rev-parse --all)", "r");
  24        if (!revs)
  25                die("unable to run 'git-rev-list'");
  26
  27        fetching = 0;
  28        for ( ; refs ; refs = refs->next) {
  29                unsigned char *remote = refs->old_sha1;
  30                unsigned char *local = refs->new_sha1;
  31
  32                if (!memcmp(remote, local, 20))
  33                        continue;
  34                packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
  35                fetching++;
  36        }
  37        packet_flush(fd[1]);
  38        if (!fetching)
  39                return 1;
  40        flushes = 1;
  41        retval = -1;
  42        while (fgets(line, sizeof(line), revs) != NULL) {
  43                unsigned char sha1[20];
  44                if (get_sha1_hex(line, sha1))
  45                        die("git-fetch-pack: expected object name, got crud");
  46                packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
  47                if (verbose)
  48                        fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
  49                if (!(31 & ++count)) {
  50                        packet_flush(fd[1]);
  51                        flushes++;
  52
  53                        /*
  54                         * We keep one window "ahead" of the other side, and
  55                         * will wait for an ACK only on the next one
  56                         */
  57                        if (count == 32)
  58                                continue;
  59                        if (get_ack(fd[0], result_sha1)) {
  60                                flushes = 0;
  61                                retval = 0;
  62                                if (verbose)
  63                                        fprintf(stderr, "got ack\n");
  64                                break;
  65                        }
  66                        flushes--;
  67                }
  68        }
  69        pclose(revs);
  70        packet_write(fd[1], "done\n");
  71        if (verbose)
  72                fprintf(stderr, "done\n");
  73        while (flushes) {
  74                flushes--;
  75                if (get_ack(fd[0], result_sha1)) {
  76                        if (verbose)
  77                                fprintf(stderr, "got ack\n");
  78                        return 0;
  79                }
  80        }
  81        return retval;
  82}
  83
  84#define COMPLETE        (1U << 0)
  85static struct commit_list *complete = NULL;
  86
  87static int mark_complete(const char *path, const unsigned char *sha1)
  88{
  89        struct object *o = parse_object(sha1);
  90
  91        while (o && o->type == tag_type) {
  92                o->flags |= COMPLETE;
  93                o = parse_object(((struct tag *)o)->tagged->sha1);
  94        }
  95        if (o->type == commit_type) {
  96                struct commit *commit = (struct commit *)o;
  97                commit->object.flags |= COMPLETE;
  98                insert_by_date(commit, &complete);
  99        }
 100        return 0;
 101}
 102
 103static void mark_recent_complete_commits(unsigned long cutoff)
 104{
 105        while (complete && cutoff <= complete->item->date) {
 106                if (verbose)
 107                        fprintf(stderr, "Marking %s as complete\n",
 108                                sha1_to_hex(complete->item->object.sha1));
 109                pop_most_recent_commit(&complete, COMPLETE);
 110        }
 111}
 112
 113static int everything_local(struct ref *refs)
 114{
 115        struct ref *ref;
 116        int retval;
 117        unsigned long cutoff = 0;
 118
 119        track_object_refs = 0;
 120        save_commit_buffer = 0;
 121
 122        for (ref = refs; ref; ref = ref->next) {
 123                struct object *o;
 124
 125                o = parse_object(ref->old_sha1);
 126                if (!o)
 127                        continue;
 128
 129                /* We already have it -- which may mean that we were
 130                 * in sync with the other side at some time after
 131                 * that (it is OK if we guess wrong here).
 132                 */
 133                if (o->type == commit_type) {
 134                        struct commit *commit = (struct commit *)o;
 135                        if (!cutoff || cutoff < commit->date)
 136                                cutoff = commit->date;
 137                }
 138        }
 139
 140        for_each_ref(mark_complete);
 141        if (cutoff)
 142                mark_recent_complete_commits(cutoff);
 143
 144        for (retval = 1; refs ; refs = refs->next) {
 145                const unsigned char *remote = refs->old_sha1;
 146                unsigned char local[20];
 147                struct object *o;
 148
 149                o = parse_object(remote);
 150                if (!o || !(o->flags & COMPLETE)) {
 151                        retval = 0;
 152                        if (!verbose)
 153                                continue;
 154                        fprintf(stderr,
 155                                "want %s (%s)\n", sha1_to_hex(remote),
 156                                refs->name);
 157                        continue;
 158                }
 159
 160                memcpy(refs->new_sha1, local, 20);
 161                if (!verbose)
 162                        continue;
 163                fprintf(stderr,
 164                        "already have %s (%s)\n", sha1_to_hex(remote),
 165                        refs->name);
 166        }
 167        return retval;
 168}
 169
 170static int fetch_pack(int fd[2], int nr_match, char **match)
 171{
 172        struct ref *ref;
 173        unsigned char sha1[20];
 174        int status;
 175        pid_t pid;
 176
 177        get_remote_heads(fd[0], &ref, nr_match, match, 1);
 178        if (!ref) {
 179                packet_flush(fd[1]);
 180                die("no matching remote head");
 181        }
 182        if (everything_local(ref)) {
 183                packet_flush(fd[1]);
 184                goto all_done;
 185        }
 186        if (find_common(fd, sha1, ref) < 0)
 187                fprintf(stderr, "warning: no common commits\n");
 188        pid = fork();
 189        if (pid < 0)
 190                die("git-fetch-pack: unable to fork off git-unpack-objects");
 191        if (!pid) {
 192                dup2(fd[0], 0);
 193                close(fd[0]);
 194                close(fd[1]);
 195                execlp("git-unpack-objects", "git-unpack-objects",
 196                       quiet ? "-q" : NULL, NULL);
 197                die("git-unpack-objects exec failed");
 198        }
 199        close(fd[0]);
 200        close(fd[1]);
 201        while (waitpid(pid, &status, 0) < 0) {
 202                if (errno != EINTR)
 203                        die("waiting for git-unpack-objects: %s", strerror(errno));
 204        }
 205        if (WIFEXITED(status)) {
 206                int code = WEXITSTATUS(status);
 207                if (code)
 208                        die("git-unpack-objects died with error code %d", code);
 209all_done:
 210                while (ref) {
 211                        printf("%s %s\n",
 212                               sha1_to_hex(ref->old_sha1), ref->name);
 213                        ref = ref->next;
 214                }
 215                return 0;
 216        }
 217        if (WIFSIGNALED(status)) {
 218                int sig = WTERMSIG(status);
 219                die("git-unpack-objects died of signal %d", sig);
 220        }
 221        die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
 222}
 223
 224int main(int argc, char **argv)
 225{
 226        int i, ret, nr_heads;
 227        char *dest = NULL, **heads;
 228        int fd[2];
 229        pid_t pid;
 230
 231        nr_heads = 0;
 232        heads = NULL;
 233        for (i = 1; i < argc; i++) {
 234                char *arg = argv[i];
 235
 236                if (*arg == '-') {
 237                        if (!strncmp("--exec=", arg, 7)) {
 238                                exec = arg + 7;
 239                                continue;
 240                        }
 241                        if (!strcmp("-q", arg)) {
 242                                quiet = 1;
 243                                continue;
 244                        }
 245                        if (!strcmp("-v", arg)) {
 246                                verbose = 1;
 247                                continue;
 248                        }
 249                        usage(fetch_pack_usage);
 250                }
 251                dest = arg;
 252                heads = argv + i + 1;
 253                nr_heads = argc - i - 1;
 254                break;
 255        }
 256        if (!dest)
 257                usage(fetch_pack_usage);
 258        pid = git_connect(fd, dest, exec);
 259        if (pid < 0)
 260                return 1;
 261        ret = fetch_pack(fd, nr_heads, heads);
 262        close(fd[0]);
 263        close(fd[1]);
 264        finish_connect(pid);
 265        return ret;
 266}