]> git.ipfire.org Git - thirdparty/git.git/blame - remote-curl.c
remote-helpers: Support custom transport options
[thirdparty/git.git] / remote-curl.c
CommitLineData
a2d725b7
DB
1#include "cache.h"
2#include "remote.h"
3#include "strbuf.h"
4#include "walker.h"
5#include "http.h"
d01a8e32 6#include "exec_cmd.h"
a2d725b7 7
37a8768f
SP
8static struct remote *remote;
9static const char *url;
10static struct walker *walker;
11
ef08ef9e
SP
12struct options {
13 int verbosity;
14 unsigned long depth;
15 unsigned progress : 1,
16 followtags : 1;
17};
18static struct options options;
19
37a8768f
SP
20static void init_walker(void)
21{
22 if (!walker)
23 walker = get_http_walker(url, remote);
24}
25
ef08ef9e
SP
26static int set_option(const char *name, const char *value)
27{
28 if (!strcmp(name, "verbosity")) {
29 char *end;
30 int v = strtol(value, &end, 10);
31 if (value == end || *end)
32 return -1;
33 options.verbosity = v;
34 return 0;
35 }
36 else if (!strcmp(name, "progress")) {
37 if (!strcmp(value, "true"))
38 options.progress = 1;
39 else if (!strcmp(value, "false"))
40 options.progress = 0;
41 else
42 return -1;
43 return 1 /* TODO implement later */;
44 }
45 else if (!strcmp(name, "depth")) {
46 char *end;
47 unsigned long v = strtoul(value, &end, 10);
48 if (value == end || *end)
49 return -1;
50 options.depth = v;
51 return 1 /* TODO implement later */;
52 }
53 else if (!strcmp(name, "followtags")) {
54 if (!strcmp(value, "true"))
55 options.followtags = 1;
56 else if (!strcmp(value, "false"))
57 options.followtags = 0;
58 else
59 return -1;
60 return 1 /* TODO implement later */;
61 }
62 else {
63 return 1 /* unsupported */;
64 }
65}
66
37a8768f 67static struct ref *get_refs(void)
a2d725b7
DB
68{
69 struct strbuf buffer = STRBUF_INIT;
70 char *data, *start, *mid;
71 char *ref_name;
72 char *refs_url;
73 int i = 0;
74 int http_ret;
75
76 struct ref *refs = NULL;
77 struct ref *ref = NULL;
78 struct ref *last_ref = NULL;
79
80 refs_url = xmalloc(strlen(url) + 11);
81 sprintf(refs_url, "%s/info/refs", url);
82
37a8768f 83 init_walker();
a2d725b7
DB
84 http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
85 switch (http_ret) {
86 case HTTP_OK:
87 break;
88 case HTTP_MISSING_TARGET:
89 die("%s not found: did you run git update-server-info on the"
90 " server?", refs_url);
91 default:
92 http_error(refs_url, http_ret);
93 die("HTTP request failed");
94 }
95
96 data = buffer.buf;
97 start = NULL;
98 mid = data;
99 while (i < buffer.len) {
100 if (!start) {
101 start = &data[i];
102 }
103 if (data[i] == '\t')
104 mid = &data[i];
105 if (data[i] == '\n') {
106 data[i] = 0;
107 ref_name = mid + 1;
108 ref = xmalloc(sizeof(struct ref) +
109 strlen(ref_name) + 1);
110 memset(ref, 0, sizeof(struct ref));
111 strcpy(ref->name, ref_name);
112 get_sha1_hex(start, ref->old_sha1);
113 if (!refs)
114 refs = ref;
115 if (last_ref)
116 last_ref->next = ref;
117 last_ref = ref;
118 start = NULL;
119 }
120 i++;
121 }
122
123 strbuf_release(&buffer);
124
125 ref = alloc_ref("HEAD");
126 if (!walker->fetch_ref(walker, ref) &&
127 !resolve_remote_symref(ref, refs)) {
128 ref->next = refs;
129 refs = ref;
130 } else {
131 free(ref);
132 }
133
134 strbuf_release(&buffer);
135 free(refs_url);
136 return refs;
137}
138
292ce46b
SP
139static int fetch_dumb(int nr_heads, struct ref **to_fetch)
140{
141 char **targets = xmalloc(nr_heads * sizeof(char*));
142 int ret, i;
143
144 for (i = 0; i < nr_heads; i++)
145 targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
146
147 init_walker();
148 walker->get_all = 1;
149 walker->get_tree = 1;
150 walker->get_history = 1;
ef08ef9e 151 walker->get_verbosely = options.verbosity >= 3;
292ce46b
SP
152 walker->get_recover = 0;
153 ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
154
155 for (i = 0; i < nr_heads; i++)
156 free(targets[i]);
157 free(targets);
158
159 return ret ? error("Fetch failed.") : 0;
160}
161
162static void parse_fetch(struct strbuf *buf)
163{
164 struct ref **to_fetch = NULL;
165 struct ref *list_head = NULL;
166 struct ref **list = &list_head;
167 int alloc_heads = 0, nr_heads = 0;
168
169 do {
170 if (!prefixcmp(buf->buf, "fetch ")) {
171 char *p = buf->buf + strlen("fetch ");
172 char *name;
173 struct ref *ref;
174 unsigned char old_sha1[20];
175
176 if (strlen(p) < 40 || get_sha1_hex(p, old_sha1))
177 die("protocol error: expected sha/ref, got %s'", p);
178 if (p[40] == ' ')
179 name = p + 41;
180 else if (!p[40])
181 name = "";
182 else
183 die("protocol error: expected sha/ref, got %s'", p);
184
185 ref = alloc_ref(name);
186 hashcpy(ref->old_sha1, old_sha1);
187
188 *list = ref;
189 list = &ref->next;
190
191 ALLOC_GROW(to_fetch, nr_heads + 1, alloc_heads);
192 to_fetch[nr_heads++] = ref;
193 }
194 else
195 die("http transport does not support %s", buf->buf);
196
197 strbuf_reset(buf);
198 if (strbuf_getline(buf, stdin, '\n') == EOF)
199 return;
200 if (!*buf->buf)
201 break;
202 } while (1);
203
204 if (fetch_dumb(nr_heads, to_fetch))
205 exit(128); /* error already reported */
206 free_refs(list_head);
207 free(to_fetch);
208
209 printf("\n");
210 fflush(stdout);
211 strbuf_reset(buf);
212}
213
a2d725b7
DB
214int main(int argc, const char **argv)
215{
a2d725b7 216 struct strbuf buf = STRBUF_INIT;
a2d725b7 217
c6dfb399 218 git_extract_argv0_path(argv[0]);
a2d725b7
DB
219 setup_git_directory();
220 if (argc < 2) {
221 fprintf(stderr, "Remote needed\n");
222 return 1;
223 }
224
ef08ef9e
SP
225 options.verbosity = 1;
226 options.progress = !!isatty(2);
227
a2d725b7
DB
228 remote = remote_get(argv[1]);
229
230 if (argc > 2) {
231 url = argv[2];
232 } else {
233 url = remote->url[0];
234 }
235
236 do {
237 if (strbuf_getline(&buf, stdin, '\n') == EOF)
238 break;
239 if (!prefixcmp(buf.buf, "fetch ")) {
292ce46b
SP
240 parse_fetch(&buf);
241
a2d725b7 242 } else if (!strcmp(buf.buf, "list")) {
37a8768f 243 struct ref *refs = get_refs();
a2d725b7 244 struct ref *posn;
a2d725b7
DB
245 for (posn = refs; posn; posn = posn->next) {
246 if (posn->symref)
247 printf("@%s %s\n", posn->symref, posn->name);
248 else
249 printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
250 }
251 printf("\n");
252 fflush(stdout);
ef08ef9e
SP
253 } else if (!prefixcmp(buf.buf, "option ")) {
254 char *name = buf.buf + strlen("option ");
255 char *value = strchr(name, ' ');
256 int result;
257
258 if (value)
259 *value++ = '\0';
260 else
261 value = "true";
262
263 result = set_option(name, value);
264 if (!result)
265 printf("ok\n");
266 else if (result < 0)
267 printf("error invalid value\n");
268 else
269 printf("unsupported\n");
270 fflush(stdout);
271
a2d725b7
DB
272 } else if (!strcmp(buf.buf, "capabilities")) {
273 printf("fetch\n");
ef08ef9e 274 printf("option\n");
a2d725b7
DB
275 printf("\n");
276 fflush(stdout);
277 } else {
278 return 1;
279 }
280 strbuf_reset(&buf);
281 } while (1);
282 return 0;
283}