use std::path::{Path, PathBuf};
pub fn find_repo_root(start: &Path) -> Option<PathBuf> {
let start = start.canonicalize().ok()?;
for ancestor in start.ancestors() {
if ancestor.join(".git").exists() {
return Some(ancestor.to_path_buf());
}
}
None
}
pub fn resolve_working_dir() -> PathBuf {
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
find_repo_root(&cwd).unwrap_or(cwd)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_find_repo_root_with_git_dir() {
let temp = tempfile::tempdir().unwrap();
let root = temp.path();
fs::create_dir(root.join(".git")).unwrap();
let sub = root.join("a").join("b").join("c");
fs::create_dir_all(&sub).unwrap();
let found = find_repo_root(&sub);
assert!(found.is_some());
assert_eq!(
found.unwrap().canonicalize().unwrap(),
root.canonicalize().unwrap()
);
}
#[test]
fn test_find_repo_root_from_root_itself() {
let temp = tempfile::tempdir().unwrap();
let root = temp.path();
fs::create_dir(root.join(".git")).unwrap();
let found = find_repo_root(root);
assert!(found.is_some());
assert_eq!(
found.unwrap().canonicalize().unwrap(),
root.canonicalize().unwrap()
);
}
#[test]
fn test_find_repo_root_no_git_dir() {
let temp = tempfile::tempdir().unwrap();
let sub = temp.path().join("a").join("b");
fs::create_dir_all(&sub).unwrap();
let result = find_repo_root(&sub);
if let Some(found) = result {
assert!(found.join(".git").exists());
}
}
#[test]
fn test_find_repo_root_nonexistent_path() {
let result = find_repo_root(Path::new("/nonexistent/path/that/does/not/exist"));
assert!(result.is_none());
}
#[test]
fn test_resolve_working_dir_returns_path() {
let dir = resolve_working_dir();
assert!(dir.exists() || dir == PathBuf::from("."));
}
}