remote-helpers: Fetch more than one ref in a batch
[git/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
12static void init_walker(void)
13{
14 if (!walker)
15 walker = get_http_walker(url, remote);
16}
17
18static struct ref *get_refs(void)
a2d725b7
DB
19{
20 struct strbuf buffer = STRBUF_INIT;
21 char *data, *start, *mid;
22 char *ref_name;
23 char *refs_url;
24 int i = 0;
25 int http_ret;
26
27 struct ref *refs = NULL;
28 struct ref *ref = NULL;
29 struct ref *last_ref = NULL;
30
31 refs_url = xmalloc(strlen(url) + 11);
32 sprintf(refs_url, "%s/info/refs", url);
33
37a8768f 34 init_walker();
a2d725b7
DB
35 http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
36 switch (http_ret) {
37 case HTTP_OK:
38 break;
39 case HTTP_MISSING_TARGET:
40 die("%s not found: did you run git update-server-info on the"
41 " server?", refs_url);
42 default:
43 http_error(refs_url, http_ret);
44 die("HTTP request failed");
45 }
46
47 data = buffer.buf;
48 start = NULL;
49 mid = data;
50 while (i < buffer.len) {
51 if (!start) {
52 start = &data[i];
53 }
54 if (data[i] == '\t')
55 mid = &data[i];
56 if (data[i] == '\n') {
57 data[i] = 0;
58 ref_name = mid + 1;
59 ref = xmalloc(sizeof(struct ref) +
60 strlen(ref_name) + 1);
61 memset(ref, 0, sizeof(struct ref));
62 strcpy(ref->name, ref_name);
63 get_sha1_hex(start, ref->old_sha1);
64 if (!refs)
65 refs = ref;
66 if (last_ref)
67 last_ref->next = ref;
68 last_ref = ref;
69 start = NULL;
70 }
71 i++;
72 }
73
74 strbuf_release(&buffer);
75
76 ref = alloc_ref("HEAD");
77 if (!walker->fetch_ref(walker, ref) &&
78 !resolve_remote_symref(ref, refs)) {
79 ref->next = refs;
80 refs = ref;
81 } else {
82 free(ref);
83 }
84
85 strbuf_release(&buffer);
86 free(refs_url);
87 return refs;
88}
89
292ce46b
SP
90static int fetch_dumb(int nr_heads, struct ref **to_fetch)
91{
92 char **targets = xmalloc(nr_heads * sizeof(char*));
93 int ret, i;
94
95 for (i = 0; i < nr_heads; i++)
96 targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
97
98 init_walker();
99 walker->get_all = 1;
100 walker->get_tree = 1;
101 walker->get_history = 1;
102 walker->get_verbosely = 0;
103 walker->get_recover = 0;
104 ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
105
106 for (i = 0; i < nr_heads; i++)
107 free(targets[i]);
108 free(targets);
109
110 return ret ? error("Fetch failed.") : 0;
111}
112
113static void parse_fetch(struct strbuf *buf)
114{
115 struct ref **to_fetch = NULL;
116 struct ref *list_head = NULL;
117 struct ref **list = &list_head;
118 int alloc_heads = 0, nr_heads = 0;
119
120 do {
121 if (!prefixcmp(buf->buf, "fetch ")) {
122 char *p = buf->buf + strlen("fetch ");
123 char *name;
124 struct ref *ref;
125 unsigned char old_sha1[20];
126
127 if (strlen(p) < 40 || get_sha1_hex(p, old_sha1))
128 die("protocol error: expected sha/ref, got %s'", p);
129 if (p[40] == ' ')
130 name = p + 41;
131 else if (!p[40])
132 name = "";
133 else
134 die("protocol error: expected sha/ref, got %s'", p);
135
136 ref = alloc_ref(name);
137 hashcpy(ref->old_sha1, old_sha1);
138
139 *list = ref;
140 list = &ref->next;
141
142 ALLOC_GROW(to_fetch, nr_heads + 1, alloc_heads);
143 to_fetch[nr_heads++] = ref;
144 }
145 else
146 die("http transport does not support %s", buf->buf);
147
148 strbuf_reset(buf);
149 if (strbuf_getline(buf, stdin, '\n') == EOF)
150 return;
151 if (!*buf->buf)
152 break;
153 } while (1);
154
155 if (fetch_dumb(nr_heads, to_fetch))
156 exit(128); /* error already reported */
157 free_refs(list_head);
158 free(to_fetch);
159
160 printf("\n");
161 fflush(stdout);
162 strbuf_reset(buf);
163}
164
a2d725b7
DB
165int main(int argc, const char **argv)
166{
a2d725b7 167 struct strbuf buf = STRBUF_INIT;
a2d725b7 168
c6dfb399 169 git_extract_argv0_path(argv[0]);
a2d725b7
DB
170 setup_git_directory();
171 if (argc < 2) {
172 fprintf(stderr, "Remote needed\n");
173 return 1;
174 }
175
176 remote = remote_get(argv[1]);
177
178 if (argc > 2) {
179 url = argv[2];
180 } else {
181 url = remote->url[0];
182 }
183
184 do {
185 if (strbuf_getline(&buf, stdin, '\n') == EOF)
186 break;
187 if (!prefixcmp(buf.buf, "fetch ")) {
292ce46b
SP
188 parse_fetch(&buf);
189
a2d725b7 190 } else if (!strcmp(buf.buf, "list")) {
37a8768f 191 struct ref *refs = get_refs();
a2d725b7 192 struct ref *posn;
a2d725b7
DB
193 for (posn = refs; posn; posn = posn->next) {
194 if (posn->symref)
195 printf("@%s %s\n", posn->symref, posn->name);
196 else
197 printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
198 }
199 printf("\n");
200 fflush(stdout);
201 } else if (!strcmp(buf.buf, "capabilities")) {
202 printf("fetch\n");
203 printf("\n");
204 fflush(stdout);
205 } else {
206 return 1;
207 }
208 strbuf_reset(&buf);
209 } while (1);
210 return 0;
211}