use std::{
fmt::Debug,
path::{Path, PathBuf},
};
#[cfg(feature = "git-cli")]
pub use self::git_cli::GitCliBackendError;
#[cfg(feature = "git-gix")]
pub use self::git_gix::GixBackendError;
#[cfg(feature = "git-libgit2")]
pub use self::git_libgit2::Libgit2BackendError;
use crate::{
error::{self, ModifyGuardError},
repository::{FileChange, RepositoryChanges},
util::WorktreeRelativePath,
};
#[cfg(feature = "git-cli")]
mod git_cli;
#[cfg(feature = "git-gix")]
mod git_gix;
#[cfg(feature = "git-libgit2")]
mod git_libgit2;
#[cfg(test)]
mod tests;
trait VcsBackend: Debug + Send + Sync {
fn discover(&self, path: &Path) -> Result<Option<Box<dyn VcsRepository>>, ModifyGuardError>;
fn open(&self, path: &Path) -> Result<Option<Box<dyn VcsRepository>>, ModifyGuardError>;
}
static BACKENDS: &[&dyn VcsBackend] = &[
#[cfg(feature = "git-gix")]
&git_gix::BACKEND,
#[cfg(feature = "git-libgit2")]
&git_libgit2::BACKEND,
#[cfg(feature = "git-cli")]
&git_cli::BACKEND,
];
pub(crate) fn discover(path: &Path) -> Result<Option<Box<dyn VcsRepository>>, ModifyGuardError> {
for backend in BACKENDS {
if let Some(repo) = backend.discover(path)? {
return Ok(Some(repo));
}
}
Ok(None)
}
pub(crate) fn open(path: &Path) -> Result<Box<dyn VcsRepository>, ModifyGuardError> {
for backend in BACKENDS {
if let Some(repo) = backend.open(path)? {
return Ok(repo);
}
}
Err(error::NotARepositorySnafu { path }.build())
}
pub(crate) trait VcsRepository: Debug {
fn worktree(&self) -> &Path;
fn repository_changes(&self) -> Result<Option<RepositoryChanges>, ModifyGuardError>;
fn path_changes(&self, wt_path: &Path) -> Result<Option<RepositoryChanges>, ModifyGuardError>;
fn file_change(&self, wt_path: &Path) -> Result<Option<FileChange>, ModifyGuardError>;
fn resolve_path(&self, path: &Path) -> Result<PathBuf, ModifyGuardError> {
let wt_path = WorktreeRelativePath::from_path(self.worktree(), path)?;
Ok(wt_path.into())
}
}
const _: Option<&dyn VcsRepository> = None;