]>
Commit | Line | Data |
---|---|---|
def88e9a | 1 | #include "cache.h" |
fb9040cc | 2 | #include "refs.h" |
def88e9a | 3 | #include "pkt-line.h" |
75bfc6c2 | 4 | #include <sys/wait.h> |
def88e9a | 5 | |
8b3d9dc0 | 6 | static int quiet; |
33b83034 JH |
7 | static int verbose; |
8 | static const char fetch_pack_usage[] = | |
9 | "git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>..."; | |
def88e9a LT |
10 | static const char *exec = "git-upload-pack"; |
11 | ||
33b83034 JH |
12 | static int find_common(int fd[2], unsigned char *result_sha1, |
13 | struct ref *refs) | |
def88e9a LT |
14 | { |
15 | static char line[1000]; | |
75bfc6c2 LT |
16 | int count = 0, flushes = 0, retval; |
17 | FILE *revs; | |
def88e9a | 18 | |
75bfc6c2 LT |
19 | revs = popen("git-rev-list $(git-rev-parse --all)", "r"); |
20 | if (!revs) | |
21 | die("unable to run 'git-rev-list'"); | |
33b83034 JH |
22 | |
23 | while (refs) { | |
24 | unsigned char *remote = refs->old_sha1; | |
25 | if (verbose) | |
26 | fprintf(stderr, | |
27 | "want %s (%s)\n", sha1_to_hex(remote), | |
28 | refs->name); | |
29 | packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); | |
30 | refs = refs->next; | |
31 | } | |
fb9040cc | 32 | packet_flush(fd[1]); |
75bfc6c2 LT |
33 | flushes = 1; |
34 | retval = -1; | |
35 | while (fgets(line, sizeof(line), revs) != NULL) { | |
def88e9a LT |
36 | unsigned char sha1[20]; |
37 | if (get_sha1_hex(line, sha1)) | |
38 | die("git-fetch-pack: expected object name, got crud"); | |
39 | packet_write(fd[1], "have %s\n", sha1_to_hex(sha1)); | |
33b83034 JH |
40 | if (verbose) |
41 | fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); | |
def88e9a LT |
42 | if (!(31 & ++count)) { |
43 | packet_flush(fd[1]); | |
44 | flushes++; | |
45 | ||
46 | /* | |
47 | * We keep one window "ahead" of the other side, and | |
48 | * will wait for an ACK only on the next one | |
49 | */ | |
50 | if (count == 32) | |
51 | continue; | |
75bfc6c2 LT |
52 | if (get_ack(fd[0], result_sha1)) { |
53 | flushes = 0; | |
54 | retval = 0; | |
33b83034 JH |
55 | if (verbose) |
56 | fprintf(stderr, "got ack\n"); | |
75bfc6c2 LT |
57 | break; |
58 | } | |
def88e9a LT |
59 | flushes--; |
60 | } | |
61 | } | |
75bfc6c2 LT |
62 | pclose(revs); |
63 | packet_write(fd[1], "done\n"); | |
33b83034 JH |
64 | if (verbose) |
65 | fprintf(stderr, "done\n"); | |
def88e9a LT |
66 | while (flushes) { |
67 | flushes--; | |
33b83034 JH |
68 | if (get_ack(fd[0], result_sha1)) { |
69 | if (verbose) | |
70 | fprintf(stderr, "got ack\n"); | |
def88e9a | 71 | return 0; |
33b83034 | 72 | } |
def88e9a | 73 | } |
75bfc6c2 | 74 | return retval; |
def88e9a LT |
75 | } |
76 | ||
def88e9a LT |
77 | static int fetch_pack(int fd[2], int nr_match, char **match) |
78 | { | |
d1c133f5 LT |
79 | struct ref *ref; |
80 | unsigned char sha1[20]; | |
81 | int status; | |
75bfc6c2 | 82 | pid_t pid; |
def88e9a | 83 | |
d1c133f5 LT |
84 | get_remote_heads(fd[0], &ref, nr_match, match); |
85 | if (!ref) { | |
86 | packet_flush(fd[1]); | |
87 | die("no matching remote head"); | |
88 | } | |
33b83034 JH |
89 | if (find_common(fd, sha1, ref) < 0) |
90 | fprintf(stderr, "warning: no common commits\n"); | |
75bfc6c2 LT |
91 | pid = fork(); |
92 | if (pid < 0) | |
93 | die("git-fetch-pack: unable to fork off git-unpack-objects"); | |
94 | if (!pid) { | |
75bfc6c2 LT |
95 | dup2(fd[0], 0); |
96 | close(fd[0]); | |
85c414b5 | 97 | close(fd[1]); |
8b3d9dc0 JH |
98 | execlp("git-unpack-objects", "git-unpack-objects", |
99 | quiet ? "-q" : NULL, NULL); | |
75bfc6c2 LT |
100 | die("git-unpack-objects exec failed"); |
101 | } | |
fb9040cc | 102 | close(fd[0]); |
75bfc6c2 LT |
103 | close(fd[1]); |
104 | while (waitpid(pid, &status, 0) < 0) { | |
105 | if (errno != EINTR) | |
106 | die("waiting for git-unpack-objects: %s", strerror(errno)); | |
107 | } | |
108 | if (WIFEXITED(status)) { | |
109 | int code = WEXITSTATUS(status); | |
110 | if (code) | |
111 | die("git-unpack-objects died with error code %d", code); | |
33b83034 JH |
112 | while (ref) { |
113 | printf("%s %s\n", | |
114 | sha1_to_hex(ref->old_sha1), ref->name); | |
115 | ref = ref->next; | |
116 | } | |
75bfc6c2 LT |
117 | return 0; |
118 | } | |
119 | if (WIFSIGNALED(status)) { | |
120 | int sig = WTERMSIG(status); | |
121 | die("git-unpack-objects died of signal %d", sig); | |
122 | } | |
123 | die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status); | |
def88e9a LT |
124 | } |
125 | ||
126 | int main(int argc, char **argv) | |
127 | { | |
128 | int i, ret, nr_heads; | |
129 | char *dest = NULL, **heads; | |
130 | int fd[2]; | |
131 | pid_t pid; | |
132 | ||
133 | nr_heads = 0; | |
134 | heads = NULL; | |
135 | for (i = 1; i < argc; i++) { | |
136 | char *arg = argv[i]; | |
137 | ||
138 | if (*arg == '-') { | |
8b3d9dc0 JH |
139 | if (!strncmp("--exec=", arg, 7)) { |
140 | exec = arg + 7; | |
141 | continue; | |
142 | } | |
33b83034 JH |
143 | if (!strcmp("-q", arg)) { |
144 | quiet = 1; | |
145 | continue; | |
146 | } | |
147 | if (!strcmp("-v", arg)) { | |
148 | verbose = 1; | |
149 | continue; | |
150 | } | |
def88e9a LT |
151 | usage(fetch_pack_usage); |
152 | } | |
153 | dest = arg; | |
154 | heads = argv + i + 1; | |
155 | nr_heads = argc - i - 1; | |
156 | break; | |
157 | } | |
158 | if (!dest) | |
159 | usage(fetch_pack_usage); | |
160 | pid = git_connect(fd, dest, exec); | |
161 | if (pid < 0) | |
162 | return 1; | |
163 | ret = fetch_pack(fd, nr_heads, heads); | |
164 | close(fd[0]); | |
165 | close(fd[1]); | |
166 | finish_connect(pid); | |
167 | return ret; | |
168 | } |