Code

Merge branch 'db/vcs-helper'
[git.git] / transport-helper.c
1 #include "cache.h"
2 #include "transport.h"
4 #include "run-command.h"
5 #include "commit.h"
6 #include "diff.h"
7 #include "revision.h"
9 struct helper_data
10 {
11         const char *name;
12         struct child_process *helper;
13         unsigned fetch : 1;
14 };
16 static 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;
23         if (data->helper)
24                 return data->helper;
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;
40         strbuf_addstr(&buf, "capabilities\n");
41         write_in_full(helper->in, buf.buf, buf.len);
42         strbuf_reset(&buf);
44         file = fdopen(helper->out, "r");
45         while (1) {
46                 if (strbuf_getline(&buf, file, '\n') == EOF)
47                         exit(128); /* child died, message supplied already */
49                 if (!*buf.buf)
50                         break;
51                 if (!strcmp(buf.buf, "fetch"))
52                         data->fetch = 1;
53         }
54         return data->helper;
55 }
57 static int disconnect_helper(struct transport *transport)
58 {
59         struct helper_data *data = transport->data;
60         if (data->helper) {
61                 write_in_full(data->helper->in, "\n", 1);
62                 close(data->helper->in);
63                 finish_command(data->helper);
64                 free((char *)data->helper->argv[0]);
65                 free(data->helper->argv);
66                 free(data->helper);
67                 data->helper = NULL;
68         }
69         return 0;
70 }
72 static int fetch_with_fetch(struct transport *transport,
73                             int nr_heads, const struct ref **to_fetch)
74 {
75         struct child_process *helper = get_helper(transport);
76         FILE *file = fdopen(helper->out, "r");
77         int i;
78         struct strbuf buf = STRBUF_INIT;
80         for (i = 0; i < nr_heads; i++) {
81                 const struct ref *posn = to_fetch[i];
82                 if (posn->status & REF_STATUS_UPTODATE)
83                         continue;
85                 strbuf_addf(&buf, "fetch %s %s\n",
86                             sha1_to_hex(posn->old_sha1), posn->name);
87                 write_in_full(helper->in, buf.buf, buf.len);
88                 strbuf_reset(&buf);
90                 if (strbuf_getline(&buf, file, '\n') == EOF)
91                         exit(128); /* child died, message supplied already */
92         }
93         return 0;
94 }
96 static int fetch(struct transport *transport,
97                  int nr_heads, const struct ref **to_fetch)
98 {
99         struct helper_data *data = transport->data;
100         int i, count;
102         count = 0;
103         for (i = 0; i < nr_heads; i++)
104                 if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
105                         count++;
107         if (!count)
108                 return 0;
110         if (data->fetch)
111                 return fetch_with_fetch(transport, nr_heads, to_fetch);
113         return -1;
116 static struct ref *get_refs_list(struct transport *transport, int for_push)
118         struct child_process *helper;
119         struct ref *ret = NULL;
120         struct ref **tail = &ret;
121         struct ref *posn;
122         struct strbuf buf = STRBUF_INIT;
123         FILE *file;
125         helper = get_helper(transport);
127         strbuf_addstr(&buf, "list\n");
128         write_in_full(helper->in, buf.buf, buf.len);
129         strbuf_reset(&buf);
131         file = fdopen(helper->out, "r");
132         while (1) {
133                 char *eov, *eon;
134                 if (strbuf_getline(&buf, file, '\n') == EOF)
135                         exit(128); /* child died, message supplied already */
137                 if (!*buf.buf)
138                         break;
140                 eov = strchr(buf.buf, ' ');
141                 if (!eov)
142                         die("Malformed response in ref list: %s", buf.buf);
143                 eon = strchr(eov + 1, ' ');
144                 *eov = '\0';
145                 if (eon)
146                         *eon = '\0';
147                 *tail = alloc_ref(eov + 1);
148                 if (buf.buf[0] == '@')
149                         (*tail)->symref = xstrdup(buf.buf + 1);
150                 else if (buf.buf[0] != '?')
151                         get_sha1_hex(buf.buf, (*tail)->old_sha1);
152                 tail = &((*tail)->next);
153         }
154         strbuf_release(&buf);
156         for (posn = ret; posn; posn = posn->next)
157                 resolve_remote_symref(posn, ret);
159         return ret;
162 int transport_helper_init(struct transport *transport, const char *name)
164         struct helper_data *data = xcalloc(sizeof(*data), 1);
165         data->name = name;
167         transport->data = data;
168         transport->get_refs_list = get_refs_list;
169         transport->fetch = fetch;
170         transport->disconnect = disconnect_helper;
171         return 0;