Code

Move WebDAV HTTP push under remote-curl
[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"
7 #include "run-command.h"
9 static struct remote *remote;
10 static const char *url;
11 static struct walker *walker;
13 struct options {
14         int verbosity;
15         unsigned long depth;
16         unsigned progress : 1,
17                 followtags : 1,
18                 dry_run : 1;
19 };
20 static struct options options;
22 static void init_walker(void)
23 {
24         if (!walker)
25                 walker = get_http_walker(url, remote);
26 }
28 static int set_option(const char *name, const char *value)
29 {
30         if (!strcmp(name, "verbosity")) {
31                 char *end;
32                 int v = strtol(value, &end, 10);
33                 if (value == end || *end)
34                         return -1;
35                 options.verbosity = v;
36                 return 0;
37         }
38         else if (!strcmp(name, "progress")) {
39                 if (!strcmp(value, "true"))
40                         options.progress = 1;
41                 else if (!strcmp(value, "false"))
42                         options.progress = 0;
43                 else
44                         return -1;
45                 return 1 /* TODO implement later */;
46         }
47         else if (!strcmp(name, "depth")) {
48                 char *end;
49                 unsigned long v = strtoul(value, &end, 10);
50                 if (value == end || *end)
51                         return -1;
52                 options.depth = v;
53                 return 1 /* TODO implement later */;
54         }
55         else if (!strcmp(name, "followtags")) {
56                 if (!strcmp(value, "true"))
57                         options.followtags = 1;
58                 else if (!strcmp(value, "false"))
59                         options.followtags = 0;
60                 else
61                         return -1;
62                 return 1 /* TODO implement later */;
63         }
64         else if (!strcmp(name, "dry-run")) {
65                 if (!strcmp(value, "true"))
66                         options.dry_run = 1;
67                 else if (!strcmp(value, "false"))
68                         options.dry_run = 0;
69                 else
70                         return -1;
71                 return 0;
72         }
73         else {
74                 return 1 /* unsupported */;
75         }
76 }
78 static struct ref *get_refs(void)
79 {
80         struct strbuf buffer = STRBUF_INIT;
81         char *data, *start, *mid;
82         char *ref_name;
83         char *refs_url;
84         int i = 0;
85         int http_ret;
87         struct ref *refs = NULL;
88         struct ref *ref = NULL;
89         struct ref *last_ref = NULL;
91         refs_url = xmalloc(strlen(url) + 11);
92         sprintf(refs_url, "%s/info/refs", url);
94         init_walker();
95         http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
96         switch (http_ret) {
97         case HTTP_OK:
98                 break;
99         case HTTP_MISSING_TARGET:
100                 die("%s not found: did you run git update-server-info on the"
101                     " server?", refs_url);
102         default:
103                 http_error(refs_url, http_ret);
104                 die("HTTP request failed");
105         }
107         data = buffer.buf;
108         start = NULL;
109         mid = data;
110         while (i < buffer.len) {
111                 if (!start) {
112                         start = &data[i];
113                 }
114                 if (data[i] == '\t')
115                         mid = &data[i];
116                 if (data[i] == '\n') {
117                         data[i] = 0;
118                         ref_name = mid + 1;
119                         ref = xmalloc(sizeof(struct ref) +
120                                       strlen(ref_name) + 1);
121                         memset(ref, 0, sizeof(struct ref));
122                         strcpy(ref->name, ref_name);
123                         get_sha1_hex(start, ref->old_sha1);
124                         if (!refs)
125                                 refs = ref;
126                         if (last_ref)
127                                 last_ref->next = ref;
128                         last_ref = ref;
129                         start = NULL;
130                 }
131                 i++;
132         }
134         strbuf_release(&buffer);
136         ref = alloc_ref("HEAD");
137         if (!walker->fetch_ref(walker, ref) &&
138             !resolve_remote_symref(ref, refs)) {
139                 ref->next = refs;
140                 refs = ref;
141         } else {
142                 free(ref);
143         }
145         strbuf_release(&buffer);
146         free(refs_url);
147         return refs;
150 static void output_refs(struct ref *refs)
152         struct ref *posn;
153         for (posn = refs; posn; posn = posn->next) {
154                 if (posn->symref)
155                         printf("@%s %s\n", posn->symref, posn->name);
156                 else
157                         printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
158         }
159         printf("\n");
160         fflush(stdout);
161         free_refs(refs);
164 static int fetch_dumb(int nr_heads, struct ref **to_fetch)
166         char **targets = xmalloc(nr_heads * sizeof(char*));
167         int ret, i;
169         for (i = 0; i < nr_heads; i++)
170                 targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
172         init_walker();
173         walker->get_all = 1;
174         walker->get_tree = 1;
175         walker->get_history = 1;
176         walker->get_verbosely = options.verbosity >= 3;
177         walker->get_recover = 0;
178         ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
180         for (i = 0; i < nr_heads; i++)
181                 free(targets[i]);
182         free(targets);
184         return ret ? error("Fetch failed.") : 0;
187 static void parse_fetch(struct strbuf *buf)
189         struct ref **to_fetch = NULL;
190         struct ref *list_head = NULL;
191         struct ref **list = &list_head;
192         int alloc_heads = 0, nr_heads = 0;
194         do {
195                 if (!prefixcmp(buf->buf, "fetch ")) {
196                         char *p = buf->buf + strlen("fetch ");
197                         char *name;
198                         struct ref *ref;
199                         unsigned char old_sha1[20];
201                         if (strlen(p) < 40 || get_sha1_hex(p, old_sha1))
202                                 die("protocol error: expected sha/ref, got %s'", p);
203                         if (p[40] == ' ')
204                                 name = p + 41;
205                         else if (!p[40])
206                                 name = "";
207                         else
208                                 die("protocol error: expected sha/ref, got %s'", p);
210                         ref = alloc_ref(name);
211                         hashcpy(ref->old_sha1, old_sha1);
213                         *list = ref;
214                         list = &ref->next;
216                         ALLOC_GROW(to_fetch, nr_heads + 1, alloc_heads);
217                         to_fetch[nr_heads++] = ref;
218                 }
219                 else
220                         die("http transport does not support %s", buf->buf);
222                 strbuf_reset(buf);
223                 if (strbuf_getline(buf, stdin, '\n') == EOF)
224                         return;
225                 if (!*buf->buf)
226                         break;
227         } while (1);
229         if (fetch_dumb(nr_heads, to_fetch))
230                 exit(128); /* error already reported */
231         free_refs(list_head);
232         free(to_fetch);
234         printf("\n");
235         fflush(stdout);
236         strbuf_reset(buf);
239 static int push_dav(int nr_spec, char **specs)
241         const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
242         int argc = 0, i;
244         argv[argc++] = "http-push";
245         argv[argc++] = "--helper-status";
246         if (options.dry_run)
247                 argv[argc++] = "--dry-run";
248         if (options.verbosity > 1)
249                 argv[argc++] = "--verbose";
250         argv[argc++] = url;
251         for (i = 0; i < nr_spec; i++)
252                 argv[argc++] = specs[i];
253         argv[argc++] = NULL;
255         if (run_command_v_opt(argv, RUN_GIT_CMD))
256                 die("git-%s failed", argv[0]);
257         free(argv);
258         return 0;
261 static void parse_push(struct strbuf *buf)
263         char **specs = NULL;
264         int alloc_spec = 0, nr_spec = 0, i;
266         do {
267                 if (!prefixcmp(buf->buf, "push ")) {
268                         ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
269                         specs[nr_spec++] = xstrdup(buf->buf + 5);
270                 }
271                 else
272                         die("http transport does not support %s", buf->buf);
274                 strbuf_reset(buf);
275                 if (strbuf_getline(buf, stdin, '\n') == EOF)
276                         return;
277                 if (!*buf->buf)
278                         break;
279         } while (1);
281         if (push_dav(nr_spec, specs))
282                 exit(128); /* error already reported */
283         for (i = 0; i < nr_spec; i++)
284                 free(specs[i]);
285         free(specs);
287         printf("\n");
288         fflush(stdout);
291 int main(int argc, const char **argv)
293         struct strbuf buf = STRBUF_INIT;
295         git_extract_argv0_path(argv[0]);
296         setup_git_directory();
297         if (argc < 2) {
298                 fprintf(stderr, "Remote needed\n");
299                 return 1;
300         }
302         options.verbosity = 1;
303         options.progress = !!isatty(2);
305         remote = remote_get(argv[1]);
307         if (argc > 2) {
308                 url = argv[2];
309         } else {
310                 url = remote->url[0];
311         }
313         do {
314                 if (strbuf_getline(&buf, stdin, '\n') == EOF)
315                         break;
316                 if (!prefixcmp(buf.buf, "fetch ")) {
317                         parse_fetch(&buf);
319                 } else if (!strcmp(buf.buf, "list") || !prefixcmp(buf.buf, "list ")) {
320                         output_refs(get_refs());
322                 } else if (!prefixcmp(buf.buf, "push ")) {
323                         parse_push(&buf);
325                 } else if (!prefixcmp(buf.buf, "option ")) {
326                         char *name = buf.buf + strlen("option ");
327                         char *value = strchr(name, ' ');
328                         int result;
330                         if (value)
331                                 *value++ = '\0';
332                         else
333                                 value = "true";
335                         result = set_option(name, value);
336                         if (!result)
337                                 printf("ok\n");
338                         else if (result < 0)
339                                 printf("error invalid value\n");
340                         else
341                                 printf("unsupported\n");
342                         fflush(stdout);
344                 } else if (!strcmp(buf.buf, "capabilities")) {
345                         printf("fetch\n");
346                         printf("option\n");
347                         printf("push\n");
348                         printf("\n");
349                         fflush(stdout);
350                 } else {
351                         return 1;
352                 }
353                 strbuf_reset(&buf);
354         } while (1);
355         return 0;