xtask-toolkit 0.1.12

A collection of useful tools for xtask building
Documentation
use std::path::{Path, PathBuf};

pub struct DirCompress {
    dir: PathBuf,
    filter_extensions: Vec<String>,
    filter_filename_regex: Option<regex::Regex>,
    filter_filenames: Vec<String>,
    search_subdirs: bool,
}

impl DirCompress {
    pub fn new<T>(dir: T) -> Option<Self> where T: Into<PathBuf> {
        let dir : PathBuf = dir.into();
        dir.is_dir().then_some(Self {
            dir,
            filter_filenames: Vec::new(),
            filter_extensions: Vec::new(),
            filter_filename_regex: None,
            search_subdirs: false,
        })
    }

    pub fn search_subdirs(&mut self) -> &mut Self {
        self.search_subdirs = true;
        self
    }

    pub fn filter_extension(&mut self, extension: &str) -> &mut Self {
        self.filter_extensions.push(extension.to_string());
        self
    }

    pub fn filter_filename_regex(&mut self, regex: regex::Regex) -> &mut Self {
        self.filter_filename_regex = Some(regex);
        self
    }

    pub fn filter_filename(&mut self, filename: &str) -> &mut Self {
        self.filter_filenames.push(filename.to_string());
        self
    }

    pub fn compress(&self, output_file: &Path) -> Result<(), std::io::Error> {
        let walkdir = walkdir::WalkDir::new(&self.dir);
        let walkdir = if self.search_subdirs {
            walkdir.max_depth(1)
        } else {
            walkdir
        };

        let files = walkdir
            .into_iter()
            .filter_map(|x| {
                x.ok()
                    .and_then(|x| {
                        let filename = x.file_name().to_string_lossy();

                        for name in &self.filter_filenames {
                            if filename == name.as_str() {
                                return Some(x);
                            }
                        }

                        for ext in &self.filter_extensions {
                            if x.file_name().to_string_lossy().ends_with(ext) {
                                return Some(x);
                            }
                        }

                        if let Some(regex) = &self.filter_filename_regex {
                            if regex.is_match(filename.as_ref()) {
                                return Some(x);
                            }
                        }

                        None
                    })
                    .and_then(|x| x.path().is_file().then_some(x))
            })
            .map(|x| x.path().to_path_buf())
            .collect::<Vec<PathBuf>>();

        let dest_file = std::fs::File::create(&output_file)?;
        let enc = flate2::write::GzEncoder::new(&dest_file, flate2::Compression::default());
        let mut builder = tar::Builder::new(enc);

        for src in files {
            builder.append_path_with_name(
                &src,
                src.file_name()
                    .unwrap_or_default()
                    .to_string_lossy()
                    .to_string(),
            )?;
        }

        Ok(())
    }
}