zip_extensions/
write.rs

1use std::fs::File;
2use std::io;
3use std::io::Write;
4use std::path::PathBuf;
5
6use crate::default_entry_handler::DefaultEntryHandler;
7use crate::entry_handler::EntryHandler;
8use zip::result::ZipResult;
9use zip::write::{FileOptionExtension, FileOptions, SimpleFileOptions};
10use zip::{CompressionMethod, ZipWriter};
11
12/// Creates a zip archive that contains the files and directories from the specified directory.
13pub fn zip_create_from_directory(archive_file: &PathBuf, directory: &PathBuf) -> ZipResult<()> {
14    let options = SimpleFileOptions::default().compression_method(CompressionMethod::Stored);
15    zip_create_from_directory_with_options(archive_file, directory, |_| options)
16}
17
18/// Creates a zip archive that contains the files and directories from the specified directory.
19pub fn zip_create_from_directory_with_options<F, T>(
20    archive_file: &PathBuf,
21    directory: &PathBuf,
22    cb_file_options: F,
23) -> ZipResult<()>
24where
25    T: FileOptionExtension,
26    F: Fn(&PathBuf) -> FileOptions<T>,
27{
28    let file = File::create(archive_file)?;
29    let zip_writer = ZipWriter::new(file);
30    zip_writer.create_from_directory_with_options(directory, cb_file_options, &DefaultEntryHandler)
31}
32
33pub trait ZipWriterExtensions {
34    /// Creates a zip archive that contains the files and directories from the specified directory.
35    fn create_from_directory(self, directory: &PathBuf) -> ZipResult<()>;
36
37    /// Creates a zip archive that contains the files and directories from the specified directory, uses the specified compression level.
38    fn create_from_directory_with_options<F, T, H>(
39        self,
40        directory: &PathBuf,
41        cb_file_options: F,
42        handler: &H,
43    ) -> ZipResult<()>
44    where
45        T: FileOptionExtension,
46        F: Fn(&PathBuf) -> FileOptions<T>,
47        H: EntryHandler<T>;
48}
49
50impl<W: Write + io::Seek> ZipWriterExtensions for ZipWriter<W> {
51    fn create_from_directory(self, directory: &PathBuf) -> ZipResult<()> {
52        let options = SimpleFileOptions::default().compression_method(CompressionMethod::Stored);
53        self.create_from_directory_with_options(directory, |_| options, &DefaultEntryHandler)
54    }
55
56    fn create_from_directory_with_options<F, T, H>(
57        mut self,
58        directory: &PathBuf,
59        cb_file_options: F,
60        handler: &H,
61    ) -> ZipResult<()>
62    where
63        T: FileOptionExtension,
64        F: Fn(&PathBuf) -> FileOptions<T>,
65        H: EntryHandler<T>,
66    {
67        let mut paths_queue: Vec<PathBuf> = vec![];
68        paths_queue.push(directory.clone());
69
70        let mut buffer = Vec::new();
71
72        while let Some(next) = paths_queue.pop() {
73            let directory_entry_iterator = std::fs::read_dir(next)?;
74            for entry in directory_entry_iterator {
75                let entry_path = entry?.path();
76                let file_options = cb_file_options(&entry_path);
77                handler.handle_entry(
78                    &mut self,
79                    &directory,
80                    &entry_path,
81                    file_options,
82                    &mut buffer,
83                )?;
84                let entry_metadata = std::fs::metadata(entry_path.clone())?;
85                if entry_metadata.is_dir() {
86                    paths_queue.push(entry_path.clone());
87                }
88            }
89        }
90
91        self.finish()?;
92        Ok(())
93    }
94}