use crate::error::MyResult;
use crate::git::cache::TriOption::*;
use crate::git::flags::GitFlags;
use crate::git::repo::GitRepo;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::DerefMut;
use std::path::{Path, PathBuf};
use std::rc::Rc;
enum TriOption<T> {
Yes(T),
No,
Maybe,
}
type GitRepoMap = HashMap<PathBuf, Option<Rc<RefCell<GitRepo>>>>;
pub struct GitCache {
flags: GitFlags,
repos: RefCell<GitRepoMap>,
}
impl GitCache {
pub fn new(flags: &GitFlags) -> Self {
let flags = flags.clone();
let repos = RefCell::new(HashMap::new());
Self { flags, repos }
}
pub fn test_ignored(&self, path: &Path) -> bool {
if let Some(parent) = path.parent() {
if let Some(repo) = self.find_repository(parent) {
let repo = repo.borrow();
return repo.test_ignored(path).unwrap_or(true);
}
}
true
}
pub fn test_allowed(&self, path: &Path) -> MyResult<Option<GitFlags>> {
if let Some(parent) = path.parent() {
if let Some(repo) = self.find_repository(parent) {
let mut repo = repo.borrow_mut();
let result = repo.test_allowed(&self.flags, path)?;
return Ok(result);
}
}
if self.flags.untracked {
let result = GitFlags::default().with_untracked(true);
return Ok(Some(result));
}
Ok(None)
}
fn find_repository(&self, path: &Path) -> Option<Rc<RefCell<GitRepo>>> {
let mut repos = self.repos.borrow_mut();
match Self::find_recursive(repos.deref_mut(), path) {
Yes(repo) => {
Some(repo)
}
No => {
None
}
Maybe => {
if let Some(repo) = GitRepo::open_repository(path, repos.keys()) {
let root = repo.get_root().to_path_buf();
let repo = Rc::new(RefCell::new(repo));
repos.insert(root, Some(Rc::clone(&repo)));
Some(repo)
} else {
let path = PathBuf::from(path);
repos.insert(path, None);
None
}
}
}
}
fn find_recursive(repos: &GitRepoMap, path: &Path) -> TriOption<Rc<RefCell<GitRepo>>> {
if let Some(repo) = repos.get(path) {
if let Some(repo) = repo {
Yes(Rc::clone(repo))
} else {
No
}
} else if let Some(parent) = path.parent() {
if let Yes(repo) = Self::find_recursive(repos, parent) {
Yes(repo)
} else {
Maybe
}
} else {
Maybe
}
}
}