Skip to main content

teaql_tool_extra/
archive.rs

1use teaql_tool_core::{Result, TeaQLToolError};
2use std::fs::File;
3use zip::write::SimpleFileOptions;
4
5#[derive(Debug, Clone)]
6pub struct ArchiveTool;
7
8impl ArchiveTool {
9    pub fn new() -> Self { Self }
10
11    pub fn zip_dir(&self, src_dir: &str, dst_file: &str) -> Result<()> {
12        let file = File::create(dst_file).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
13        let mut zip = zip::ZipWriter::new(file);
14        let options = SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated);
15        
16        let walkdir = walkdir::WalkDir::new(src_dir);
17        let it = walkdir.into_iter();
18        
19        for entry in it.filter_map(|e| e.ok()) {
20            let path = entry.path();
21            let name = path.strip_prefix(std::path::Path::new(src_dir)).unwrap();
22            let name_str = name.to_str().unwrap().replace("\\", "/");
23            
24            if path.is_file() {
25                zip.start_file(name_str, options).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
26                let mut f = File::open(path).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
27                std::io::copy(&mut f, &mut zip).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
28            } else if !name.as_os_str().is_empty() {
29                zip.add_directory(name_str, options).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
30            }
31        }
32        zip.finish().map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
33        Ok(())
34    }
35
36    pub fn unzip(&self, src_file: &str, dst_dir: &str) -> Result<()> {
37        let file = File::open(src_file).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
38        let mut archive = zip::ZipArchive::new(file).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
39        
40        for i in 0..archive.len() {
41            let mut file = archive.by_index(i).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
42            let outpath = match file.enclosed_name() {
43                Some(path) => std::path::Path::new(dst_dir).join(path),
44                None => continue,
45            };
46            
47            if (*file.name()).ends_with('/') {
48                std::fs::create_dir_all(&outpath).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
49            } else {
50                if let Some(p) = outpath.parent() {
51                    if !p.exists() {
52                        std::fs::create_dir_all(&p).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
53                    }
54                }
55                let mut outfile = File::create(&outpath).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
56                std::io::copy(&mut file, &mut outfile).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
57            }
58        }
59        Ok(())
60    }
61}
62
63impl Default for ArchiveTool {
64    fn default() -> Self { Self::new() }
65}