jsona_util/util/
glob_rule.rs

1use globset::{Glob, GlobSetBuilder};
2use std::{fmt::Debug, path::Path};
3use url::Url;
4
5use super::path as path_utils;
6use super::url as url_utils;
7
8#[derive(Clone)]
9pub struct GlobRule {
10    raw_include: Vec<String>,
11    raw_exclude: Vec<String>,
12    include: globset::GlobSet,
13    exclude: globset::GlobSet,
14}
15
16impl Debug for GlobRule {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("GlobRule")
19            .field("include", &self.raw_include)
20            .field("exclude", &self.raw_exclude)
21            .finish()
22    }
23}
24
25impl GlobRule {
26    pub fn new(
27        include: impl IntoIterator<Item = impl AsRef<str>>,
28        exclude: impl IntoIterator<Item = impl AsRef<str>>,
29    ) -> Result<Self, anyhow::Error> {
30        let mut inc = GlobSetBuilder::new();
31        let mut raw_include = vec![];
32        for glob in include {
33            inc.add(Glob::new(glob.as_ref())?);
34            raw_include.push(glob.as_ref().to_string());
35        }
36
37        let mut exc = GlobSetBuilder::new();
38        let mut raw_exclude = vec![];
39        for glob in exclude {
40            exc.add(Glob::new(glob.as_ref())?);
41            raw_exclude.push(glob.as_ref().to_string());
42        }
43
44        Ok(Self {
45            include: inc.build()?,
46            exclude: exc.build()?,
47            raw_include,
48            raw_exclude,
49        })
50    }
51
52    pub fn preprocessing_pattern(pattern: &str, base: &Option<Url>) -> Option<String> {
53        let path = path_utils::to_unix(pattern);
54        if path.starts_with('/') {
55            let base = base.as_ref().and_then(url_utils::to_file_path)?;
56            Some(format!("{}{}", base.trim_end_matches('/'), path))
57        } else {
58            Some(format!("**/{}", path))
59        }
60    }
61
62    pub fn is_match(&self, path: impl AsRef<Path>) -> bool {
63        if !self.include.is_match(path.as_ref()) {
64            return false;
65        }
66
67        !self.exclude.is_match(path.as_ref())
68    }
69    pub fn is_match_url(&self, url: &Url) -> bool {
70        if let Some(path) = url_utils::to_file_path(url).map(path_utils::to_unix) {
71            self.is_match(path)
72        } else {
73            false
74        }
75    }
76}