1use ignore::gitignore::Gitignore;
2use std::{ffi::OsStr, path::Path, sync::Arc};
3
4#[derive(Debug)]
5pub enum IgnoreStack {
6 None,
7 Some {
8 abs_base_path: Arc<Path>,
9 ignore: Arc<Gitignore>,
10 parent: Arc<IgnoreStack>,
11 },
12 All,
13}
14
15impl IgnoreStack {
16 pub fn none() -> Arc<Self> {
17 Arc::new(Self::None)
18 }
19
20 pub fn all() -> Arc<Self> {
21 Arc::new(Self::All)
22 }
23
24 pub fn append(self: Arc<Self>, abs_base_path: Arc<Path>, ignore: Arc<Gitignore>) -> Arc<Self> {
25 match self.as_ref() {
26 IgnoreStack::All => self,
27 _ => Arc::new(Self::Some {
28 abs_base_path,
29 ignore,
30 parent: self,
31 }),
32 }
33 }
34
35 pub fn is_abs_path_ignored(&self, abs_path: &Path, is_dir: bool) -> bool {
36 if is_dir && abs_path.file_name() == Some(OsStr::new(".git")) {
37 return true;
38 }
39
40 match self {
41 Self::None => false,
42 Self::All => true,
43 Self::Some {
44 abs_base_path,
45 ignore,
46 parent: prev,
47 } => match ignore.matched(abs_path.strip_prefix(abs_base_path).unwrap(), is_dir) {
48 ignore::Match::None => prev.is_abs_path_ignored(abs_path, is_dir),
49 ignore::Match::Ignore(_) => true,
50 ignore::Match::Whitelist(_) => false,
51 },
52 }
53 }
54}