jsona_util/util/
glob_rule.rs1use 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}