blob: fbc4938e2a9d8ce384f79df8243389eb0101303f [file] [log] [blame]
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;
const USAGE: &str = r#"usage: dir_zipper <zipper> <output> <root-dir> [<file>...]
Creates a zip archive, stripping a directory prefix from each file name.
Args:
zipper: Path to @bazel_tools//tools/zip:zipper.
output: Path to zip file to create: e.g., "/tmp/out.zip".
root_dir: Directory to strip from each archive name, with no trailing
slash: e.g., "/tmp/myfiles".
files: List of files to include in the archive, all under `root_dir`:
e.g., ["/tmp/myfiles/a", "/tmp/myfiles/b/c"].
Example:
dir_zipper \
bazel-rules_rust/external/bazel_tools/tools/zip/zipper/zipper \
/tmp/out.zip \
/tmp/myfiles \
/tmp/myfiles/a /tmp/myfiles/b/c
This will create /tmp/out.zip with file entries "a" and "b/c".
"#;
macro_rules! die {
($($arg:tt)*) => {
{
eprintln!($($arg)*);
std::process::exit(1);
}
};
}
fn main() {
let mut args = std::env::args_os().skip(1);
let (zipper, output, root_dir) = match args.next().zip(args.next()).zip(args.next()) {
Some(((zipper, output), root_dir)) => (
PathBuf::from(zipper),
PathBuf::from(output),
PathBuf::from(root_dir),
),
_ => {
die!("{}", USAGE);
}
};
let files = args.map(PathBuf::from).collect::<Vec<_>>();
let mut comm = Command::new(zipper);
comm.arg("c"); // create, but don't compress
comm.arg(output);
for f in files {
let rel = f.strip_prefix(&root_dir).unwrap_or_else(|_e| {
die!(
"fatal: non-descendant: {} not under {}",
f.display(),
root_dir.display()
);
});
let mut spec = OsString::new();
spec.push(rel);
spec.push("=");
spec.push(f);
comm.arg(spec);
}
let exit_status = comm
.spawn()
.unwrap_or_else(|e| die!("fatal: could not spawn zipper: {}", e))
.wait()
.unwrap_or_else(|e| die!("fatal: could not wait on zipper: {}", e));
if !exit_status.success() {
match exit_status.code() {
Some(c) => std::process::exit(c),
None => die!("fatal: zipper terminated by signal"),
}
}
}