use anyhow::Result; use collections::HashMap; use parking_lot::Mutex; use std::{ path::{Component, Path, PathBuf}, sync::Arc, }; pub use git2::Repository as LibGitRepository; #[async_trait::async_trait] pub trait GitRepository: Send { fn reload_index(&self); fn load_index_text(&self, relative_file_path: &Path) -> Option; } #[async_trait::async_trait] impl GitRepository for LibGitRepository { fn reload_index(&self) { if let Ok(mut index) = self.index() { _ = index.read(false); } } fn load_index_text(&self, relative_file_path: &Path) -> Option { fn logic(repo: &LibGitRepository, relative_file_path: &Path) -> Result> { const STAGE_NORMAL: i32 = 0; let index = repo.index()?; // This check is required because index.get_path() unwraps internally :( check_path_to_repo_path_errors(relative_file_path)?; let oid = match index.get_path(&relative_file_path, STAGE_NORMAL) { Some(entry) => entry.id, None => return Ok(None), }; let content = repo.find_blob(oid)?.content().to_owned(); Ok(Some(String::from_utf8(content)?)) } match logic(&self, relative_file_path) { Ok(value) => return value, Err(err) => log::error!("Error loading head text: {:?}", err), } None } } #[derive(Debug, Clone, Default)] pub struct FakeGitRepository { state: Arc>, } #[derive(Debug, Clone, Default)] pub struct FakeGitRepositoryState { pub index_contents: HashMap, } impl FakeGitRepository { pub fn open(state: Arc>) -> Arc> { Arc::new(Mutex::new(FakeGitRepository { state })) } } #[async_trait::async_trait] impl GitRepository for FakeGitRepository { fn reload_index(&self) {} fn load_index_text(&self, path: &Path) -> Option { let state = self.state.lock(); state.index_contents.get(path).cloned() } } fn check_path_to_repo_path_errors(relative_file_path: &Path) -> Result<()> { match relative_file_path.components().next() { None => anyhow::bail!("repo path should not be empty"), Some(Component::Prefix(_)) => anyhow::bail!( "repo path `{}` should be relative, not a windows prefix", relative_file_path.to_string_lossy() ), Some(Component::RootDir) => { anyhow::bail!( "repo path `{}` should be relative", relative_file_path.to_string_lossy() ) } Some(Component::CurDir) => { anyhow::bail!( "repo path `{}` should not start with `.`", relative_file_path.to_string_lossy() ) } Some(Component::ParentDir) => { anyhow::bail!( "repo path `{}` should not start with `..`", relative_file_path.to_string_lossy() ) } _ => Ok(()), } }