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 | ||
12 | static void init_walker(void) | |
13 | { | |
14 | if (!walker) | |
15 | walker = get_http_walker(url, remote); | |
16 | } | |
17 | ||
18 | static 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 |
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; | |
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 | ||
113 | static 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 |
165 | int 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 | } |