auths_infra_git/repo.rs
1use auths_core::ports::storage::StorageError;
2use git2::Repository;
3use std::path::{Path, PathBuf};
4use std::sync::Mutex;
5
6/// Newtype wrapper around `git2::Repository`.
7///
8/// Wraps the repository in a `Mutex` to satisfy `Send + Sync` bounds
9/// required by the storage port traits, since `git2::Repository` is
10/// not `Sync` by default.
11///
12/// Usage:
13/// ```ignore
14/// use auths_infra_git::GitRepo;
15///
16/// let repo = GitRepo::open("/path/to/repo")?;
17/// ```
18pub struct GitRepo {
19 inner: Mutex<Repository>,
20 path: PathBuf,
21}
22
23impl GitRepo {
24 /// Opens an existing Git repository at the given path.
25 ///
26 /// Args:
27 /// * `path`: Filesystem path to the repository root.
28 ///
29 /// Usage:
30 /// ```ignore
31 /// let repo = GitRepo::open("/home/user/.auths")?;
32 /// ```
33 pub fn open(path: impl AsRef<Path>) -> Result<Self, StorageError> {
34 let path = path.as_ref().to_path_buf();
35 let inner = Repository::open(&path).map_err(|e| StorageError::Io(e.to_string()))?;
36 Ok(Self {
37 inner: Mutex::new(inner),
38 path,
39 })
40 }
41
42 /// Initializes a new Git repository at the given path.
43 ///
44 /// Args:
45 /// * `path`: Filesystem path where the repository will be created.
46 ///
47 /// Usage:
48 /// ```ignore
49 /// let repo = GitRepo::init("/tmp/new-repo")?;
50 /// ```
51 pub fn init(path: impl AsRef<Path>) -> Result<Self, StorageError> {
52 let path = path.as_ref().to_path_buf();
53 let inner = Repository::init(&path).map_err(|e| StorageError::Io(e.to_string()))?;
54 Ok(Self {
55 inner: Mutex::new(inner),
56 path,
57 })
58 }
59
60 pub(crate) fn with_repo<T>(
61 &self,
62 f: impl FnOnce(&Repository) -> Result<T, StorageError>,
63 ) -> Result<T, StorageError> {
64 let repo = self
65 .inner
66 .lock()
67 .map_err(|e| StorageError::Io(format!("mutex poisoned: {}", e)))?;
68 f(&repo)
69 }
70
71 pub fn path(&self) -> &Path {
72 &self.path
73 }
74}