628a5ca21062ee26ca219f75e13ad7d3c7dcff4d
[git/git.git] / transport-helper.c
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 #include "remote.h"
9
10 struct helper_data
11 {
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;
19 };
20
21 static struct child_process *get_helper(struct transport *transport)
22 {
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;
30
31 if (data->helper)
32 return data->helper;
33
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;
47
48 write_str_in_full(helper->in, "capabilities\n");
49
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 */
54
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 "));
66 }
67 }
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]);
74 }
75 free(refspecs);
76 }
77 strbuf_release(&buf);
78 return data->helper;
79 }
80
81 static int disconnect_helper(struct transport *transport)
82 {
83 struct helper_data *data = transport->data;
84 if (data->helper) {
85 write_str_in_full(data->helper->in, "\n");
86 close(data->helper->in);
87 finish_command(data->helper);
88 free((char *)data->helper->argv[0]);
89 free(data->helper->argv);
90 free(data->helper);
91 data->helper = NULL;
92 }
93 return 0;
94 }
95
96 static int release_helper(struct transport *transport)
97 {
98 struct helper_data *data = transport->data;
99 free_refspec(data->refspec_nr, data->refspecs);
100 data->refspecs = NULL;
101 disconnect_helper(transport);
102 free(transport->data);
103 return 0;
104 }
105
106 static int fetch_with_fetch(struct transport *transport,
107 int nr_heads, struct ref **to_fetch)
108 {
109 struct child_process *helper = get_helper(transport);
110 FILE *file = xfdopen(helper->out, "r");
111 int i;
112 struct strbuf buf = STRBUF_INIT;
113
114 for (i = 0; i < nr_heads; i++) {
115 const struct ref *posn = to_fetch[i];
116 if (posn->status & REF_STATUS_UPTODATE)
117 continue;
118
119 strbuf_addf(&buf, "fetch %s %s\n",
120 sha1_to_hex(posn->old_sha1), posn->name);
121 write_in_full(helper->in, buf.buf, buf.len);
122 strbuf_reset(&buf);
123
124 if (strbuf_getline(&buf, file, '\n') == EOF)
125 exit(128); /* child died, message supplied already */
126 }
127 return 0;
128 }
129
130 static int get_importer(struct transport *transport, struct child_process *fastimport)
131 {
132 struct child_process *helper = get_helper(transport);
133 memset(fastimport, 0, sizeof(*fastimport));
134 fastimport->in = helper->out;
135 fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
136 fastimport->argv[0] = "fast-import";
137 fastimport->argv[1] = "--quiet";
138
139 fastimport->git_cmd = 1;
140 return start_command(fastimport);
141 }
142
143 static int fetch_with_import(struct transport *transport,
144 int nr_heads, struct ref **to_fetch)
145 {
146 struct child_process fastimport;
147 struct child_process *helper = get_helper(transport);
148 struct helper_data *data = transport->data;
149 int i;
150 struct ref *posn;
151 struct strbuf buf = STRBUF_INIT;
152
153 if (get_importer(transport, &fastimport))
154 die("Couldn't run fast-import");
155
156 for (i = 0; i < nr_heads; i++) {
157 posn = to_fetch[i];
158 if (posn->status & REF_STATUS_UPTODATE)
159 continue;
160
161 strbuf_addf(&buf, "import %s\n", posn->name);
162 write_in_full(helper->in, buf.buf, buf.len);
163 strbuf_reset(&buf);
164 }
165 disconnect_helper(transport);
166 finish_command(&fastimport);
167 free(fastimport.argv);
168 fastimport.argv = NULL;
169
170 for (i = 0; i < nr_heads; i++) {
171 char *private;
172 posn = to_fetch[i];
173 if (posn->status & REF_STATUS_UPTODATE)
174 continue;
175 if (data->refspecs)
176 private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name);
177 else
178 private = strdup(posn->name);
179 read_ref(private, posn->old_sha1);
180 free(private);
181 }
182 strbuf_release(&buf);
183 return 0;
184 }
185
186 static int fetch(struct transport *transport,
187 int nr_heads, struct ref **to_fetch)
188 {
189 struct helper_data *data = transport->data;
190 int i, count;
191
192 count = 0;
193 for (i = 0; i < nr_heads; i++)
194 if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
195 count++;
196
197 if (!count)
198 return 0;
199
200 if (data->fetch)
201 return fetch_with_fetch(transport, nr_heads, to_fetch);
202
203 if (data->import)
204 return fetch_with_import(transport, nr_heads, to_fetch);
205
206 return -1;
207 }
208
209 static struct ref *get_refs_list(struct transport *transport, int for_push)
210 {
211 struct child_process *helper;
212 struct ref *ret = NULL;
213 struct ref **tail = &ret;
214 struct ref *posn;
215 struct strbuf buf = STRBUF_INIT;
216 FILE *file;
217
218 helper = get_helper(transport);
219
220 write_str_in_full(helper->in, "list\n");
221
222 file = xfdopen(helper->out, "r");
223 while (1) {
224 char *eov, *eon;
225 if (strbuf_getline(&buf, file, '\n') == EOF)
226 exit(128); /* child died, message supplied already */
227
228 if (!*buf.buf)
229 break;
230
231 eov = strchr(buf.buf, ' ');
232 if (!eov)
233 die("Malformed response in ref list: %s", buf.buf);
234 eon = strchr(eov + 1, ' ');
235 *eov = '\0';
236 if (eon)
237 *eon = '\0';
238 *tail = alloc_ref(eov + 1);
239 if (buf.buf[0] == '@')
240 (*tail)->symref = xstrdup(buf.buf + 1);
241 else if (buf.buf[0] != '?')
242 get_sha1_hex(buf.buf, (*tail)->old_sha1);
243 tail = &((*tail)->next);
244 }
245 strbuf_release(&buf);
246
247 for (posn = ret; posn; posn = posn->next)
248 resolve_remote_symref(posn, ret);
249
250 return ret;
251 }
252
253 int transport_helper_init(struct transport *transport, const char *name)
254 {
255 struct helper_data *data = xcalloc(sizeof(*data), 1);
256 data->name = name;
257
258 transport->data = data;
259 transport->get_refs_list = get_refs_list;
260 transport->fetch = fetch;
261 transport->disconnect = release_helper;
262 return 0;
263 }