1 use std::ffi::OsString;
2 use std::path::PathBuf;
3 use std::process::Command;
4
5 const USAGE: &str = r#"usage: dir_zipper <zipper> <output> <root-dir> [<file>...]
6
7 Creates a zip archive, stripping a directory prefix from each file name.
8
9 Args:
10 zipper: Path to @bazel_tools//tools/zip:zipper.
11 output: Path to zip file to create: e.g., "/tmp/out.zip".
12 root_dir: Directory to strip from each archive name, with no trailing
13 slash: e.g., "/tmp/myfiles".
14 files: List of files to include in the archive, all under `root_dir`:
15 e.g., ["/tmp/myfiles/a", "/tmp/myfiles/b/c"].
16
17 Example:
18 dir_zipper \
19 bazel-rules_rust/external/bazel_tools/tools/zip/zipper/zipper \
20 /tmp/out.zip \
21 /tmp/myfiles \
22 /tmp/myfiles/a /tmp/myfiles/b/c
23
24 This will create /tmp/out.zip with file entries "a" and "b/c".
25 "#;
26
27 macro_rules! die {
28 ($($arg:tt)*) => {
29 {
30 eprintln!($($arg)*);
31 std::process::exit(1);
32 }
33 };
34 }
35
main()36 fn main() {
37 let mut args = std::env::args_os().skip(1);
38 let (zipper, output, root_dir) = match args.next().zip(args.next()).zip(args.next()) {
39 Some(((zipper, output), root_dir)) => (
40 PathBuf::from(zipper),
41 PathBuf::from(output),
42 PathBuf::from(root_dir),
43 ),
44 _ => {
45 die!("{}", USAGE);
46 }
47 };
48 let files = args.map(PathBuf::from).collect::<Vec<_>>();
49 let mut comm = Command::new(zipper);
50 comm.arg("c"); // create, but don't compress
51 comm.arg(output);
52 for f in files {
53 let rel = f.strip_prefix(&root_dir).unwrap_or_else(|_e| {
54 die!(
55 "fatal: non-descendant: {} not under {}",
56 f.display(),
57 root_dir.display()
58 );
59 });
60 let mut spec = OsString::new();
61 spec.push(rel);
62 spec.push("=");
63 spec.push(f);
64 comm.arg(spec);
65 }
66 let exit_status = comm
67 .spawn()
68 .unwrap_or_else(|e| die!("fatal: could not spawn zipper: {}", e))
69 .wait()
70 .unwrap_or_else(|e| die!("fatal: could not wait on zipper: {}", e));
71 if !exit_status.success() {
72 match exit_status.code() {
73 Some(c) => std::process::exit(c),
74 None => die!("fatal: zipper terminated by signal"),
75 }
76 }
77 }
78