1use std::path::Path;
4use std::sync::Arc;
5use std::time::SystemTime;
6
7use endringer::Error as EndringerError;
8use endringer::Result;
9use endringer::repository::{Repository, jj_repository, repository};
10use endringer::{
11 AheadBehind, BlameEntry, BranchInfo, BranchTrackingInfo, CommitId, CommitInfo,
12 CommitQuery, CommitQueryResult, ConflictSummary, DiffEntry, DiffOptions, DiffSummary,
13 OperationState, RefInfo, RefKind, RemoteInfo, RepositoryInfo, RepositorySnapshot,
14 RichWorktreeStatus, SnapshotRequest, SortOrder, StashDetail, StashEntry,
15 StatusDigest, StatusOptions, SubmoduleInfo, SubmoduleSummary, TagInfo, TreeEntry,
16 WorktreeDetail, WorktreeInfo, WorktreeStatus,
17};
18
19fn join_err(e: tokio::task::JoinError) -> EndringerError {
21 EndringerError::TaskJoin { message: e.to_string() }
22}
23
24#[derive(Clone)]
30pub struct AsyncRepository {
31 inner: Arc<Repository>,
32}
33
34impl AsyncRepository {
35 pub async fn open(path: &Path) -> Result<Self> {
37 let path = path.to_path_buf();
38 let inner = tokio::task::spawn_blocking(move || repository(&path))
39 .await
40 .map_err(join_err)??;
41 Ok(AsyncRepository { inner: Arc::new(inner) })
42 }
43
44 pub async fn open_jj(path: &Path) -> Result<Self> {
46 let path = path.to_path_buf();
47 let inner = tokio::task::spawn_blocking(move || jj_repository(&path))
48 .await
49 .map_err(join_err)??;
50 Ok(AsyncRepository { inner: Arc::new(inner) })
51 }
52
53 pub async fn status_digest(&self) -> Result<StatusDigest> {
56 let r = Arc::clone(&self.inner);
57 tokio::task::spawn_blocking(move || r.status_digest()).await.map_err(join_err)?
58 }
59
60 pub async fn local_branches(&self) -> Result<Vec<BranchInfo>> {
63 let r = Arc::clone(&self.inner);
64 tokio::task::spawn_blocking(move || r.local_branches()).await.map_err(join_err)?
65 }
66
67 pub async fn remote_branches(&self) -> Result<Vec<BranchInfo>> {
68 let r = Arc::clone(&self.inner);
69 tokio::task::spawn_blocking(move || r.remote_branches()).await.map_err(join_err)?
70 }
71
72 pub async fn list_commits(&self) -> Result<Vec<CommitInfo>> {
75 let r = Arc::clone(&self.inner);
76 tokio::task::spawn_blocking(move || r.list_commits()).await.map_err(join_err)?
77 }
78
79 pub async fn list_commits_sorted(&self, order: SortOrder) -> Result<Vec<CommitInfo>> {
80 let r = Arc::clone(&self.inner);
81 tokio::task::spawn_blocking(move || r.list_commits_sorted(order)).await.map_err(join_err)?
82 }
83
84 pub async fn log_since(&self, since: SystemTime, until: SystemTime) -> Result<Vec<CommitInfo>> {
85 let r = Arc::clone(&self.inner);
86 tokio::task::spawn_blocking(move || r.log_since(since, until)).await.map_err(join_err)?
87 }
88
89 pub async fn find_commit(&self, id: CommitId) -> Result<CommitInfo> {
90 let r = Arc::clone(&self.inner);
91 tokio::task::spawn_blocking(move || r.find_commit(&id)).await.map_err(join_err)?
92 }
93
94 pub async fn query_commits(&self, query: CommitQuery) -> Result<CommitQueryResult> {
95 let r = Arc::clone(&self.inner);
96 tokio::task::spawn_blocking(move || r.query_commits(query)).await.map_err(join_err)?
97 }
98
99 pub async fn list_tags(&self) -> Result<Vec<TagInfo>> {
102 let r = Arc::clone(&self.inner);
103 tokio::task::spawn_blocking(move || r.list_tags()).await.map_err(join_err)?
104 }
105
106 pub async fn list_tags_sorted(&self, order: SortOrder) -> Result<Vec<TagInfo>> {
107 let r = Arc::clone(&self.inner);
108 tokio::task::spawn_blocking(move || r.list_tags_sorted(order)).await.map_err(join_err)?
109 }
110
111 pub async fn create_tag(&self, name: String) -> Result<()> {
112 let r = Arc::clone(&self.inner);
113 tokio::task::spawn_blocking(move || r.create_tag(&name)).await.map_err(join_err)?
114 }
115
116 pub async fn create_annotated_tag(&self, name: String, message: String) -> Result<()> {
117 let r = Arc::clone(&self.inner);
118 tokio::task::spawn_blocking(move || r.create_annotated_tag(&name, &message)).await.map_err(join_err)?
119 }
120
121 pub async fn delete_tag(&self, name: String) -> Result<()> {
122 let r = Arc::clone(&self.inner);
123 tokio::task::spawn_blocking(move || r.delete_tag(&name)).await.map_err(join_err)?
124 }
125
126 pub async fn diff(&self, from: CommitId, to: CommitId) -> Result<DiffSummary> {
129 let r = Arc::clone(&self.inner);
130 tokio::task::spawn_blocking(move || r.diff(&from, &to)).await.map_err(join_err)?
131 }
132
133 pub async fn remote_url(&self, name: String) -> Result<Option<String>> {
136 let r = Arc::clone(&self.inner);
137 tokio::task::spawn_blocking(move || r.remote_url(&name))
138 .await
139 .map_err(join_err)?
140 }
141
142 pub async fn is_dirty(&self) -> Result<bool> {
145 let r = Arc::clone(&self.inner);
146 tokio::task::spawn_blocking(move || r.is_dirty()).await.map_err(join_err)?
147 }
148
149 pub async fn merge_base(&self, a: CommitId, b: CommitId) -> Result<Option<CommitId>> {
152 let r = Arc::clone(&self.inner);
153 tokio::task::spawn_blocking(move || r.merge_base(&a, &b)).await.map_err(join_err)?
154 }
155
156 pub async fn is_ancestor(&self, candidate: CommitId, descendant: CommitId) -> Result<bool> {
157 let r = Arc::clone(&self.inner);
158 tokio::task::spawn_blocking(move || r.is_ancestor(&candidate, &descendant)).await.map_err(join_err)?
159 }
160
161 pub async fn blame(&self, path: std::path::PathBuf) -> Result<Vec<BlameEntry>> {
164 let r = Arc::clone(&self.inner);
165 tokio::task::spawn_blocking(move || r.blame(&path)).await.map_err(join_err)?
166 }
167
168 pub async fn worktree_status(&self) -> Result<WorktreeStatus> {
169 let r = Arc::clone(&self.inner);
170 tokio::task::spawn_blocking(move || r.worktree_status()).await.map_err(join_err)?
171 }
172
173 pub async fn rich_worktree_status(&self, options: StatusOptions) -> Result<RichWorktreeStatus> {
174 let r = Arc::clone(&self.inner);
175 tokio::task::spawn_blocking(move || r.rich_worktree_status(options)).await.map_err(join_err)?
176 }
177
178 pub async fn file_at_commit(
179 &self,
180 path: std::path::PathBuf,
181 commit_id: CommitId,
182 ) -> Result<Vec<u8>> {
183 let r = Arc::clone(&self.inner);
184 tokio::task::spawn_blocking(move || r.file_at_commit(&path, &commit_id)).await.map_err(join_err)?
185 }
186
187 pub async fn submodules(&self) -> Result<Vec<SubmoduleInfo>> {
188 let r = Arc::clone(&self.inner);
189 tokio::task::spawn_blocking(move || r.submodules()).await.map_err(join_err)?
190 }
191
192 pub async fn stash_entries(&self) -> Result<Vec<StashEntry>> {
193 let r = Arc::clone(&self.inner);
194 tokio::task::spawn_blocking(move || r.stash_entries()).await.map_err(join_err)?
195 }
196
197 pub async fn worktrees(&self) -> Result<Vec<WorktreeInfo>> {
198 let r = Arc::clone(&self.inner);
199 tokio::task::spawn_blocking(move || r.worktrees()).await.map_err(join_err)?
200 }
201
202 pub async fn ahead_behind(
205 &self,
206 local: CommitId,
207 upstream: CommitId,
208 ) -> Result<AheadBehind> {
209 let r = Arc::clone(&self.inner);
210 tokio::task::spawn_blocking(move || r.ahead_behind(&local, &upstream)).await.map_err(join_err)?
211 }
212
213 pub async fn branch_ahead_behind(
214 &self,
215 branch: String,
216 ) -> Result<Option<AheadBehind>> {
217 let r = Arc::clone(&self.inner);
218 tokio::task::spawn_blocking(move || r.branch_ahead_behind(&branch)).await.map_err(join_err)?
219 }
220
221 pub async fn repository_info(&self) -> Result<RepositoryInfo> {
224 let r = Arc::clone(&self.inner);
225 tokio::task::spawn_blocking(move || r.repository_info()).await.map_err(join_err)?
226 }
227
228 pub async fn branch_tracking(&self, branch: String) -> Result<BranchTrackingInfo> {
231 let r = Arc::clone(&self.inner);
232 tokio::task::spawn_blocking(move || r.branch_tracking(&branch)).await.map_err(join_err)?
233 }
234
235 pub async fn local_branch_tracking(&self) -> Result<Vec<BranchTrackingInfo>> {
236 let r = Arc::clone(&self.inner);
237 tokio::task::spawn_blocking(move || r.local_branch_tracking()).await.map_err(join_err)?
238 }
239
240 pub async fn is_merged_into(&self, branch: String, target: String) -> Result<bool> {
241 let r = Arc::clone(&self.inner);
242 tokio::task::spawn_blocking(move || r.is_merged_into(&branch, &target)).await.map_err(join_err)?
243 }
244
245 pub async fn operation_state(&self) -> Result<OperationState> {
248 let r = Arc::clone(&self.inner);
249 tokio::task::spawn_blocking(move || r.operation_state()).await.map_err(join_err)?
250 }
251
252 pub async fn unmerged_paths(&self) -> Result<Vec<std::path::PathBuf>> {
253 let r = Arc::clone(&self.inner);
254 tokio::task::spawn_blocking(move || r.unmerged_paths()).await.map_err(join_err)?
255 }
256
257 pub async fn conflict_summary(&self) -> Result<ConflictSummary> {
258 let r = Arc::clone(&self.inner);
259 tokio::task::spawn_blocking(move || r.conflict_summary()).await.map_err(join_err)?
260 }
261
262 pub async fn blame_at(&self, path: std::path::PathBuf, commit_id: CommitId) -> Result<Vec<BlameEntry>> {
265 let r = Arc::clone(&self.inner);
266 tokio::task::spawn_blocking(move || r.blame_at(&path, &commit_id)).await.map_err(join_err)?
267 }
268
269 pub async fn tree_at_commit(&self, commit_id: CommitId) -> Result<Vec<TreeEntry>> {
270 let r = Arc::clone(&self.inner);
271 tokio::task::spawn_blocking(move || r.tree_at_commit(&commit_id)).await.map_err(join_err)?
272 }
273
274 pub async fn tree_at_path(&self, commit_id: CommitId, path: std::path::PathBuf) -> Result<Vec<TreeEntry>> {
275 let r = Arc::clone(&self.inner);
276 tokio::task::spawn_blocking(move || r.tree_at_path(&commit_id, &path)).await.map_err(join_err)?
277 }
278
279 pub async fn remotes(&self) -> Result<Vec<RemoteInfo>> {
282 let r = Arc::clone(&self.inner);
283 tokio::task::spawn_blocking(move || r.remotes()).await.map_err(join_err)?
284 }
285
286 pub async fn references(&self) -> Result<Vec<RefInfo>> {
287 let r = Arc::clone(&self.inner);
288 tokio::task::spawn_blocking(move || r.references()).await.map_err(join_err)?
289 }
290
291 pub async fn references_by_kind(&self, kind: RefKind) -> Result<Vec<RefInfo>> {
292 let r = Arc::clone(&self.inner);
293 tokio::task::spawn_blocking(move || r.references_by_kind(kind)).await.map_err(join_err)?
294 }
295
296 pub async fn submodule_summaries(&self) -> Result<Vec<SubmoduleSummary>> {
299 let r = Arc::clone(&self.inner);
300 tokio::task::spawn_blocking(move || r.submodule_summaries()).await.map_err(join_err)?
301 }
302
303 pub async fn stash_detail(&self, index: usize) -> Result<StashDetail> {
304 let r = Arc::clone(&self.inner);
305 tokio::task::spawn_blocking(move || r.stash_detail(index)).await.map_err(join_err)?
306 }
307
308 pub async fn stash_diff(&self, index: usize) -> Result<DiffSummary> {
309 let r = Arc::clone(&self.inner);
310 tokio::task::spawn_blocking(move || r.stash_diff(index)).await.map_err(join_err)?
311 }
312
313 pub async fn worktree_details(&self) -> Result<Vec<WorktreeDetail>> {
314 let r = Arc::clone(&self.inner);
315 tokio::task::spawn_blocking(move || r.worktree_details()).await.map_err(join_err)?
316 }
317
318 pub async fn snapshot(&self, request: SnapshotRequest) -> Result<RepositorySnapshot> {
319 let r = Arc::clone(&self.inner);
320 tokio::task::spawn_blocking(move || r.snapshot(request)).await.map_err(join_err)?
321 }
322
323 pub async fn diff_entries(&self, from: CommitId, to: CommitId, options: DiffOptions) -> Result<Vec<DiffEntry>> {
324 let r = Arc::clone(&self.inner);
325 tokio::task::spawn_blocking(move || r.diff_entries(&from, &to, options)).await.map_err(join_err)?
326 }
327}