1use std::path::Path;
2use std::path::PathBuf;
3
4use git2::Repository;
5use rootcause::option_ext::OptionExt;
6use rootcause::prelude::ResultExt;
7
8pub fn discover(path: &Path) -> rootcause::Result<Repository> {
14 Ok(Repository::discover(path)
15 .context("error discovering repo")
16 .attach_with(|| format!("path={}", path.display()))?)
17}
18
19pub fn get_root(repo: &Repository) -> PathBuf {
25 if let Some(workdir) = repo.workdir() {
26 return workdir.to_path_buf();
27 }
28 repo.commondir()
30 .components()
31 .filter(|c| c.as_os_str() != ".git")
32 .collect()
33}
34
35pub fn get_relative_path_to_repo(path: &Path, repo: &Repository) -> rootcause::Result<PathBuf> {
41 let repo_workdir = repo
42 .workdir()
43 .context("error getting repository working directory")
44 .attach_with(|| format!("repo={:?}", repo.path().display()))?;
45 Ok(Path::new("/").join(path.strip_prefix(repo_workdir)?))
46}
47
48#[cfg(test)]
49mod tests {
50 use test_that::prelude::*;
51
52 use super::*;
53
54 #[test]
55 fn test_discover_when_path_is_inside_repo_returns_repo() {
56 let (_temp_dir, repo) = crate::tests::init_test_repo(None);
57 let workdir = repo.workdir().unwrap();
58 assert_that!(discover(workdir).map(|_| ()), ok(eq(())));
59 }
60
61 #[test]
62 fn test_discover_when_path_is_not_a_repo_returns_error() {
63 let temp_dir = tempfile::TempDir::new().unwrap();
64 assert_that!(
65 discover(temp_dir.path()).map_err(|err| err.to_string()).map(|_| ()),
66 err(contains_substring("error discovering repo"))
67 );
68 }
69
70 #[test]
71 fn test_get_root_returns_workdir() {
72 let (_temp_dir, repo) = crate::tests::init_test_repo(None);
73 let root = get_root(&repo);
74 assert_that!(root, eq(repo.workdir().unwrap()));
75 }
76
77 #[test]
78 fn test_get_root_in_worktree_returns_worktree_path() {
79 let (temp_dir, repo) = crate::tests::init_test_repo(None);
80
81 let wt_dir = temp_dir.path().join("my_worktree");
82 repo.worktree("my_worktree", &wt_dir, None).unwrap();
83
84 let wt_repo = Repository::open(&wt_dir).unwrap();
85 let root = get_root(&wt_repo);
86 assert_that!(root, eq(wt_dir.canonicalize().unwrap()));
87 }
88
89 #[test]
90 fn test_get_relative_path_to_repo_when_path_inside_repo_returns_rooted_relative() {
91 let (_temp_dir, repo) = crate::tests::init_test_repo(None);
92 let workdir = repo.workdir().unwrap();
93 let file_path = workdir.join("src").join("main.rs");
94 assert_that!(
95 get_relative_path_to_repo(&file_path, &repo),
96 ok(eq(PathBuf::from("/src/main.rs")))
97 );
98 }
99
100 #[test]
101 fn test_get_relative_path_to_repo_when_path_outside_repo_returns_error() {
102 let (_temp_dir, repo) = crate::tests::init_test_repo(None);
103 let outside_path = Path::new("/completely/different/path");
104 assert_that!(get_relative_path_to_repo(outside_path, &repo), err(anything()));
105 }
106}