use std::{fs, io::prelude::*, path::Path};
use anyhow::{Context, Result};
use log::debug;
use walkdir::WalkDir;
use zip::{ZipWriter, write::SimpleFileOptions};
pub(crate) fn zip_dir(src: &Path, dest: &Path, prefix: &str) -> Result<()> {
let file = fs::File::create(dest)?;
let walkdir = WalkDir::new(src);
let mut zip = ZipWriter::new(file);
let options = SimpleFileOptions::default().unix_permissions(0o755);
let mut buffer = Vec::new();
for entry in walkdir.into_iter().filter_map(|e| e.ok()) {
let path =
fs::canonicalize(entry.path()).with_context(|| format!("Failed to canonicalize path: {:?}", entry.path()))?;
let name = path.strip_prefix(prefix).unwrap_or(path.as_path());
let os_name = match name.as_os_str().to_str() {
Some(s) => s,
None => {
debug!("{} did not convert to os_str", name.display());
continue;
}
};
if path.is_file() {
debug!("Zipping {:?} ...", os_name);
zip.start_file(os_name, options)?;
let mut f = fs::File::open(path)?;
f.read_to_end(&mut buffer)?;
zip.write_all(&buffer)?;
buffer.clear();
} else if !os_name.is_empty() {
zip.add_directory(os_name, options)?;
}
}
zip.finish()?;
Result::Ok(())
}