teaql-tool-extra 0.1.0

Heavy-dependency extra utilities for the TeaQL Tool ecosystem.
Documentation
use teaql_tool_core::{Result, TeaQLToolError};
use std::fs::File;
use zip::write::SimpleFileOptions;

#[derive(Debug, Clone)]
pub struct ArchiveTool;

impl ArchiveTool {
    pub fn new() -> Self { Self }

    pub fn zip_dir(&self, src_dir: &str, dst_file: &str) -> Result<()> {
        let file = File::create(dst_file).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
        let mut zip = zip::ZipWriter::new(file);
        let options = SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated);
        
        let walkdir = walkdir::WalkDir::new(src_dir);
        let it = walkdir.into_iter();
        
        for entry in it.filter_map(|e| e.ok()) {
            let path = entry.path();
            let name = path.strip_prefix(std::path::Path::new(src_dir)).unwrap();
            let name_str = name.to_str().unwrap().replace("\\", "/");
            
            if path.is_file() {
                zip.start_file(name_str, options).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
                let mut f = File::open(path).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
                std::io::copy(&mut f, &mut zip).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
            } else if !name.as_os_str().is_empty() {
                zip.add_directory(name_str, options).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
            }
        }
        zip.finish().map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
        Ok(())
    }

    pub fn unzip(&self, src_file: &str, dst_dir: &str) -> Result<()> {
        let file = File::open(src_file).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
        let mut archive = zip::ZipArchive::new(file).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
        
        for i in 0..archive.len() {
            let mut file = archive.by_index(i).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
            let outpath = match file.enclosed_name() {
                Some(path) => std::path::Path::new(dst_dir).join(path),
                None => continue,
            };
            
            if (*file.name()).ends_with('/') {
                std::fs::create_dir_all(&outpath).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
            } else {
                if let Some(p) = outpath.parent() {
                    if !p.exists() {
                        std::fs::create_dir_all(&p).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
                    }
                }
                let mut outfile = File::create(&outpath).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
                std::io::copy(&mut file, &mut outfile).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
            }
        }
        Ok(())
    }
}

impl Default for ArchiveTool {
    fn default() -> Self { Self::new() }
}