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