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