Code

remote-helpers: Fetch more than one ref in a batch
[git.git] / remote-curl.c
1 #include "cache.h"
2 #include "remote.h"
3 #include "strbuf.h"
4 #include "walker.h"
5 #include "http.h"
6 #include "exec_cmd.h"
8 static struct remote *remote;
9 static const char *url;
10 static struct walker *walker;
12 static void init_walker(void)
13 {
14         if (!walker)
15                 walker = get_http_walker(url, remote);
16 }
18 static struct ref *get_refs(void)
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;
27         struct ref *refs = NULL;
28         struct ref *ref = NULL;
29         struct ref *last_ref = NULL;
31         refs_url = xmalloc(strlen(url) + 11);
32         sprintf(refs_url, "%s/info/refs", url);
34         init_walker();
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         }
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         }
74         strbuf_release(&buffer);
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         }
85         strbuf_release(&buffer);
86         free(refs_url);
87         return refs;
88 }
90 static int fetch_dumb(int nr_heads, struct ref **to_fetch)
91 {
92         char **targets = xmalloc(nr_heads * sizeof(char*));
93         int ret, i;
95         for (i = 0; i < nr_heads; i++)
96                 targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
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);
106         for (i = 0; i < nr_heads; i++)
107                 free(targets[i]);
108         free(targets);
110         return ret ? error("Fetch failed.") : 0;
113 static void parse_fetch(struct strbuf *buf)
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;
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];
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);
136                         ref = alloc_ref(name);
137                         hashcpy(ref->old_sha1, old_sha1);
139                         *list = ref;
140                         list = &ref->next;
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);
148                 strbuf_reset(buf);
149                 if (strbuf_getline(buf, stdin, '\n') == EOF)
150                         return;
151                 if (!*buf->buf)
152                         break;
153         } while (1);
155         if (fetch_dumb(nr_heads, to_fetch))
156                 exit(128); /* error already reported */
157         free_refs(list_head);
158         free(to_fetch);
160         printf("\n");
161         fflush(stdout);
162         strbuf_reset(buf);
165 int main(int argc, const char **argv)
167         struct strbuf buf = STRBUF_INIT;
169         git_extract_argv0_path(argv[0]);
170         setup_git_directory();
171         if (argc < 2) {
172                 fprintf(stderr, "Remote needed\n");
173                 return 1;
174         }
176         remote = remote_get(argv[1]);
178         if (argc > 2) {
179                 url = argv[2];
180         } else {
181                 url = remote->url[0];
182         }
184         do {
185                 if (strbuf_getline(&buf, stdin, '\n') == EOF)
186                         break;
187                 if (!prefixcmp(buf.buf, "fetch ")) {
188                         parse_fetch(&buf);
190                 } else if (!strcmp(buf.buf, "list")) {
191                         struct ref *refs = get_refs();
192                         struct ref *posn;
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;