1use std::sync::Mutex;
4use std::time::SystemTime;
5
6use anyhow::Result;
7use endringer_core::backend::VcsBackend;
8use endringer_core::types::{BranchInfo, CommitId, CommitInfo, DiffSummary, SortOrder, StatusDigest, TagInfo};
9
10use crate::{branch, commit, diff, tag};
11
12pub struct GitBackend {
18 inner: Mutex<gix::Repository>,
19}
20
21impl GitBackend {
22 pub fn open(path: &std::path::Path) -> Result<Self> {
24 let inner = gix::discover(path)?;
25 Ok(GitBackend { inner: Mutex::new(inner) })
26 }
27}
28
29macro_rules! repo {
31 ($self:expr) => {
32 $self.inner.lock().expect("gix repository mutex poisoned")
33 };
34}
35
36impl VcsBackend for GitBackend {
37 fn status_digest(&self) -> Result<StatusDigest> {
38 commit::status_digest(&*repo!(self))
39 }
40
41 fn local_branches(&self) -> Result<Vec<BranchInfo>> {
42 branch::local_branches(&*repo!(self))
43 }
44
45 fn remote_branches(&self) -> Result<Vec<BranchInfo>> {
46 branch::remote_branches(&*repo!(self))
47 }
48
49 fn list_commits(&self) -> Result<Vec<CommitInfo>> {
50 branch::list_commits(&*repo!(self))
51 }
52
53 fn list_commits_sorted(&self, order: SortOrder) -> Result<Vec<CommitInfo>> {
54 branch::list_commits_sorted(&*repo!(self), order)
55 }
56
57 fn log_since(&self, since: SystemTime, until: SystemTime) -> Result<Vec<CommitInfo>> {
58 branch::log_since(&*repo!(self), since, until)
59 }
60
61 fn find_commit(&self, id: &CommitId) -> Result<CommitInfo> {
62 branch::find_commit(&*repo!(self), id)
63 }
64
65 fn list_tags(&self) -> Result<Vec<TagInfo>> {
66 tag::list_tags(&*repo!(self))
67 }
68
69 fn list_tags_sorted(&self, order: SortOrder) -> Result<Vec<TagInfo>> {
70 tag::list_tags_sorted(&*repo!(self), order)
71 }
72
73 fn create_tag(&self, name: &str) -> Result<()> {
74 tag::create_tag(&*repo!(self), name)
75 }
76
77 fn create_annotated_tag(&self, name: &str, message: &str) -> Result<()> {
78 tag::create_annotated_tag(&*repo!(self), name, message)
79 }
80
81 fn delete_tag(&self, name: &str) -> Result<()> {
82 tag::delete_tag(&*repo!(self), name)
83 }
84
85 fn diff(&self, from: &CommitId, to: &CommitId) -> Result<DiffSummary> {
86 diff::diff(&*repo!(self), from, to)
87 }
88
89 fn remote_url(&self, name: &str) -> Option<String> {
90 let repo = repo!(self);
91 let remote = repo.find_remote(name).ok()?;
92 let url = remote.url(gix::remote::Direction::Fetch)?;
93 Some(url.to_bstring().to_string())
94 }
95}