use std::path::{Path, PathBuf};
use crate::error::{Error, Result};
pub(crate) struct Repo {
inner: gix::Repository,
}
impl Repo {
pub(crate) fn discover(start: &Path) -> Result<Repo> {
match gix::discover(start) {
Ok(inner) => Ok(Repo { inner }),
Err(_) => Err(Error::NotInRepo),
}
}
pub(crate) fn gix(&self) -> &gix::Repository {
&self.inner
}
pub(crate) fn is_bare(&self) -> bool {
self.inner.workdir().is_none()
}
pub(crate) fn current_workdir(&self) -> Option<PathBuf> {
self.inner.workdir().map(Path::to_path_buf)
}
pub(crate) fn git_dir(&self) -> PathBuf {
self.inner.git_dir().to_path_buf()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testutil::TestRepo;
#[test]
fn discovers_from_root_and_subdir() {
let repo = TestRepo::init();
let r = Repo::discover(repo.root()).unwrap();
assert!(!r.is_bare());
assert_eq!(canon(&r.current_workdir().unwrap()), canon(repo.root()));
let sub = repo.root().join("a/b");
std::fs::create_dir_all(&sub).unwrap();
let r2 = Repo::discover(&sub).unwrap();
assert_eq!(canon(&r2.current_workdir().unwrap()), canon(repo.root()));
}
#[test]
fn current_workdir_from_linked_worktree() {
let repo = TestRepo::init();
repo.add_worktree("feature/x", "../wt-x");
let linked = repo.root().parent().unwrap().join("wt-x");
let r = Repo::discover(&linked).unwrap();
assert_eq!(canon(&r.current_workdir().unwrap()), canon(&linked));
}
#[test]
fn not_in_repo_errors() {
let dir = tempfile::tempdir().unwrap();
assert!(matches!(Repo::discover(dir.path()), Err(Error::NotInRepo)));
}
#[test]
fn bare_repo_is_detected() {
let repo = TestRepo::init_bare();
let r = Repo::discover(repo.root()).unwrap();
assert!(r.is_bare());
assert!(r.current_workdir().is_none());
}
fn canon(p: &Path) -> PathBuf {
std::fs::canonicalize(p).unwrap_or_else(|_| p.to_path_buf())
}
}