0951f116153409a1d5462865954ac60b15a0bdd5
   1#include "cache.h"
   2#include "remote.h"
   3#include "strbuf.h"
   4#include "walker.h"
   5#include "http.h"
   6#include "exec_cmd.h"
   7
   8static struct remote *remote;
   9static const char *url;
  10static struct walker *walker;
  11
  12struct options {
  13        int verbosity;
  14        unsigned long depth;
  15        unsigned progress : 1,
  16                followtags : 1;
  17};
  18static struct options options;
  19
  20static void init_walker(void)
  21{
  22        if (!walker)
  23                walker = get_http_walker(url, remote);
  24}
  25
  26static int set_option(const char *name, const char *value)
  27{
  28        if (!strcmp(name, "verbosity")) {
  29                char *end;
  30                int v = strtol(value, &end, 10);
  31                if (value == end || *end)
  32                        return -1;
  33                options.verbosity = v;
  34                return 0;
  35        }
  36        else if (!strcmp(name, "progress")) {
  37                if (!strcmp(value, "true"))
  38                        options.progress = 1;
  39                else if (!strcmp(value, "false"))
  40                        options.progress = 0;
  41                else
  42                        return -1;
  43                return 1 /* TODO implement later */;
  44        }
  45        else if (!strcmp(name, "depth")) {
  46                char *end;
  47                unsigned long v = strtoul(value, &end, 10);
  48                if (value == end || *end)
  49                        return -1;
  50                options.depth = v;
  51                return 1 /* TODO implement later */;
  52        }
  53        else if (!strcmp(name, "followtags")) {
  54                if (!strcmp(value, "true"))
  55                        options.followtags = 1;
  56                else if (!strcmp(value, "false"))
  57                        options.followtags = 0;
  58                else
  59                        return -1;
  60                return 1 /* TODO implement later */;
  61        }
  62        else {
  63                return 1 /* unsupported */;
  64        }
  65}
  66
  67static struct ref *get_refs(void)
  68{
  69        struct strbuf buffer = STRBUF_INIT;
  70        char *data, *start, *mid;
  71        char *ref_name;
  72        char *refs_url;
  73        int i = 0;
  74        int http_ret;
  75
  76        struct ref *refs = NULL;
  77        struct ref *ref = NULL;
  78        struct ref *last_ref = NULL;
  79
  80        refs_url = xmalloc(strlen(url) + 11);
  81        sprintf(refs_url, "%s/info/refs", url);
  82
  83        init_walker();
  84        http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
  85        switch (http_ret) {
  86        case HTTP_OK:
  87                break;
  88        case HTTP_MISSING_TARGET:
  89                die("%s not found: did you run git update-server-info on the"
  90                    " server?", refs_url);
  91        default:
  92                http_error(refs_url, http_ret);
  93                die("HTTP request failed");
  94        }
  95
  96        data = buffer.buf;
  97        start = NULL;
  98        mid = data;
  99        while (i < buffer.len) {
 100                if (!start) {
 101                        start = &data[i];
 102                }
 103                if (data[i] == '\t')
 104                        mid = &data[i];
 105                if (data[i] == '\n') {
 106                        data[i] = 0;
 107                        ref_name = mid + 1;
 108                        ref = xmalloc(sizeof(struct ref) +
 109                                      strlen(ref_name) + 1);
 110                        memset(ref, 0, sizeof(struct ref));
 111                        strcpy(ref->name, ref_name);
 112                        get_sha1_hex(start, ref->old_sha1);
 113                        if (!refs)
 114                                refs = ref;
 115                        if (last_ref)
 116                                last_ref->next = ref;
 117                        last_ref = ref;
 118                        start = NULL;
 119                }
 120                i++;
 121        }
 122
 123        strbuf_release(&buffer);
 124
 125        ref = alloc_ref("HEAD");
 126        if (!walker->fetch_ref(walker, ref) &&
 127            !resolve_remote_symref(ref, refs)) {
 128                ref->next = refs;
 129                refs = ref;
 130        } else {
 131                free(ref);
 132        }
 133
 134        strbuf_release(&buffer);
 135        free(refs_url);
 136        return refs;
 137}
 138
 139static int fetch_dumb(int nr_heads, struct ref **to_fetch)
 140{
 141        char **targets = xmalloc(nr_heads * sizeof(char*));
 142        int ret, i;
 143
 144        for (i = 0; i < nr_heads; i++)
 145                targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
 146
 147        init_walker();
 148        walker->get_all = 1;
 149        walker->get_tree = 1;
 150        walker->get_history = 1;
 151        walker->get_verbosely = options.verbosity >= 3;
 152        walker->get_recover = 0;
 153        ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
 154
 155        for (i = 0; i < nr_heads; i++)
 156                free(targets[i]);
 157        free(targets);
 158
 159        return ret ? error("Fetch failed.") : 0;
 160}
 161
 162static void parse_fetch(struct strbuf *buf)
 163{
 164        struct ref **to_fetch = NULL;
 165        struct ref *list_head = NULL;
 166        struct ref **list = &list_head;
 167        int alloc_heads = 0, nr_heads = 0;
 168
 169        do {
 170                if (!prefixcmp(buf->buf, "fetch ")) {
 171                        char *p = buf->buf + strlen("fetch ");
 172                        char *name;
 173                        struct ref *ref;
 174                        unsigned char old_sha1[20];
 175
 176                        if (strlen(p) < 40 || get_sha1_hex(p, old_sha1))
 177                                die("protocol error: expected sha/ref, got %s'", p);
 178                        if (p[40] == ' ')
 179                                name = p + 41;
 180                        else if (!p[40])
 181                                name = "";
 182                        else
 183                                die("protocol error: expected sha/ref, got %s'", p);
 184
 185                        ref = alloc_ref(name);
 186                        hashcpy(ref->old_sha1, old_sha1);
 187
 188                        *list = ref;
 189                        list = &ref->next;
 190
 191                        ALLOC_GROW(to_fetch, nr_heads + 1, alloc_heads);
 192                        to_fetch[nr_heads++] = ref;
 193                }
 194                else
 195                        die("http transport does not support %s", buf->buf);
 196
 197                strbuf_reset(buf);
 198                if (strbuf_getline(buf, stdin, '\n') == EOF)
 199                        return;
 200                if (!*buf->buf)
 201                        break;
 202        } while (1);
 203
 204        if (fetch_dumb(nr_heads, to_fetch))
 205                exit(128); /* error already reported */
 206        free_refs(list_head);
 207        free(to_fetch);
 208
 209        printf("\n");
 210        fflush(stdout);
 211        strbuf_reset(buf);
 212}
 213
 214int main(int argc, const char **argv)
 215{
 216        struct strbuf buf = STRBUF_INIT;
 217
 218        git_extract_argv0_path(argv[0]);
 219        setup_git_directory();
 220        if (argc < 2) {
 221                fprintf(stderr, "Remote needed\n");
 222                return 1;
 223        }
 224
 225        options.verbosity = 1;
 226        options.progress = !!isatty(2);
 227
 228        remote = remote_get(argv[1]);
 229
 230        if (argc > 2) {
 231                url = argv[2];
 232        } else {
 233                url = remote->url[0];
 234        }
 235
 236        do {
 237                if (strbuf_getline(&buf, stdin, '\n') == EOF)
 238                        break;
 239                if (!prefixcmp(buf.buf, "fetch ")) {
 240                        parse_fetch(&buf);
 241
 242                } else if (!strcmp(buf.buf, "list")) {
 243                        struct ref *refs = get_refs();
 244                        struct ref *posn;
 245                        for (posn = refs; posn; posn = posn->next) {
 246                                if (posn->symref)
 247                                        printf("@%s %s\n", posn->symref, posn->name);
 248                                else
 249                                        printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
 250                        }
 251                        printf("\n");
 252                        fflush(stdout);
 253                } else if (!prefixcmp(buf.buf, "option ")) {
 254                        char *name = buf.buf + strlen("option ");
 255                        char *value = strchr(name, ' ');
 256                        int result;
 257
 258                        if (value)
 259                                *value++ = '\0';
 260                        else
 261                                value = "true";
 262
 263                        result = set_option(name, value);
 264                        if (!result)
 265                                printf("ok\n");
 266                        else if (result < 0)
 267                                printf("error invalid value\n");
 268                        else
 269                                printf("unsupported\n");
 270                        fflush(stdout);
 271
 272                } else if (!strcmp(buf.buf, "capabilities")) {
 273                        printf("fetch\n");
 274                        printf("option\n");
 275                        printf("\n");
 276                        fflush(stdout);
 277                } else {
 278                        return 1;
 279                }
 280                strbuf_reset(&buf);
 281        } while (1);
 282        return 0;
 283}