file_source/paths_provider/
glob.rs1use std::path::PathBuf;
4
5pub use glob::MatchOptions;
6use glob::Pattern;
7
8use super::PathsProvider;
9use crate::FileSourceInternalEvents;
10
11pub struct Glob<E: FileSourceInternalEvents> {
16 include_patterns: Vec<String>,
17 exclude_patterns: Vec<Pattern>,
18 glob_match_options: MatchOptions,
19 emitter: E,
20}
21
22impl<E: FileSourceInternalEvents> Glob<E> {
23 pub fn new(
27 include_patterns: &[PathBuf],
28 exclude_patterns: &[PathBuf],
29 glob_match_options: MatchOptions,
30 emitter: E,
31 ) -> Option<Self> {
32 let include_patterns = include_patterns
33 .iter()
34 .map(|path| path.to_str().map(ToOwned::to_owned))
35 .collect::<Option<_>>()?;
36
37 let exclude_patterns = exclude_patterns
38 .iter()
39 .filter_map(|path| path.to_str().map(|path| Pattern::new(path).ok()))
40 .collect::<Option<Vec<_>>>()?;
41
42 Some(Self {
43 include_patterns,
44 exclude_patterns,
45 glob_match_options,
46 emitter,
47 })
48 }
49}
50
51impl<E: FileSourceInternalEvents> PathsProvider for Glob<E> {
52 type IntoIter = Vec<PathBuf>;
53
54 fn paths(&self) -> Self::IntoIter {
55 self.include_patterns
56 .iter()
57 .flat_map(|include_pattern| {
58 glob::glob_with(include_pattern.as_str(), self.glob_match_options)
59 .expect("failed to read glob pattern")
60 .filter_map(|val| {
61 val.map_err(|error| {
62 self.emitter
63 .emit_path_globbing_failed(error.path(), error.error())
64 })
65 .ok()
66 })
67 })
68 .filter(|candidate_path: &PathBuf| -> bool {
69 !self.exclude_patterns.iter().any(|exclude_pattern| {
70 let candidate_path_str = candidate_path.to_str().unwrap();
71 exclude_pattern.matches(candidate_path_str)
72 })
73 })
74 .collect()
75 }
76}