Commit | Line | Data |
---|---|---|
6eb996b5 DB |
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" | |
72ff8943 | 8 | #include "remote.h" |
6eb996b5 DB |
9 | |
10 | struct helper_data | |
11 | { | |
12 | const char *name; | |
13 | struct child_process *helper; | |
14 | unsigned fetch : 1; | |
e65e91ed | 15 | unsigned import : 1; |
72ff8943 DB |
16 | /* These go from remote name (as in "list") to private name */ |
17 | struct refspec *refspecs; | |
18 | int refspec_nr; | |
6eb996b5 DB |
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; | |
72ff8943 DB |
27 | const char **refspecs = NULL; |
28 | int refspec_nr = 0; | |
29 | int refspec_alloc = 0; | |
6eb996b5 DB |
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 | ||
3d913526 | 48 | write_str_in_full(helper->in, "capabilities\n"); |
2d14d65c | 49 | |
41698375 | 50 | file = xfdopen(helper->out, "r"); |
6eb996b5 DB |
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; | |
e65e91ed DB |
59 | if (!strcmp(buf.buf, "import")) |
60 | data->import = 1; | |
72ff8943 DB |
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); | |
6eb996b5 | 76 | } |
b962dbdc | 77 | strbuf_release(&buf); |
6eb996b5 DB |
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) { | |
3d913526 | 85 | write_str_in_full(data->helper->in, "\n"); |
6eb996b5 DB |
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 | ||
f2a37151 DB |
96 | static int release_helper(struct transport *transport) |
97 | { | |
72ff8943 DB |
98 | struct helper_data *data = transport->data; |
99 | free_refspec(data->refspec_nr, data->refspecs); | |
100 | data->refspecs = NULL; | |
f2a37151 DB |
101 | disconnect_helper(transport); |
102 | free(transport->data); | |
103 | return 0; | |
104 | } | |
105 | ||
6eb996b5 | 106 | static int fetch_with_fetch(struct transport *transport, |
37148311 | 107 | int nr_heads, struct ref **to_fetch) |
6eb996b5 DB |
108 | { |
109 | struct child_process *helper = get_helper(transport); | |
41698375 | 110 | FILE *file = xfdopen(helper->out, "r"); |
6eb996b5 DB |
111 | int i; |
112 | struct strbuf buf = STRBUF_INIT; | |
113 | ||
114 | for (i = 0; i < nr_heads; i++) { | |
1088261f | 115 | const struct ref *posn = to_fetch[i]; |
6eb996b5 DB |
116 | if (posn->status & REF_STATUS_UPTODATE) |
117 | continue; | |
2d14d65c DB |
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 | ||
6eb996b5 DB |
124 | if (strbuf_getline(&buf, file, '\n') == EOF) |
125 | exit(128); /* child died, message supplied already */ | |
126 | } | |
127 | return 0; | |
128 | } | |
129 | ||
e65e91ed DB |
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); | |
72ff8943 | 148 | struct helper_data *data = transport->data; |
e65e91ed DB |
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); | |
b962dbdc SR |
167 | free(fastimport.argv); |
168 | fastimport.argv = NULL; | |
e65e91ed DB |
169 | |
170 | for (i = 0; i < nr_heads; i++) { | |
72ff8943 | 171 | char *private; |
e65e91ed DB |
172 | posn = to_fetch[i]; |
173 | if (posn->status & REF_STATUS_UPTODATE) | |
174 | continue; | |
72ff8943 DB |
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); | |
e65e91ed | 181 | } |
b962dbdc | 182 | strbuf_release(&buf); |
e65e91ed DB |
183 | return 0; |
184 | } | |
185 | ||
6eb996b5 | 186 | static int fetch(struct transport *transport, |
37148311 | 187 | int nr_heads, struct ref **to_fetch) |
6eb996b5 DB |
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 | ||
e65e91ed DB |
203 | if (data->import) |
204 | return fetch_with_import(transport, nr_heads, to_fetch); | |
205 | ||
6eb996b5 DB |
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); | |
2d14d65c | 219 | |
3d913526 | 220 | write_str_in_full(helper->in, "list\n"); |
6eb996b5 | 221 | |
41698375 | 222 | file = xfdopen(helper->out, "r"); |
6eb996b5 DB |
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 | ||
c9e388bb | 253 | int transport_helper_init(struct transport *transport, const char *name) |
6eb996b5 DB |
254 | { |
255 | struct helper_data *data = xcalloc(sizeof(*data), 1); | |
c9e388bb | 256 | data->name = name; |
6eb996b5 DB |
257 | |
258 | transport->data = data; | |
259 | transport->get_refs_list = get_refs_list; | |
260 | transport->fetch = fetch; | |
f2a37151 | 261 | transport->disconnect = release_helper; |
6eb996b5 DB |
262 | return 0; |
263 | } |