Skip to content

Commit

Permalink
Adds support for per-item FileOptions (#14)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
matzefriedrich and m4heshd authored May 31, 2024
1 parent e9c1ea6 commit b5858a6
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 25 deletions.
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "zip-extensions"
version = "0.6.2"
version = "0.7.0"
authors = ["Matthias Friedrich <[email protected]>"]
edition = "2021"
description = "An extension crate for zip."
Expand All @@ -15,4 +15,4 @@ exclude = [
]

[dependencies]
zip = "0.6.2"
zip = "0.6.6"
2 changes: 1 addition & 1 deletion src/file_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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('/');
}
Expand Down
6 changes: 3 additions & 3 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand All @@ -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),
Expand All @@ -38,7 +38,7 @@ pub fn zip_extract_file_to_memory(
buffer: &mut Vec<u8>,
) -> 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),
Expand Down
49 changes: 30 additions & 19 deletions src/write.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,62 @@
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<F>(
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 {
/// Creates a zip archive that contains the files and directories from the specified directory.
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<F>(
&mut self,
directory: &PathBuf,
options: FileOptions,
) -> ZipResult<()>;
options_map: F,
) -> ZipResult<()>
where
F: Fn(&PathBuf) -> FileOptions;
}

impl<W: Write + io::Seek> ZipWriterExtensions for ZipWriter<W> {
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<F>(
&mut self,
directory: &PathBuf,
options: FileOptions,
) -> ZipResult<()> {
options_map: F,
) -> ZipResult<()>
where
F: Fn(&PathBuf) -> FileOptions,
{
let mut paths_queue: Vec<PathBuf> = vec![];
paths_queue.push(directory.clone());

Expand All @@ -57,17 +67,18 @@ impl<W: Write + io::Seek> ZipWriterExtensions for ZipWriter<W> {

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());
}
}
Expand Down

0 comments on commit b5858a6

Please sign in to comment.