]>
Commit | Line | Data |
---|---|---|
4df096a5 FBH |
1 | /* |
2 | * Copyright (c) 2006 Franck Bui-Huu | |
3 | * Copyright (c) 2006 Rene Scharfe | |
4 | */ | |
4df096a5 FBH |
5 | #include "cache.h" |
6 | #include "builtin.h" | |
7 | #include "archive.h" | |
8 | #include "commit.h" | |
9 | #include "tree-walk.h" | |
10 | #include "exec_cmd.h" | |
11 | #include "pkt-line.h" | |
23d6d112 | 12 | #include "sideband.h" |
8460b2fc | 13 | #include "attr.h" |
4df096a5 FBH |
14 | |
15 | static const char archive_usage[] = \ | |
e0ffb248 | 16 | "git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]"; |
4df096a5 | 17 | |
34533004 | 18 | const struct archiver archivers[] = { |
6c2f207b SP |
19 | { "tar", write_tar_archive, NULL }, |
20 | { "zip", write_zip_archive, parse_extra_zip_args }, | |
4df096a5 FBH |
21 | }; |
22 | ||
37f94436 | 23 | static int run_remote_archiver(const char *remote, int argc, |
4df096a5 FBH |
24 | const char **argv) |
25 | { | |
23d6d112 | 26 | char *url, buf[LARGE_PACKET_MAX]; |
4df096a5 | 27 | int fd[2], i, len, rv; |
98158e9c | 28 | struct child_process *conn; |
fe5ab763 JH |
29 | const char *exec = "git-upload-archive"; |
30 | int exec_at = 0; | |
4df096a5 | 31 | |
fe5ab763 JH |
32 | for (i = 1; i < argc; i++) { |
33 | const char *arg = argv[i]; | |
599065a3 | 34 | if (!prefixcmp(arg, "--exec=")) { |
fe5ab763 JH |
35 | if (exec_at) |
36 | die("multiple --exec specified"); | |
37 | exec = arg + 7; | |
38 | exec_at = i; | |
39 | break; | |
40 | } | |
41 | } | |
4df096a5 | 42 | |
37f94436 | 43 | url = xstrdup(remote); |
98158e9c | 44 | conn = git_connect(fd, url, exec, 0); |
4df096a5 | 45 | |
fe5ab763 JH |
46 | for (i = 1; i < argc; i++) { |
47 | if (i == exec_at) | |
48 | continue; | |
4df096a5 | 49 | packet_write(fd[1], "argument %s\n", argv[i]); |
fe5ab763 | 50 | } |
4df096a5 FBH |
51 | packet_flush(fd[1]); |
52 | ||
53 | len = packet_read_line(fd[0], buf, sizeof(buf)); | |
54 | if (!len) | |
55 | die("git-archive: expected ACK/NAK, got EOF"); | |
56 | if (buf[len-1] == '\n') | |
57 | buf[--len] = 0; | |
58 | if (strcmp(buf, "ACK")) { | |
cc44c765 | 59 | if (len > 5 && !prefixcmp(buf, "NACK ")) |
4df096a5 FBH |
60 | die("git-archive: NACK %s", buf + 5); |
61 | die("git-archive: protocol error"); | |
62 | } | |
63 | ||
64 | len = packet_read_line(fd[0], buf, sizeof(buf)); | |
65 | if (len) | |
66 | die("git-archive: expected a flush"); | |
67 | ||
68 | /* Now, start reading from fd[0] and spit it out to stdout */ | |
9ac13ec9 | 69 | rv = recv_sideband("archive", fd[0], 1, 2); |
4df096a5 | 70 | close(fd[0]); |
ec587fde | 71 | close(fd[1]); |
98158e9c | 72 | rv |= finish_connect(conn); |
4df096a5 FBH |
73 | |
74 | return !!rv; | |
75 | } | |
76 | ||
34533004 | 77 | static const struct archiver *lookup_archiver(const char *name) |
4df096a5 | 78 | { |
34533004 | 79 | int i; |
4df096a5 FBH |
80 | |
81 | for (i = 0; i < ARRAY_SIZE(archivers); i++) { | |
34533004 RS |
82 | if (!strcmp(name, archivers[i].name)) |
83 | return &archivers[i]; | |
4df096a5 | 84 | } |
34533004 | 85 | return NULL; |
4df096a5 FBH |
86 | } |
87 | ||
88 | void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args) | |
89 | { | |
90 | ar_args->pathspec = get_pathspec(ar_args->base, pathspec); | |
91 | } | |
92 | ||
93 | void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, | |
94 | const char *prefix) | |
95 | { | |
96 | const char *name = argv[0]; | |
97 | const unsigned char *commit_sha1; | |
98 | time_t archive_time; | |
99 | struct tree *tree; | |
8460b2fc | 100 | const struct commit *commit; |
4df096a5 FBH |
101 | unsigned char sha1[20]; |
102 | ||
103 | if (get_sha1(name, sha1)) | |
104 | die("Not a valid object name"); | |
105 | ||
106 | commit = lookup_commit_reference_gently(sha1, 1); | |
107 | if (commit) { | |
108 | commit_sha1 = commit->object.sha1; | |
109 | archive_time = commit->date; | |
110 | } else { | |
111 | commit_sha1 = NULL; | |
112 | archive_time = time(NULL); | |
113 | } | |
114 | ||
115 | tree = parse_tree_indirect(sha1); | |
116 | if (tree == NULL) | |
117 | die("not a tree object"); | |
118 | ||
119 | if (prefix) { | |
120 | unsigned char tree_sha1[20]; | |
121 | unsigned int mode; | |
122 | int err; | |
123 | ||
124 | err = get_tree_entry(tree->object.sha1, prefix, | |
125 | tree_sha1, &mode); | |
126 | if (err || !S_ISDIR(mode)) | |
127 | die("current working directory is untracked"); | |
128 | ||
4df096a5 FBH |
129 | tree = parse_tree_indirect(tree_sha1); |
130 | } | |
131 | ar_args->tree = tree; | |
132 | ar_args->commit_sha1 = commit_sha1; | |
8460b2fc | 133 | ar_args->commit = commit; |
4df096a5 FBH |
134 | ar_args->time = archive_time; |
135 | } | |
136 | ||
34533004 RS |
137 | int parse_archive_args(int argc, const char **argv, const struct archiver **ar, |
138 | struct archiver_args *args) | |
4df096a5 FBH |
139 | { |
140 | const char *extra_argv[MAX_EXTRA_ARGS]; | |
141 | int extra_argc = 0; | |
8ff21b1a | 142 | const char *format = "tar"; |
4df096a5 | 143 | const char *base = ""; |
e0ffb248 | 144 | int verbose = 0; |
4df096a5 FBH |
145 | int i; |
146 | ||
147 | for (i = 1; i < argc; i++) { | |
148 | const char *arg = argv[i]; | |
149 | ||
150 | if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) { | |
37f94436 JH |
151 | for (i = 0; i < ARRAY_SIZE(archivers); i++) |
152 | printf("%s\n", archivers[i].name); | |
153 | exit(0); | |
4df096a5 | 154 | } |
e0ffb248 JH |
155 | if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { |
156 | verbose = 1; | |
157 | continue; | |
158 | } | |
cc44c765 | 159 | if (!prefixcmp(arg, "--format=")) { |
4df096a5 FBH |
160 | format = arg + 9; |
161 | continue; | |
162 | } | |
cc44c765 | 163 | if (!prefixcmp(arg, "--prefix=")) { |
4df096a5 FBH |
164 | base = arg + 9; |
165 | continue; | |
166 | } | |
4df096a5 FBH |
167 | if (!strcmp(arg, "--")) { |
168 | i++; | |
169 | break; | |
170 | } | |
171 | if (arg[0] == '-') { | |
172 | if (extra_argc > MAX_EXTRA_ARGS - 1) | |
173 | die("Too many extra options"); | |
174 | extra_argv[extra_argc++] = arg; | |
175 | continue; | |
176 | } | |
177 | break; | |
178 | } | |
179 | ||
37f94436 JH |
180 | /* We need at least one parameter -- tree-ish */ |
181 | if (argc - 1 < i) | |
4df096a5 | 182 | usage(archive_usage); |
34533004 RS |
183 | *ar = lookup_archiver(format); |
184 | if (!*ar) | |
4df096a5 FBH |
185 | die("Unknown archive format '%s'", format); |
186 | ||
37f94436 | 187 | if (extra_argc) { |
34533004 | 188 | if (!(*ar)->parse_extra) |
2232c0c6 | 189 | die("'%s' format does not handle %s", |
34533004 RS |
190 | (*ar)->name, extra_argv[0]); |
191 | args->extra = (*ar)->parse_extra(extra_argc, extra_argv); | |
4df096a5 | 192 | } |
34533004 RS |
193 | args->verbose = verbose; |
194 | args->base = base; | |
d53fe818 | 195 | args->baselen = strlen(base); |
4df096a5 FBH |
196 | |
197 | return i; | |
198 | } | |
199 | ||
d751864c | 200 | static const char *extract_remote_arg(int *ac, const char **av) |
37f94436 JH |
201 | { |
202 | int ix, iy, cnt = *ac; | |
203 | int no_more_options = 0; | |
204 | const char *remote = NULL; | |
205 | ||
206 | for (ix = iy = 1; ix < cnt; ix++) { | |
207 | const char *arg = av[ix]; | |
208 | if (!strcmp(arg, "--")) | |
209 | no_more_options = 1; | |
210 | if (!no_more_options) { | |
cc44c765 | 211 | if (!prefixcmp(arg, "--remote=")) { |
37f94436 JH |
212 | if (remote) |
213 | die("Multiple --remote specified"); | |
214 | remote = arg + 9; | |
215 | continue; | |
216 | } | |
217 | if (arg[0] != '-') | |
218 | no_more_options = 1; | |
219 | } | |
220 | if (ix != iy) | |
221 | av[iy] = arg; | |
222 | iy++; | |
223 | } | |
224 | if (remote) { | |
225 | av[--cnt] = NULL; | |
226 | *ac = cnt; | |
227 | } | |
228 | return remote; | |
229 | } | |
230 | ||
4df096a5 FBH |
231 | int cmd_archive(int argc, const char **argv, const char *prefix) |
232 | { | |
34533004 RS |
233 | const struct archiver *ar = NULL; |
234 | struct archiver_args args; | |
4df096a5 | 235 | int tree_idx; |
37f94436 | 236 | const char *remote = NULL; |
4df096a5 | 237 | |
d751864c | 238 | remote = extract_remote_arg(&argc, argv); |
37f94436 JH |
239 | if (remote) |
240 | return run_remote_archiver(remote, argc, argv); | |
4df096a5 | 241 | |
aa909861 | 242 | setvbuf(stderr, NULL, _IOLBF, BUFSIZ); |
8142f603 | 243 | |
34533004 | 244 | tree_idx = parse_archive_args(argc, argv, &ar, &args); |
265d5280 RS |
245 | if (prefix == NULL) |
246 | prefix = setup_git_directory(); | |
4df096a5 FBH |
247 | |
248 | argv += tree_idx; | |
34533004 RS |
249 | parse_treeish_arg(argv, &args, prefix); |
250 | parse_pathspec_arg(argv + 1, &args); | |
4df096a5 | 251 | |
34533004 | 252 | return ar->write_archive(&args); |
4df096a5 | 253 | } |