transport-helper.con commit git-http-fetch: not a builtin (1088261)
   1#include "cache.h"
   2#include "transport.h"
   3
   4#include "run-command.h"
   5#include "commit.h"
   6#include "diff.h"
   7#include "revision.h"
   8
   9struct helper_data
  10{
  11        const char *name;
  12        struct child_process *helper;
  13        unsigned fetch : 1;
  14};
  15
  16static struct child_process *get_helper(struct transport *transport)
  17{
  18        struct helper_data *data = transport->data;
  19        struct strbuf buf = STRBUF_INIT;
  20        struct child_process *helper;
  21        FILE *file;
  22
  23        if (data->helper)
  24                return data->helper;
  25
  26        helper = xcalloc(1, sizeof(*helper));
  27        helper->in = -1;
  28        helper->out = -1;
  29        helper->err = 0;
  30        helper->argv = xcalloc(4, sizeof(*helper->argv));
  31        strbuf_addf(&buf, "remote-%s", data->name);
  32        helper->argv[0] = strbuf_detach(&buf, NULL);
  33        helper->argv[1] = transport->remote->name;
  34        helper->argv[2] = transport->url;
  35        helper->git_cmd = 1;
  36        if (start_command(helper))
  37                die("Unable to run helper: git %s", helper->argv[0]);
  38        data->helper = helper;
  39
  40        write_in_full(data->helper->in, "capabilities\n", 13);
  41        file = fdopen(helper->out, "r");
  42        while (1) {
  43                if (strbuf_getline(&buf, file, '\n') == EOF)
  44                        exit(128); /* child died, message supplied already */
  45
  46                if (!*buf.buf)
  47                        break;
  48                if (!strcmp(buf.buf, "fetch"))
  49                        data->fetch = 1;
  50        }
  51        return data->helper;
  52}
  53
  54static int disconnect_helper(struct transport *transport)
  55{
  56        struct helper_data *data = transport->data;
  57        if (data->helper) {
  58                write_in_full(data->helper->in, "\n", 1);
  59                close(data->helper->in);
  60                finish_command(data->helper);
  61                free((char *)data->helper->argv[0]);
  62                free(data->helper->argv);
  63                free(data->helper);
  64                data->helper = NULL;
  65        }
  66        return 0;
  67}
  68
  69static int fetch_with_fetch(struct transport *transport,
  70                            int nr_heads, const struct ref **to_fetch)
  71{
  72        struct child_process *helper = get_helper(transport);
  73        FILE *file = fdopen(helper->out, "r");
  74        int i;
  75        struct strbuf buf = STRBUF_INIT;
  76
  77        for (i = 0; i < nr_heads; i++) {
  78                const struct ref *posn = to_fetch[i];
  79                if (posn->status & REF_STATUS_UPTODATE)
  80                        continue;
  81                write_in_full(helper->in, "fetch ", 6);
  82                write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40);
  83                write_in_full(helper->in, " ", 1);
  84                write_in_full(helper->in, posn->name, strlen(posn->name));
  85                write_in_full(helper->in, "\n", 1);
  86                if (strbuf_getline(&buf, file, '\n') == EOF)
  87                        exit(128); /* child died, message supplied already */
  88        }
  89        return 0;
  90}
  91
  92static int fetch(struct transport *transport,
  93                 int nr_heads, const struct ref **to_fetch)
  94{
  95        struct helper_data *data = transport->data;
  96        int i, count;
  97
  98        count = 0;
  99        for (i = 0; i < nr_heads; i++)
 100                if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
 101                        count++;
 102
 103        if (!count)
 104                return 0;
 105
 106        if (data->fetch)
 107                return fetch_with_fetch(transport, nr_heads, to_fetch);
 108
 109        return -1;
 110}
 111
 112static struct ref *get_refs_list(struct transport *transport, int for_push)
 113{
 114        struct child_process *helper;
 115        struct ref *ret = NULL;
 116        struct ref **tail = &ret;
 117        struct ref *posn;
 118        struct strbuf buf = STRBUF_INIT;
 119        FILE *file;
 120
 121        helper = get_helper(transport);
 122        write_in_full(helper->in, "list\n", 5);
 123
 124        file = fdopen(helper->out, "r");
 125        while (1) {
 126                char *eov, *eon;
 127                if (strbuf_getline(&buf, file, '\n') == EOF)
 128                        exit(128); /* child died, message supplied already */
 129
 130                if (!*buf.buf)
 131                        break;
 132
 133                eov = strchr(buf.buf, ' ');
 134                if (!eov)
 135                        die("Malformed response in ref list: %s", buf.buf);
 136                eon = strchr(eov + 1, ' ');
 137                *eov = '\0';
 138                if (eon)
 139                        *eon = '\0';
 140                *tail = alloc_ref(eov + 1);
 141                if (buf.buf[0] == '@')
 142                        (*tail)->symref = xstrdup(buf.buf + 1);
 143                else if (buf.buf[0] != '?')
 144                        get_sha1_hex(buf.buf, (*tail)->old_sha1);
 145                tail = &((*tail)->next);
 146        }
 147        strbuf_release(&buf);
 148
 149        for (posn = ret; posn; posn = posn->next)
 150                resolve_remote_symref(posn, ret);
 151
 152        return ret;
 153}
 154
 155int transport_helper_init(struct transport *transport)
 156{
 157        struct helper_data *data = xcalloc(sizeof(*data), 1);
 158        char *eom = strchr(transport->url, ':');
 159        if (!eom)
 160                return -1;
 161        data->name = xstrndup(transport->url, eom - transport->url);
 162
 163        transport->data = data;
 164        transport->get_refs_list = get_refs_list;
 165        transport->fetch = fetch;
 166        transport->disconnect = disconnect_helper;
 167        return 0;
 168}