Allow helper to map private ref names into normal names
[git/dscho.git] / transport-helper.c
blobda8185a98150fddf692c9ead76097acbe7b9b41c
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"
8 #include "remote.h"
10 struct helper_data
12 const char *name;
13 struct child_process *helper;
14 unsigned fetch : 1;
15 unsigned import : 1;
16 /* These go from remote name (as in "list") to private name */
17 struct refspec *refspecs;
18 int refspec_nr;
21 static struct child_process *get_helper(struct transport *transport)
23 struct helper_data *data = transport->data;
24 struct strbuf buf = STRBUF_INIT;
25 struct child_process *helper;
26 FILE *file;
27 const char **refspecs = NULL;
28 int refspec_nr = 0;
29 int refspec_alloc = 0;
31 if (data->helper)
32 return data->helper;
34 helper = xcalloc(1, sizeof(*helper));
35 helper->in = -1;
36 helper->out = -1;
37 helper->err = 0;
38 helper->argv = xcalloc(4, sizeof(*helper->argv));
39 strbuf_addf(&buf, "remote-%s", data->name);
40 helper->argv[0] = strbuf_detach(&buf, NULL);
41 helper->argv[1] = transport->remote->name;
42 helper->argv[2] = transport->url;
43 helper->git_cmd = 1;
44 if (start_command(helper))
45 die("Unable to run helper: git %s", helper->argv[0]);
46 data->helper = helper;
48 write_str_in_full(helper->in, "capabilities\n");
50 file = xfdopen(helper->out, "r");
51 while (1) {
52 if (strbuf_getline(&buf, file, '\n') == EOF)
53 exit(128); /* child died, message supplied already */
55 if (!*buf.buf)
56 break;
57 if (!strcmp(buf.buf, "fetch"))
58 data->fetch = 1;
59 if (!strcmp(buf.buf, "import"))
60 data->import = 1;
61 if (!data->refspecs && !prefixcmp(buf.buf, "refspec ")) {
62 ALLOC_GROW(refspecs,
63 refspec_nr + 1,
64 refspec_alloc);
65 refspecs[refspec_nr++] = strdup(buf.buf + strlen("refspec "));
68 if (refspecs) {
69 int i;
70 data->refspec_nr = refspec_nr;
71 data->refspecs = parse_fetch_refspec(refspec_nr, refspecs);
72 for (i = 0; i < refspec_nr; i++) {
73 free((char *)refspecs[i]);
75 free(refspecs);
77 return data->helper;
80 static int disconnect_helper(struct transport *transport)
82 struct helper_data *data = transport->data;
83 if (data->helper) {
84 write_str_in_full(data->helper->in, "\n");
85 close(data->helper->in);
86 finish_command(data->helper);
87 free((char *)data->helper->argv[0]);
88 free(data->helper->argv);
89 free(data->helper);
90 data->helper = NULL;
92 return 0;
95 static int release_helper(struct transport *transport)
97 struct helper_data *data = transport->data;
98 free_refspec(data->refspec_nr, data->refspecs);
99 data->refspecs = NULL;
100 disconnect_helper(transport);
101 free(transport->data);
102 return 0;
105 static int fetch_with_fetch(struct transport *transport,
106 int nr_heads, struct ref **to_fetch)
108 struct child_process *helper = get_helper(transport);
109 FILE *file = xfdopen(helper->out, "r");
110 int i;
111 struct strbuf buf = STRBUF_INIT;
113 for (i = 0; i < nr_heads; i++) {
114 const struct ref *posn = to_fetch[i];
115 if (posn->status & REF_STATUS_UPTODATE)
116 continue;
118 strbuf_addf(&buf, "fetch %s %s\n",
119 sha1_to_hex(posn->old_sha1), posn->name);
120 write_in_full(helper->in, buf.buf, buf.len);
121 strbuf_reset(&buf);
123 if (strbuf_getline(&buf, file, '\n') == EOF)
124 exit(128); /* child died, message supplied already */
126 return 0;
129 static int get_importer(struct transport *transport, struct child_process *fastimport)
131 struct child_process *helper = get_helper(transport);
132 memset(fastimport, 0, sizeof(*fastimport));
133 fastimport->in = helper->out;
134 fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
135 fastimport->argv[0] = "fast-import";
136 fastimport->argv[1] = "--quiet";
138 fastimport->git_cmd = 1;
139 return start_command(fastimport);
142 static int fetch_with_import(struct transport *transport,
143 int nr_heads, struct ref **to_fetch)
145 struct child_process fastimport;
146 struct child_process *helper = get_helper(transport);
147 struct helper_data *data = transport->data;
148 int i;
149 struct ref *posn;
150 struct strbuf buf = STRBUF_INIT;
152 if (get_importer(transport, &fastimport))
153 die("Couldn't run fast-import");
155 for (i = 0; i < nr_heads; i++) {
156 posn = to_fetch[i];
157 if (posn->status & REF_STATUS_UPTODATE)
158 continue;
160 strbuf_addf(&buf, "import %s\n", posn->name);
161 write_in_full(helper->in, buf.buf, buf.len);
162 strbuf_reset(&buf);
164 disconnect_helper(transport);
165 finish_command(&fastimport);
167 for (i = 0; i < nr_heads; i++) {
168 char *private;
169 posn = to_fetch[i];
170 if (posn->status & REF_STATUS_UPTODATE)
171 continue;
172 if (data->refspecs)
173 private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name);
174 else
175 private = strdup(posn->name);
176 read_ref(private, posn->old_sha1);
177 free(private);
179 return 0;
182 static int fetch(struct transport *transport,
183 int nr_heads, struct ref **to_fetch)
185 struct helper_data *data = transport->data;
186 int i, count;
188 count = 0;
189 for (i = 0; i < nr_heads; i++)
190 if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
191 count++;
193 if (!count)
194 return 0;
196 if (data->fetch)
197 return fetch_with_fetch(transport, nr_heads, to_fetch);
199 if (data->import)
200 return fetch_with_import(transport, nr_heads, to_fetch);
202 return -1;
205 static struct ref *get_refs_list(struct transport *transport, int for_push)
207 struct child_process *helper;
208 struct ref *ret = NULL;
209 struct ref **tail = &ret;
210 struct ref *posn;
211 struct strbuf buf = STRBUF_INIT;
212 FILE *file;
214 helper = get_helper(transport);
216 write_str_in_full(helper->in, "list\n");
218 file = xfdopen(helper->out, "r");
219 while (1) {
220 char *eov, *eon;
221 if (strbuf_getline(&buf, file, '\n') == EOF)
222 exit(128); /* child died, message supplied already */
224 if (!*buf.buf)
225 break;
227 eov = strchr(buf.buf, ' ');
228 if (!eov)
229 die("Malformed response in ref list: %s", buf.buf);
230 eon = strchr(eov + 1, ' ');
231 *eov = '\0';
232 if (eon)
233 *eon = '\0';
234 *tail = alloc_ref(eov + 1);
235 if (buf.buf[0] == '@')
236 (*tail)->symref = xstrdup(buf.buf + 1);
237 else if (buf.buf[0] != '?')
238 get_sha1_hex(buf.buf, (*tail)->old_sha1);
239 tail = &((*tail)->next);
241 strbuf_release(&buf);
243 for (posn = ret; posn; posn = posn->next)
244 resolve_remote_symref(posn, ret);
246 return ret;
249 int transport_helper_init(struct transport *transport, const char *name)
251 struct helper_data *data = xcalloc(sizeof(*data), 1);
252 data->name = name;
254 transport->data = data;
255 transport->get_refs_list = get_refs_list;
256 transport->fetch = fetch;
257 transport->disconnect = release_helper;
258 return 0;