Commit | Line | Data |
---|---|---|
def88e9a | 1 | #include "cache.h" |
fb9040cc | 2 | #include "refs.h" |
def88e9a | 3 | #include "pkt-line.h" |
49bb805e JH |
4 | #include "commit.h" |
5 | #include "tag.h" | |
6 | #include <time.h> | |
75bfc6c2 | 7 | #include <sys/wait.h> |
def88e9a | 8 | |
8b3d9dc0 | 9 | static int quiet; |
33b83034 JH |
10 | static int verbose; |
11 | static const char fetch_pack_usage[] = | |
12 | "git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>..."; | |
def88e9a LT |
13 | static const char *exec = "git-upload-pack"; |
14 | ||
0a8944dd JS |
15 | #define COMPLETE (1U << 0) |
16 | ||
33b83034 JH |
17 | static int find_common(int fd[2], unsigned char *result_sha1, |
18 | struct ref *refs) | |
def88e9a | 19 | { |
2759cbc7 | 20 | int fetching; |
af2d3aa4 JH |
21 | static char line[1000]; |
22 | static char rev_command[1024]; | |
23 | int count = 0, flushes = 0, retval, rev_command_len; | |
24 | FILE *revs; | |
def88e9a | 25 | |
af2d3aa4 JH |
26 | strcpy(rev_command, "git-rev-list $(git-rev-parse --all)"); |
27 | rev_command_len = strlen(rev_command); | |
2759cbc7 LT |
28 | fetching = 0; |
29 | for ( ; refs ; refs = refs->next) { | |
33b83034 | 30 | unsigned char *remote = refs->old_sha1; |
4dab94d5 | 31 | struct object *o; |
2759cbc7 | 32 | |
0a8944dd | 33 | /* |
4dab94d5 JH |
34 | * If that object is complete (i.e. it is an ancestor of a |
35 | * local ref), we tell them we have it but do not have to | |
36 | * tell them about its ancestors, which they already know | |
37 | * about. | |
f1f0a2be JH |
38 | * |
39 | * We use lookup_object here because we are only | |
40 | * interested in the case we *know* the object is | |
41 | * reachable and we have already scanned it. | |
4dab94d5 | 42 | */ |
f1f0a2be | 43 | if (((o = lookup_object(remote)) != NULL) && |
4dab94d5 | 44 | (o->flags & COMPLETE)) { |
af2d3aa4 JH |
45 | struct commit_list *p; |
46 | struct commit *commit = | |
47 | (struct commit *) (o = deref_tag(o)); | |
48 | if (!o) | |
49 | goto repair; | |
50 | if (o->type != commit_type) | |
51 | continue; | |
52 | p = commit->parents; | |
53 | while (p && | |
54 | rev_command_len + 44 < sizeof(rev_command)) { | |
55 | snprintf(rev_command + rev_command_len, 44, | |
56 | " ^%s", | |
57 | sha1_to_hex(p->item->object.sha1)); | |
58 | rev_command_len += 43; | |
59 | p = p->next; | |
60 | } | |
2759cbc7 | 61 | continue; |
0a8944dd | 62 | } |
af2d3aa4 JH |
63 | repair: |
64 | packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); | |
2759cbc7 | 65 | fetching++; |
33b83034 | 66 | } |
fb9040cc | 67 | packet_flush(fd[1]); |
2759cbc7 LT |
68 | if (!fetching) |
69 | return 1; | |
0a8944dd | 70 | |
af2d3aa4 JH |
71 | revs = popen(rev_command, "r"); |
72 | if (!revs) | |
73 | die("unable to run 'git-rev-list'"); | |
74 | ||
75 | flushes = 1; | |
75bfc6c2 | 76 | retval = -1; |
af2d3aa4 JH |
77 | while (fgets(line, sizeof(line), revs) != NULL) { |
78 | unsigned char sha1[20]; | |
79 | if (get_sha1_hex(line, sha1)) | |
80 | die("git-fetch-pack: expected object name, got crud"); | |
def88e9a | 81 | packet_write(fd[1], "have %s\n", sha1_to_hex(sha1)); |
33b83034 JH |
82 | if (verbose) |
83 | fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); | |
def88e9a LT |
84 | if (!(31 & ++count)) { |
85 | packet_flush(fd[1]); | |
86 | flushes++; | |
87 | ||
88 | /* | |
89 | * We keep one window "ahead" of the other side, and | |
90 | * will wait for an ACK only on the next one | |
91 | */ | |
92 | if (count == 32) | |
93 | continue; | |
af2d3aa4 JH |
94 | if (get_ack(fd[0], result_sha1)) { |
95 | flushes = 0; | |
96 | retval = 0; | |
97 | if (verbose) | |
98 | fprintf(stderr, "got ack\n"); | |
99 | break; | |
100 | } | |
def88e9a LT |
101 | flushes--; |
102 | } | |
103 | } | |
af2d3aa4 | 104 | pclose(revs); |
75bfc6c2 | 105 | packet_write(fd[1], "done\n"); |
33b83034 JH |
106 | if (verbose) |
107 | fprintf(stderr, "done\n"); | |
def88e9a | 108 | while (flushes) { |
af2d3aa4 | 109 | flushes--; |
33b83034 JH |
110 | if (get_ack(fd[0], result_sha1)) { |
111 | if (verbose) | |
af2d3aa4 JH |
112 | fprintf(stderr, "got ack\n"); |
113 | return 0; | |
33b83034 | 114 | } |
def88e9a | 115 | } |
75bfc6c2 | 116 | return retval; |
def88e9a LT |
117 | } |
118 | ||
49bb805e JH |
119 | static struct commit_list *complete = NULL; |
120 | ||
121 | static int mark_complete(const char *path, const unsigned char *sha1) | |
122 | { | |
123 | struct object *o = parse_object(sha1); | |
124 | ||
125 | while (o && o->type == tag_type) { | |
f1f0a2be JH |
126 | struct tag *t = (struct tag *) o; |
127 | if (!t->tagged) | |
128 | break; /* broken repository */ | |
49bb805e | 129 | o->flags |= COMPLETE; |
f1f0a2be | 130 | o = parse_object(t->tagged->sha1); |
49bb805e | 131 | } |
f1f0a2be | 132 | if (o && o->type == commit_type) { |
49bb805e JH |
133 | struct commit *commit = (struct commit *)o; |
134 | commit->object.flags |= COMPLETE; | |
135 | insert_by_date(commit, &complete); | |
136 | } | |
137 | return 0; | |
138 | } | |
139 | ||
140 | static void mark_recent_complete_commits(unsigned long cutoff) | |
141 | { | |
142 | while (complete && cutoff <= complete->item->date) { | |
143 | if (verbose) | |
144 | fprintf(stderr, "Marking %s as complete\n", | |
145 | sha1_to_hex(complete->item->object.sha1)); | |
146 | pop_most_recent_commit(&complete, COMPLETE); | |
147 | } | |
148 | } | |
149 | ||
2759cbc7 LT |
150 | static int everything_local(struct ref *refs) |
151 | { | |
49bb805e | 152 | struct ref *ref; |
2759cbc7 | 153 | int retval; |
49bb805e JH |
154 | unsigned long cutoff = 0; |
155 | ||
156 | track_object_refs = 0; | |
157 | save_commit_buffer = 0; | |
158 | ||
159 | for (ref = refs; ref; ref = ref->next) { | |
160 | struct object *o; | |
161 | ||
162 | o = parse_object(ref->old_sha1); | |
163 | if (!o) | |
164 | continue; | |
165 | ||
166 | /* We already have it -- which may mean that we were | |
167 | * in sync with the other side at some time after | |
168 | * that (it is OK if we guess wrong here). | |
169 | */ | |
170 | if (o->type == commit_type) { | |
171 | struct commit *commit = (struct commit *)o; | |
172 | if (!cutoff || cutoff < commit->date) | |
173 | cutoff = commit->date; | |
174 | } | |
175 | } | |
176 | ||
177 | for_each_ref(mark_complete); | |
178 | if (cutoff) | |
179 | mark_recent_complete_commits(cutoff); | |
2759cbc7 LT |
180 | |
181 | for (retval = 1; refs ; refs = refs->next) { | |
182 | const unsigned char *remote = refs->old_sha1; | |
183 | unsigned char local[20]; | |
49bb805e | 184 | struct object *o; |
2759cbc7 | 185 | |
49bb805e JH |
186 | o = parse_object(remote); |
187 | if (!o || !(o->flags & COMPLETE)) { | |
2759cbc7 LT |
188 | retval = 0; |
189 | if (!verbose) | |
190 | continue; | |
191 | fprintf(stderr, | |
192 | "want %s (%s)\n", sha1_to_hex(remote), | |
193 | refs->name); | |
194 | continue; | |
195 | } | |
196 | ||
197 | memcpy(refs->new_sha1, local, 20); | |
198 | if (!verbose) | |
199 | continue; | |
200 | fprintf(stderr, | |
201 | "already have %s (%s)\n", sha1_to_hex(remote), | |
202 | refs->name); | |
203 | } | |
204 | return retval; | |
205 | } | |
206 | ||
def88e9a LT |
207 | static int fetch_pack(int fd[2], int nr_match, char **match) |
208 | { | |
d1c133f5 LT |
209 | struct ref *ref; |
210 | unsigned char sha1[20]; | |
211 | int status; | |
75bfc6c2 | 212 | pid_t pid; |
def88e9a | 213 | |
1a7141ff | 214 | get_remote_heads(fd[0], &ref, nr_match, match, 1); |
d1c133f5 LT |
215 | if (!ref) { |
216 | packet_flush(fd[1]); | |
217 | die("no matching remote head"); | |
218 | } | |
2759cbc7 LT |
219 | if (everything_local(ref)) { |
220 | packet_flush(fd[1]); | |
221 | goto all_done; | |
222 | } | |
33b83034 JH |
223 | if (find_common(fd, sha1, ref) < 0) |
224 | fprintf(stderr, "warning: no common commits\n"); | |
75bfc6c2 LT |
225 | pid = fork(); |
226 | if (pid < 0) | |
227 | die("git-fetch-pack: unable to fork off git-unpack-objects"); | |
228 | if (!pid) { | |
75bfc6c2 LT |
229 | dup2(fd[0], 0); |
230 | close(fd[0]); | |
85c414b5 | 231 | close(fd[1]); |
8b3d9dc0 JH |
232 | execlp("git-unpack-objects", "git-unpack-objects", |
233 | quiet ? "-q" : NULL, NULL); | |
75bfc6c2 LT |
234 | die("git-unpack-objects exec failed"); |
235 | } | |
fb9040cc | 236 | close(fd[0]); |
75bfc6c2 LT |
237 | close(fd[1]); |
238 | while (waitpid(pid, &status, 0) < 0) { | |
239 | if (errno != EINTR) | |
240 | die("waiting for git-unpack-objects: %s", strerror(errno)); | |
241 | } | |
242 | if (WIFEXITED(status)) { | |
243 | int code = WEXITSTATUS(status); | |
244 | if (code) | |
245 | die("git-unpack-objects died with error code %d", code); | |
2759cbc7 | 246 | all_done: |
33b83034 JH |
247 | while (ref) { |
248 | printf("%s %s\n", | |
249 | sha1_to_hex(ref->old_sha1), ref->name); | |
250 | ref = ref->next; | |
251 | } | |
75bfc6c2 LT |
252 | return 0; |
253 | } | |
254 | if (WIFSIGNALED(status)) { | |
255 | int sig = WTERMSIG(status); | |
256 | die("git-unpack-objects died of signal %d", sig); | |
257 | } | |
258 | die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status); | |
def88e9a LT |
259 | } |
260 | ||
261 | int main(int argc, char **argv) | |
262 | { | |
263 | int i, ret, nr_heads; | |
264 | char *dest = NULL, **heads; | |
265 | int fd[2]; | |
266 | pid_t pid; | |
267 | ||
268 | nr_heads = 0; | |
269 | heads = NULL; | |
270 | for (i = 1; i < argc; i++) { | |
271 | char *arg = argv[i]; | |
272 | ||
273 | if (*arg == '-') { | |
8b3d9dc0 JH |
274 | if (!strncmp("--exec=", arg, 7)) { |
275 | exec = arg + 7; | |
276 | continue; | |
277 | } | |
33b83034 JH |
278 | if (!strcmp("-q", arg)) { |
279 | quiet = 1; | |
280 | continue; | |
281 | } | |
282 | if (!strcmp("-v", arg)) { | |
283 | verbose = 1; | |
284 | continue; | |
285 | } | |
def88e9a LT |
286 | usage(fetch_pack_usage); |
287 | } | |
288 | dest = arg; | |
289 | heads = argv + i + 1; | |
290 | nr_heads = argc - i - 1; | |
291 | break; | |
292 | } | |
293 | if (!dest) | |
294 | usage(fetch_pack_usage); | |
295 | pid = git_connect(fd, dest, exec); | |
296 | if (pid < 0) | |
297 | return 1; | |
298 | ret = fetch_pack(fd, nr_heads, heads); | |
299 | close(fd[0]); | |
300 | close(fd[1]); | |
301 | finish_connect(pid); | |
302 | return ret; | |
303 | } |