rskit_git/embedded/
repository.rs1use std::path::{Path, PathBuf};
2
3use rskit_errors::AppResult;
4
5use crate::core::Repository as RepositoryTrait;
6use crate::error::GitError;
7use crate::types::{Oid, Reference};
8
9use super::{map_head_error, oid_from_git2, reference_from_git2};
10
11pub struct Git2Repository {
13 pub(crate) repo: git2::Repository,
14 pub(crate) root: PathBuf,
15}
16
17impl Git2Repository {
18 pub fn root(&self) -> &Path {
20 &self.root
21 }
22}
23
24pub fn open(path: impl AsRef<Path>) -> AppResult<Git2Repository> {
26 let path = path.as_ref();
27 let abs = std::fs::canonicalize(path).map_err(|err| match err.kind() {
28 std::io::ErrorKind::NotFound => GitError::NotFound {
29 path: path.to_path_buf(),
30 },
31 _ => GitError::Internal(git2::Error::from_str(&err.to_string())),
32 })?;
33 let repo = git2::Repository::open(&abs).map_err(|err| {
34 if err.code() == git2::ErrorCode::NotFound {
35 GitError::NotFound { path: abs.clone() }
36 } else {
37 GitError::Internal(err)
38 }
39 })?;
40 let root = repo.workdir().unwrap_or_else(|| repo.path()).to_path_buf();
42 Ok(Git2Repository { repo, root })
43}
44
45pub fn discover(path: impl AsRef<Path>) -> AppResult<Git2Repository> {
47 let path = path.as_ref();
48 let repo = git2::Repository::discover(path).map_err(|err| {
49 if err.code() == git2::ErrorCode::NotFound {
50 GitError::NotFound {
51 path: path.to_path_buf(),
52 }
53 } else {
54 GitError::Internal(err)
55 }
56 })?;
57 let root = repo.workdir().unwrap_or_else(|| repo.path()).to_path_buf();
59 Ok(Git2Repository { repo, root })
60}
61
62pub fn clone(url: &str, path: impl AsRef<Path>) -> AppResult<Git2Repository> {
64 let path = path.as_ref();
65 let repo = git2::Repository::clone(url, path).map_err(GitError::Internal)?;
66 let root = repo
67 .workdir()
68 .map(Path::to_path_buf)
69 .unwrap_or_else(|| path.to_path_buf());
70 Ok(Git2Repository { repo, root })
71}
72
73pub fn init(path: impl AsRef<Path>) -> AppResult<Git2Repository> {
75 let path = path.as_ref();
76 let repo = git2::Repository::init(path).map_err(GitError::Internal)?;
77 let root = repo
78 .workdir()
79 .map(Path::to_path_buf)
80 .unwrap_or_else(|| path.to_path_buf());
81 Ok(Git2Repository { repo, root })
82}
83
84pub fn init_bare(path: impl AsRef<Path>) -> AppResult<Git2Repository> {
86 let path = path.as_ref();
87 let repo = git2::Repository::init_bare(path).map_err(GitError::Internal)?;
88 Ok(Git2Repository {
89 repo,
90 root: path.to_path_buf(),
91 })
92}
93
94impl RepositoryTrait for Git2Repository {
95 fn root(&self) -> &Path {
96 &self.root
97 }
98
99 fn head(&self) -> AppResult<Reference> {
100 let head = self.repo.head().map_err(map_head_error)?;
101 Ok(reference_from_git2(&head))
102 }
103
104 fn resolve_ref(&self, refname: &str) -> AppResult<Oid> {
105 let obj = self
106 .repo
107 .revparse_single(refname)
108 .map_err(|_| GitError::RefNotFound {
109 refname: refname.to_string(),
110 })?;
111 Ok(oid_from_git2(obj.id()))
112 }
113
114 fn is_dirty(&self) -> AppResult<bool> {
115 let statuses = self.repo.statuses(None).map_err(GitError::Internal)?;
116 Ok(!statuses.is_empty())
117 }
118}