Skip to main content

endringer_async/
async_api.rs

1//! [`AsyncRepository`] — async wrapper around [`endringer::repository::Repository`].
2
3use std::path::Path;
4use std::sync::Arc;
5use std::time::SystemTime;
6
7use anyhow::Result;
8use endringer::repository::{Repository, jj_repository, repository};
9use endringer::{BranchInfo, CommitId, CommitInfo, DiffSummary, SortOrder, StatusDigest, TagInfo};
10
11/// Async wrapper around [`Repository`].
12///
13/// Cloneable. Each method clones the inner `Arc<Repository>` and dispatches
14/// to `tokio::task::spawn_blocking` so that blocking VCS I/O does not stall
15/// the async executor.
16#[derive(Clone)]
17pub struct AsyncRepository {
18    inner: Arc<Repository>,
19}
20
21impl AsyncRepository {
22    /// Opens a Git repository at `path`.
23    pub async fn open(path: &Path) -> Result<Self> {
24        let path = path.to_path_buf();
25        let inner = tokio::task::spawn_blocking(move || repository(&path)).await??;
26        Ok(AsyncRepository { inner: Arc::new(inner) })
27    }
28
29    /// Opens a Jujutsu repository at `path`.
30    pub async fn open_jj(path: &Path) -> Result<Self> {
31        let path = path.to_path_buf();
32        let inner = tokio::task::spawn_blocking(move || jj_repository(&path)).await??;
33        Ok(AsyncRepository { inner: Arc::new(inner) })
34    }
35
36    // ── Status ─────────────────────────────────────────────────────────── //
37
38    pub async fn status_digest(&self) -> Result<StatusDigest> {
39        let r = Arc::clone(&self.inner);
40        tokio::task::spawn_blocking(move || r.status_digest()).await?
41    }
42
43    // ── Branches ───────────────────────────────────────────────────────── //
44
45    pub async fn local_branches(&self) -> Result<Vec<BranchInfo>> {
46        let r = Arc::clone(&self.inner);
47        tokio::task::spawn_blocking(move || r.local_branches()).await?
48    }
49
50    pub async fn remote_branches(&self) -> Result<Vec<BranchInfo>> {
51        let r = Arc::clone(&self.inner);
52        tokio::task::spawn_blocking(move || r.remote_branches()).await?
53    }
54
55    // ── Commits ────────────────────────────────────────────────────────── //
56
57    pub async fn list_commits(&self) -> Result<Vec<CommitInfo>> {
58        let r = Arc::clone(&self.inner);
59        tokio::task::spawn_blocking(move || r.list_commits()).await?
60    }
61
62    pub async fn list_commits_sorted(&self, order: SortOrder) -> Result<Vec<CommitInfo>> {
63        let r = Arc::clone(&self.inner);
64        tokio::task::spawn_blocking(move || r.list_commits_sorted(order)).await?
65    }
66
67    pub async fn log_since(&self, since: SystemTime, until: SystemTime) -> Result<Vec<CommitInfo>> {
68        let r = Arc::clone(&self.inner);
69        tokio::task::spawn_blocking(move || r.log_since(since, until)).await?
70    }
71
72    pub async fn find_commit(&self, id: CommitId) -> Result<CommitInfo> {
73        let r = Arc::clone(&self.inner);
74        tokio::task::spawn_blocking(move || r.find_commit(&id)).await?
75    }
76
77    // ── Tags ───────────────────────────────────────────────────────────── //
78
79    pub async fn list_tags(&self) -> Result<Vec<TagInfo>> {
80        let r = Arc::clone(&self.inner);
81        tokio::task::spawn_blocking(move || r.list_tags()).await?
82    }
83
84    pub async fn list_tags_sorted(&self, order: SortOrder) -> Result<Vec<TagInfo>> {
85        let r = Arc::clone(&self.inner);
86        tokio::task::spawn_blocking(move || r.list_tags_sorted(order)).await?
87    }
88
89    pub async fn create_tag(&self, name: String) -> Result<()> {
90        let r = Arc::clone(&self.inner);
91        tokio::task::spawn_blocking(move || r.create_tag(&name)).await?
92    }
93
94    pub async fn create_annotated_tag(&self, name: String, message: String) -> Result<()> {
95        let r = Arc::clone(&self.inner);
96        tokio::task::spawn_blocking(move || r.create_annotated_tag(&name, &message)).await?
97    }
98
99    pub async fn delete_tag(&self, name: String) -> Result<()> {
100        let r = Arc::clone(&self.inner);
101        tokio::task::spawn_blocking(move || r.delete_tag(&name)).await?
102    }
103
104    // ── Diff ───────────────────────────────────────────────────────────── //
105
106    pub async fn diff(&self, from: CommitId, to: CommitId) -> Result<DiffSummary> {
107        let r = Arc::clone(&self.inner);
108        tokio::task::spawn_blocking(move || r.diff(&from, &to)).await?
109    }
110
111    // ── Remotes ────────────────────────────────────────────────────────── //
112
113    pub async fn remote_url(&self, name: String) -> Option<String> {
114        let r = Arc::clone(&self.inner);
115        tokio::task::spawn_blocking(move || r.remote_url(&name))
116            .await
117            .ok()
118            .flatten()
119    }
120
121    // ── Working tree ───────────────────────────────────────────────────── //
122
123    pub async fn is_dirty(&self) -> Result<bool> {
124        let r = Arc::clone(&self.inner);
125        tokio::task::spawn_blocking(move || r.is_dirty()).await?
126    }
127}