auths_infra_git/
blob_store.rs1use auths_core::ports::storage::{BlobReader, BlobWriter, StorageError};
2
3use crate::error::map_git2_error;
4use crate::helpers;
5use crate::repo::GitRepo;
6
7const BLOB_FILE: &str = "data";
8
9pub struct GitBlobStore<'r> {
25 repo: &'r GitRepo,
26}
27
28impl<'r> GitBlobStore<'r> {
29 pub fn new(repo: &'r GitRepo) -> Self {
30 Self { repo }
31 }
32
33 fn ref_for_path(path: &str) -> String {
34 format!("refs/auths/blobs/{}", path)
35 }
36}
37
38impl BlobReader for GitBlobStore<'_> {
39 fn get_blob(&self, path: &str) -> Result<Vec<u8>, StorageError> {
40 let refname = Self::ref_for_path(path);
41 self.repo.with_repo(|repo| {
42 let oid = helpers::resolve_git_ref(repo, &refname).map_err(map_git2_error)?;
43 let commit = repo.find_commit(oid).map_err(map_git2_error)?;
44 let tree_oid = commit.tree_id();
45 helpers::extract_blob_payload(repo, tree_oid, BLOB_FILE).map_err(map_git2_error)
46 })
47 }
48
49 fn list_blobs(&self, prefix: &str) -> Result<Vec<String>, StorageError> {
50 let glob = format!("refs/auths/blobs/{}*", prefix);
51 self.repo.with_repo(|repo| {
52 let refs = helpers::list_refs_matching(repo, &glob).map_err(map_git2_error)?;
53 let strip_prefix = "refs/auths/blobs/";
54 Ok(refs
55 .into_iter()
56 .filter_map(|r| r.strip_prefix(strip_prefix).map(String::from))
57 .collect())
58 })
59 }
60
61 fn blob_exists(&self, path: &str) -> Result<bool, StorageError> {
62 let refname = Self::ref_for_path(path);
63 self.repo
64 .with_repo(|repo| match repo.find_reference(&refname) {
65 Ok(_) => Ok(true),
66 Err(e) if e.code() == git2::ErrorCode::NotFound => Ok(false),
67 Err(e) => Err(map_git2_error(e)),
68 })
69 }
70}
71
72impl BlobWriter for GitBlobStore<'_> {
73 fn put_blob(&self, path: &str, data: &[u8]) -> Result<(), StorageError> {
74 let refname = Self::ref_for_path(path);
75 self.repo.with_repo(|repo| {
76 helpers::create_ref_commit(
77 repo,
78 &refname,
79 data,
80 BLOB_FILE,
81 &format!("put blob {}", path),
82 )
83 .map_err(map_git2_error)?;
84 Ok(())
85 })
86 }
87
88 fn delete_blob(&self, path: &str) -> Result<(), StorageError> {
89 let refname = Self::ref_for_path(path);
90 self.repo
91 .with_repo(|repo| match repo.find_reference(&refname) {
92 Ok(mut r) => {
93 r.delete().map_err(map_git2_error)?;
94 Ok(())
95 }
96 Err(e) if e.code() == git2::ErrorCode::NotFound => Ok(()),
97 Err(e) => Err(map_git2_error(e)),
98 })
99 }
100}