1use std::time::SystemTime;
4
5use anyhow::Result;
6use endringer_core::backend::VcsBackend;
7use endringer_core::types::{
8 AheadBehind, BlameEntry, BranchInfo, BranchTrackingInfo, CommitId, CommitInfo,
9 DiffSummary, RepositoryInfo, SortOrder, StashEntry, StatusDigest, SubmoduleInfo,
10 TagInfo, WorktreeInfo, WorktreeStatus,
11};
12
13use crate::{blame, branch, commit, diff, graph, info, object, stash, status, submodule, tag, worktree};
14
15pub struct GitBackend {
22 inner: gix::ThreadSafeRepository,
23}
24
25impl GitBackend {
26 pub fn open(path: &std::path::Path) -> Result<Self> {
31 let inner = gix::discover(path)?.into_sync();
32 Ok(GitBackend { inner })
33 }
34}
35
36macro_rules! repo {
40 ($self:expr) => {
41 $self.inner.to_thread_local()
42 };
43}
44
45impl VcsBackend for GitBackend {
46 fn status_digest(&self) -> Result<StatusDigest> {
47 commit::status_digest(&repo!(self))
48 }
49
50 fn local_branches(&self) -> Result<Vec<BranchInfo>> {
51 branch::local_branches(&repo!(self))
52 }
53
54 fn remote_branches(&self) -> Result<Vec<BranchInfo>> {
55 branch::remote_branches(&repo!(self))
56 }
57
58 fn list_commits(&self) -> Result<Vec<CommitInfo>> {
59 branch::list_commits(&repo!(self))
60 }
61
62 fn list_commits_sorted(&self, order: SortOrder) -> Result<Vec<CommitInfo>> {
63 branch::list_commits_sorted(&repo!(self), order)
64 }
65
66 fn log_since(&self, since: SystemTime, until: SystemTime) -> Result<Vec<CommitInfo>> {
67 branch::log_since(&repo!(self), since, until)
68 }
69
70 fn find_commit(&self, id: &CommitId) -> Result<CommitInfo> {
71 branch::find_commit(&repo!(self), id)
72 }
73
74 fn list_tags(&self) -> Result<Vec<TagInfo>> {
75 tag::list_tags(&repo!(self))
76 }
77
78 fn list_tags_sorted(&self, order: SortOrder) -> Result<Vec<TagInfo>> {
79 tag::list_tags_sorted(&repo!(self), order)
80 }
81
82 fn create_tag(&self, name: &str) -> Result<()> {
83 tag::create_tag(&repo!(self), name)
84 }
85
86 fn create_annotated_tag(&self, name: &str, message: &str) -> Result<()> {
87 tag::create_annotated_tag(&repo!(self), name, message)
88 }
89
90 fn delete_tag(&self, name: &str) -> Result<()> {
91 tag::delete_tag(&repo!(self), name)
92 }
93
94 fn diff(&self, from: &CommitId, to: &CommitId) -> Result<DiffSummary> {
95 diff::diff(&repo!(self), from, to)
96 }
97
98 fn remote_url(&self, name: &str) -> Option<String> {
99 let repo = repo!(self);
100 let remote = repo.find_remote(name).ok()?;
101 let url = remote.url(gix::remote::Direction::Fetch)?;
102 Some(url.to_bstring().to_string())
103 }
104
105 fn is_dirty(&self) -> Result<bool> {
106 status::is_dirty(&repo!(self))
107 }
108
109 fn merge_base(&self, a: &CommitId, b: &CommitId) -> Result<Option<CommitId>> {
110 graph::merge_base(&repo!(self), a, b)
111 }
112
113 fn is_ancestor(&self, candidate: &CommitId, descendant: &CommitId) -> Result<bool> {
114 graph::is_ancestor(&repo!(self), candidate, descendant)
115 }
116
117 fn ahead_behind(&self, local: &CommitId, upstream: &CommitId) -> Result<AheadBehind> {
118 graph::ahead_behind(&repo!(self), local, upstream)
119 }
120
121 fn branch_ahead_behind(&self, branch: &str) -> Result<Option<AheadBehind>> {
122 graph::branch_ahead_behind(&repo!(self), branch)
123 }
124
125 fn repository_info(&self) -> Result<RepositoryInfo> {
126 info::repository_info(&repo!(self), endringer_core::types::BackendKind::Git)
127 }
128
129 fn branch_tracking(&self, branch: &str) -> Result<BranchTrackingInfo> {
130 branch::branch_tracking(&repo!(self), branch)
131 }
132
133 fn local_branch_tracking(&self) -> Result<Vec<BranchTrackingInfo>> {
134 branch::local_branch_tracking(&repo!(self))
135 }
136
137 fn is_merged_into(&self, b: &str, target: &str) -> Result<bool> {
138 branch::is_merged_into(&repo!(self), b, target)
139 }
140
141 fn blame(&self, path: &std::path::Path) -> Result<Vec<BlameEntry>> {
142 blame::blame(&repo!(self), path)
143 }
144
145 fn worktree_status(&self) -> Result<WorktreeStatus> {
146 status::worktree_status(&repo!(self))
147 }
148
149 fn file_at_commit(&self, path: &std::path::Path, commit_id: &CommitId) -> Result<Vec<u8>> {
150 object::file_at_commit(&repo!(self), path, commit_id)
151 }
152
153 fn submodules(&self) -> Result<Vec<SubmoduleInfo>> {
154 submodule::submodules(&repo!(self))
155 }
156
157 fn stash_entries(&self) -> Result<Vec<StashEntry>> {
158 stash::stash_entries(&repo!(self))
159 }
160
161 fn worktrees(&self) -> Result<Vec<WorktreeInfo>> {
162 worktree::worktrees(&repo!(self))
163 }
164}