From b5858a69e58a1092e9abdeba6883bbfee5518368 Mon Sep 17 00:00:00 2001 From: Matthias Friedrich <1573457+matzefriedrich@users.noreply.github.com> Date: Sat, 1 Jun 2024 01:27:16 +0200 Subject: [PATCH] Adds support for per-item FileOptions (#14) * Add support for setting per-item `FileOptions` (mapping) (#13) * Upgrades the zip dependency to version 0.6.6 * Updates the crate version * Adds a CHANGELOG file --------- Co-authored-by: Mahesh Bandara Wijerathna --- CHANGELOG.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++-- src/file_utils.rs | 2 +- src/read.rs | 6 +++--- src/write.rs | 49 +++++++++++++++++++++++++++----------------- 5 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9922373 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,52 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.7.0] - 2024-06-01 + +### Changed + +- [PR #13] Adds support for per-item file options by the `create_from_directory_with_options` method. This introduces a breaking change; instead of passing a `FileOptions` directly an `Fn` must be specified that is called for each file, and must return a `FileOptions` value. +- Upgraded the zip dependency to version 0.6.6. + + +## [0.6.2] - 2023-09-03 + +### Changed + +- [PR #10] Upgraded the zip dependency to version 0.6.2 + + +## [0.6.1] - 2021-07-30 + +### Fixed + +- [PR #6] Fixes formatting and linter warnings + + +## [0.6.0] - 2020-11-30 + +### Changed + +- [PR #4] Pass through Zip and IO errors (replaces all instances of `unwrap()`) +- [PR #4] Adds tests; extends the `try_is_zip` method so that it can detect different archive formats + + +## [0.5.0] - 2020-07-24 + +### Fixed + +- [PR #1] Fixes a bug in the `create_from_directory_with_options` method that could cause files not entirely written to disk; use `write_all` instead of `write`. + + +## [0.4.0] - 2020-03-25 + +### Added + +- New archive extraction traits `extract`, `extract_file`, and `extract_file_to_memory` +- New entry query traits `entry_path` and `file_number` +- New archive writer traits `create_from_directory` and `create_from_directory_with_options` +- Helper function that can perform all operations base on a given archive file path \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index cec254a..f2297d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zip-extensions" -version = "0.6.2" +version = "0.7.0" authors = ["Matthias Friedrich "] edition = "2021" description = "An extension crate for zip." @@ -15,4 +15,4 @@ exclude = [ ] [dependencies] -zip = "0.6.2" +zip = "0.6.6" diff --git a/src/file_utils.rs b/src/file_utils.rs index 43eeea0..b284df8 100644 --- a/src/file_utils.rs +++ b/src/file_utils.rs @@ -39,7 +39,7 @@ pub(crate) fn make_relative_path(root: &PathBuf, current: &PathBuf) -> PathBuf { pub(crate) fn path_as_string(path: &std::path::Path) -> String { let mut path_str = String::new(); for component in path.components() { - if let std::path::Component::Normal(os_str) = component { + if let Component::Normal(os_str) = component { if !path_str.is_empty() { path_str.push('/'); } diff --git a/src/read.rs b/src/read.rs index b10a148..402db1e 100644 --- a/src/read.rs +++ b/src/read.rs @@ -10,7 +10,7 @@ use zip::ZipArchive; /// Extracts a ZIP file to the given directory. pub fn zip_extract(archive_file: &PathBuf, target_dir: &PathBuf) -> ZipResult<()> { let file = File::open(archive_file)?; - let mut archive = zip::ZipArchive::new(file)?; + let mut archive = ZipArchive::new(file)?; archive.extract(target_dir) } @@ -22,7 +22,7 @@ pub fn zip_extract_file( overwrite: bool, ) -> ZipResult<()> { let file = File::open(archive_file)?; - let mut archive = zip::ZipArchive::new(file)?; + let mut archive = ZipArchive::new(file)?; let file_number: usize = match archive.file_number(entry_path) { Some(index) => index, None => return Err(ZipError::FileNotFound), @@ -38,7 +38,7 @@ pub fn zip_extract_file_to_memory( buffer: &mut Vec, ) -> ZipResult<()> { let file = File::open(archive_file)?; - let mut archive = zip::ZipArchive::new(file)?; + let mut archive = ZipArchive::new(file)?; let file_number: usize = match archive.file_number(entry_path) { Some(index) => index, None => return Err(ZipError::FileNotFound), diff --git a/src/write.rs b/src/write.rs index a43af2e..313d9ca 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1,27 +1,32 @@ -use crate::file_utils::{make_relative_path, path_as_string}; use std::fs::File; use std::io; use std::io::{Read, Write}; use std::path::PathBuf; + +use zip::{CompressionMethod, ZipWriter}; use zip::result::ZipResult; use zip::write::FileOptions; -use zip::{write, CompressionMethod, ZipWriter}; + +use crate::file_utils::{make_relative_path, path_as_string}; /// Creates a zip archive that contains the files and directories from the specified directory. pub fn zip_create_from_directory(archive_file: &PathBuf, directory: &PathBuf) -> ZipResult<()> { - let options = write::FileOptions::default().compression_method(CompressionMethod::Stored); - zip_create_from_directory_with_options(archive_file, directory, options) + let options = FileOptions::default().compression_method(CompressionMethod::Stored); + zip_create_from_directory_with_options(archive_file, directory, |_| options) } /// Creates a zip archive that contains the files and directories from the specified directory, uses the specified compression level. -pub fn zip_create_from_directory_with_options( +pub fn zip_create_from_directory_with_options( archive_file: &PathBuf, directory: &PathBuf, - options: FileOptions, -) -> ZipResult<()> { + options_map: F, +) -> ZipResult<()> +where + F: Fn(&PathBuf) -> FileOptions, +{ let file = File::create(archive_file)?; - let mut zip_writer = zip::ZipWriter::new(file); - zip_writer.create_from_directory_with_options(directory, options) + let mut zip_writer = ZipWriter::new(file); + zip_writer.create_from_directory_with_options(directory, options_map) } pub trait ZipWriterExtensions { @@ -29,24 +34,29 @@ pub trait ZipWriterExtensions { fn create_from_directory(&mut self, directory: &PathBuf) -> ZipResult<()>; /// Creates a zip archive that contains the files and directories from the specified directory, uses the specified compression level. - fn create_from_directory_with_options( + fn create_from_directory_with_options( &mut self, directory: &PathBuf, - options: FileOptions, - ) -> ZipResult<()>; + options_map: F, + ) -> ZipResult<()> + where + F: Fn(&PathBuf) -> FileOptions; } impl ZipWriterExtensions for ZipWriter { fn create_from_directory(&mut self, directory: &PathBuf) -> ZipResult<()> { - let options = write::FileOptions::default().compression_method(CompressionMethod::Stored); - self.create_from_directory_with_options(directory, options) + let options = FileOptions::default().compression_method(CompressionMethod::Stored); + self.create_from_directory_with_options(directory, |_| options) } - fn create_from_directory_with_options( + fn create_from_directory_with_options( &mut self, directory: &PathBuf, - options: FileOptions, - ) -> ZipResult<()> { + options_map: F, + ) -> ZipResult<()> + where + F: Fn(&PathBuf) -> FileOptions, + { let mut paths_queue: Vec = vec![]; paths_queue.push(directory.clone()); @@ -57,17 +67,18 @@ impl ZipWriterExtensions for ZipWriter { for entry in directory_entry_iterator { let entry_path = entry?.path(); + let file_options = options_map(&entry_path); let entry_metadata = std::fs::metadata(entry_path.clone())?; if entry_metadata.is_file() { let mut f = File::open(&entry_path)?; f.read_to_end(&mut buffer)?; let relative_path = make_relative_path(&directory, &entry_path); - self.start_file(path_as_string(&relative_path), options)?; + self.start_file(path_as_string(&relative_path), file_options)?; self.write_all(buffer.as_ref())?; buffer.clear(); } else if entry_metadata.is_dir() { let relative_path = make_relative_path(&directory, &entry_path); - self.add_directory(path_as_string(&relative_path), options)?; + self.add_directory(path_as_string(&relative_path), file_options)?; paths_queue.push(entry_path.clone()); } }