Skip to main content

xtask_toolkit/targz/
mod.rs

1use std::path::{Path, PathBuf};
2
3pub struct DirCompress {
4    dir: PathBuf,
5    filter_extensions: Vec<String>,
6    filter_filename_regex: Option<regex::Regex>,
7    filter_filenames: Vec<String>,
8    search_subdirs: bool,
9}
10
11impl DirCompress {
12    pub fn new<T>(dir: T) -> Option<Self> where T: Into<PathBuf> {
13        let dir : PathBuf = dir.into();
14        dir.is_dir().then_some(Self {
15            dir,
16            filter_filenames: Vec::new(),
17            filter_extensions: Vec::new(),
18            filter_filename_regex: None,
19            search_subdirs: false,
20        })
21    }
22
23    pub fn search_subdirs(&mut self) -> &mut Self {
24        self.search_subdirs = true;
25        self
26    }
27
28    pub fn filter_extension(&mut self, extension: &str) -> &mut Self {
29        self.filter_extensions.push(extension.to_string());
30        self
31    }
32
33    pub fn filter_filename_regex(&mut self, regex: regex::Regex) -> &mut Self {
34        self.filter_filename_regex = Some(regex);
35        self
36    }
37
38    pub fn filter_filename(&mut self, filename: &str) -> &mut Self {
39        self.filter_filenames.push(filename.to_string());
40        self
41    }
42
43    pub fn compress(&self, output_file: &Path) -> Result<(), std::io::Error> {
44        let walkdir = walkdir::WalkDir::new(&self.dir);
45        let walkdir = if self.search_subdirs {
46            walkdir.max_depth(1)
47        } else {
48            walkdir
49        };
50
51        let files = walkdir
52            .into_iter()
53            .filter_map(|x| {
54                x.ok()
55                    .and_then(|x| {
56                        let filename = x.file_name().to_string_lossy();
57
58                        for name in &self.filter_filenames {
59                            if filename == name.as_str() {
60                                return Some(x);
61                            }
62                        }
63
64                        for ext in &self.filter_extensions {
65                            if x.file_name().to_string_lossy().ends_with(ext) {
66                                return Some(x);
67                            }
68                        }
69
70                        if let Some(regex) = &self.filter_filename_regex {
71                            if regex.is_match(filename.as_ref()) {
72                                return Some(x);
73                            }
74                        }
75
76                        None
77                    })
78                    .and_then(|x| x.path().is_file().then_some(x))
79            })
80            .map(|x| x.path().to_path_buf())
81            .collect::<Vec<PathBuf>>();
82
83        let dest_file = std::fs::File::create(&output_file)?;
84        let enc = flate2::write::GzEncoder::new(&dest_file, flate2::Compression::default());
85        let mut builder = tar::Builder::new(enc);
86
87        for src in files {
88            builder.append_path_with_name(
89                &src,
90                src.file_name()
91                    .unwrap_or_default()
92                    .to_string_lossy()
93                    .to_string(),
94            )?;
95        }
96
97        Ok(())
98    }
99}