1use crate::error::MyResult;
2use crate::git::cache::TriOption::*;
3use crate::git::flags::GitFlags;
4use crate::git::repo::GitRepo;
5use std::cell::RefCell;
6use std::collections::HashMap;
7use std::ops::DerefMut;
8use std::path::{Path, PathBuf};
9use std::rc::Rc;
10
11enum TriOption<T> {
12 Yes(T),
13 No,
14 Maybe,
15}
16
17type GitRepoMap = HashMap<PathBuf, Option<Rc<RefCell<GitRepo>>>>;
18
19pub struct GitCache {
20 flags: GitFlags,
21 repos: RefCell<GitRepoMap>,
22}
23
24impl GitCache {
25 pub fn new(flags: &GitFlags) -> Self {
26 let flags = flags.clone();
27 let repos = RefCell::new(HashMap::new());
28 Self { flags, repos }
29 }
30
31 pub fn test_ignored(&self, path: &Path) -> bool {
32 if let Some(parent) = path.parent() {
33 if let Some(repo) = self.find_repository(parent) {
34 let repo = repo.borrow();
35 return repo.test_ignored(path).unwrap_or(true);
36 }
37 }
38 true
39 }
40
41 pub fn test_allowed(&self, path: &Path) -> MyResult<Option<GitFlags>> {
42 if let Some(parent) = path.parent() {
43 if let Some(repo) = self.find_repository(parent) {
44 let mut repo = repo.borrow_mut();
45 let result = repo.test_allowed(&self.flags, path)?;
46 return Ok(result);
47 }
48 }
49 if self.flags.untracked {
50 let result = GitFlags::default().with_untracked(true);
51 return Ok(Some(result));
52 }
53 Ok(None)
54 }
55
56 fn find_repository(&self, path: &Path) -> Option<Rc<RefCell<GitRepo>>> {
57 let mut repos = self.repos.borrow_mut();
58 match Self::find_recursive(repos.deref_mut(), path) {
59 Yes(repo) => {
60 Some(repo)
61 }
62 No => {
63 None
64 }
65 Maybe => {
66 if let Some(repo) = GitRepo::open_repository(path, repos.keys()) {
67 let root = repo.get_root().to_path_buf();
68 let repo = Rc::new(RefCell::new(repo));
69 repos.insert(root, Some(Rc::clone(&repo)));
70 Some(repo)
71 } else {
72 let path = PathBuf::from(path);
73 repos.insert(path, None);
74 None
75 }
76 }
77 }
78 }
79
80 fn find_recursive(repos: &GitRepoMap, path: &Path) -> TriOption<Rc<RefCell<GitRepo>>> {
81 if let Some(repo) = repos.get(path) {
82 if let Some(repo) = repo {
83 Yes(Rc::clone(repo))
84 } else {
85 No
86 }
87 } else if let Some(parent) = path.parent() {
88 if let Yes(repo) = Self::find_recursive(repos, parent) {
89 Yes(repo)
90 } else {
91 Maybe
92 }
93 } else {
94 Maybe
95 }
96 }
97}