diff options
Diffstat (limited to 'third_party/rust/zip/examples/write_dir.rs')
-rw-r--r-- | third_party/rust/zip/examples/write_dir.rs | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/third_party/rust/zip/examples/write_dir.rs b/third_party/rust/zip/examples/write_dir.rs new file mode 100644 index 0000000000..3b043528f4 --- /dev/null +++ b/third_party/rust/zip/examples/write_dir.rs @@ -0,0 +1,125 @@ +use std::io::prelude::*; +use std::io::{Seek, Write}; +use std::iter::Iterator; +use zip::result::ZipError; +use zip::write::FileOptions; + +use std::fs::File; +use std::path::Path; +use walkdir::{DirEntry, WalkDir}; + +fn main() { + std::process::exit(real_main()); +} + +const METHOD_STORED: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Stored); + +#[cfg(any( + feature = "deflate", + feature = "deflate-miniz", + feature = "deflate-zlib" +))] +const METHOD_DEFLATED: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Deflated); +#[cfg(not(any( + feature = "deflate", + feature = "deflate-miniz", + feature = "deflate-zlib" +)))] +const METHOD_DEFLATED: Option<zip::CompressionMethod> = None; + +#[cfg(feature = "bzip2")] +const METHOD_BZIP2: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Bzip2); +#[cfg(not(feature = "bzip2"))] +const METHOD_BZIP2: Option<zip::CompressionMethod> = None; + +#[cfg(feature = "zstd")] +const METHOD_ZSTD: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Zstd); +#[cfg(not(feature = "zstd"))] +const METHOD_ZSTD: Option<zip::CompressionMethod> = None; + +fn real_main() -> i32 { + let args: Vec<_> = std::env::args().collect(); + if args.len() < 3 { + println!( + "Usage: {} <source_directory> <destination_zipfile>", + args[0] + ); + return 1; + } + + let src_dir = &*args[1]; + let dst_file = &*args[2]; + for &method in [METHOD_STORED, METHOD_DEFLATED, METHOD_BZIP2, METHOD_ZSTD].iter() { + if method.is_none() { + continue; + } + match doit(src_dir, dst_file, method.unwrap()) { + Ok(_) => println!("done: {src_dir} written to {dst_file}"), + Err(e) => println!("Error: {e:?}"), + } + } + + 0 +} + +fn zip_dir<T>( + it: &mut dyn Iterator<Item = DirEntry>, + prefix: &str, + writer: T, + method: zip::CompressionMethod, +) -> zip::result::ZipResult<()> +where + T: Write + Seek, +{ + let mut zip = zip::ZipWriter::new(writer); + let options = FileOptions::default() + .compression_method(method) + .unix_permissions(0o755); + + let mut buffer = Vec::new(); + for entry in it { + let path = entry.path(); + let name = path.strip_prefix(Path::new(prefix)).unwrap(); + + // Write file or directory explicitly + // Some unzip tools unzip files with directory paths correctly, some do not! + if path.is_file() { + println!("adding file {path:?} as {name:?} ..."); + #[allow(deprecated)] + zip.start_file_from_path(name, options)?; + let mut f = File::open(path)?; + + f.read_to_end(&mut buffer)?; + zip.write_all(&buffer)?; + buffer.clear(); + } else if !name.as_os_str().is_empty() { + // Only if not root! Avoids path spec / warning + // and mapname conversion failed error on unzip + println!("adding dir {path:?} as {name:?} ..."); + #[allow(deprecated)] + zip.add_directory_from_path(name, options)?; + } + } + zip.finish()?; + Result::Ok(()) +} + +fn doit( + src_dir: &str, + dst_file: &str, + method: zip::CompressionMethod, +) -> zip::result::ZipResult<()> { + if !Path::new(src_dir).is_dir() { + return Err(ZipError::FileNotFound); + } + + let path = Path::new(dst_file); + let file = File::create(path).unwrap(); + + let walkdir = WalkDir::new(src_dir); + let it = walkdir.into_iter(); + + zip_dir(&mut it.filter_map(|e| e.ok()), src_dir, file, method)?; + + Ok(()) +} |