]>
Commit | Line | Data |
---|---|---|
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 |
8 | static struct remote *remote; |
9 | static const char *url; | |
10 | static struct walker *walker; | |
11 | ||
ef08ef9e SP |
12 | struct options { |
13 | int verbosity; | |
14 | unsigned long depth; | |
15 | unsigned progress : 1, | |
16 | followtags : 1; | |
17 | }; | |
18 | static struct options options; | |
19 | ||
37a8768f SP |
20 | static void init_walker(void) |
21 | { | |
22 | if (!walker) | |
23 | walker = get_http_walker(url, remote); | |
24 | } | |
25 | ||
ef08ef9e SP |
26 | static 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 | 67 | static 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 |
139 | static 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 | ||
162 | static 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 |
214 | int 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 | } |