1use crate::{BranchInfo, CommitInfo, GitError, RepoStatus, Result};
2use git2::Repository;
3use std::path::{Path, PathBuf};
4
5pub struct GitRepo {
6 inner: Repository,
7 path: PathBuf,
8}
9
10impl GitRepo {
11 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
12 let path = path.as_ref().to_path_buf();
13 let inner = git2::Repository::open(&path)?;
14 Ok(Self { inner, path })
15 }
16
17 pub fn discover(path: impl AsRef<Path>) -> Result<Self> {
18 let path = path.as_ref();
19 let inner = git2::Repository::discover(path)
20 .map_err(|_| GitError::NotARepo(path.display().to_string()))?;
21 let work_dir = inner
22 .workdir()
23 .map(|p| p.to_path_buf())
24 .unwrap_or_else(|| path.to_path_buf());
25 Ok(Self {
26 inner,
27 path: work_dir,
28 })
29 }
30
31 pub fn path(&self) -> &Path {
32 &self.path
33 }
34
35 pub fn git_dir(&self) -> PathBuf {
36 self.inner.path().to_path_buf()
37 }
38
39 pub fn is_bare(&self) -> bool {
40 self.inner.is_bare()
41 }
42
43 pub fn status(&self) -> Result<RepoStatus> {
44 RepoStatus::collect(&self.inner, &self.path)
45 }
46
47 pub fn current_branch(&self) -> Result<Option<BranchInfo>> {
48 BranchInfo::current(&self.inner)
49 }
50
51 pub fn branches(&self) -> Result<Vec<BranchInfo>> {
52 BranchInfo::list(&self.inner)
53 }
54
55 pub fn recent_commits(&self, count: usize) -> Result<Vec<CommitInfo>> {
56 CommitInfo::recent(&self.inner, count)
57 }
58
59 pub fn is_dirty(&self) -> Result<bool> {
60 Ok(!self.status()?.is_clean())
61 }
62
63 pub fn head_commit(&self) -> Result<Option<CommitInfo>> {
64 CommitInfo::head(&self.inner)
65 }
66
67 pub fn inner(&self) -> &Repository {
68 &self.inner
69 }
70}