1pub mod git_tree;
10
11use std::path::PathBuf;
12
13pub use memstead_base::storage::{CommitId, MemWriter, MemWriterError};
14
15#[cfg(feature = "git-object-storage")]
21pub fn git_tree_mem_writer(gitdir: PathBuf, ref_name: String) -> Box<dyn MemWriter> {
22 Box::new(git_tree::GitTreeMemWriter::new(gitdir, ref_name))
23}
24
25pub fn instantiate_full_backend(
37 mount: &memstead_base::Mount,
38) -> Result<Box<dyn memstead_base::MemBackend>, memstead_base::InstantiateError> {
39 use memstead_base::MountStorage;
40 match &mount.storage {
41 MountStorage::Folder { .. } | MountStorage::Archive { .. } | MountStorage::InMemory => {
42 memstead_base::instantiate_lean_backend(mount)
43 }
44 MountStorage::GitBranch { gitdir, branch } => {
45 let ref_name = if branch.starts_with("refs/") {
46 branch.clone()
47 } else {
48 format!("refs/heads/{branch}")
49 };
50 Ok(Box::new(git_tree::GitTreeMemWriter::new(
51 gitdir.clone(),
52 ref_name,
53 )))
54 }
55 }
56}
57
58pub const FULL_GIT_BRANCH_OPS: memstead_base::GitBranchOps = memstead_base::GitBranchOps {
64 changes_since: changes_since_dispatch,
65 diff: diff_dispatch,
66 branch_reset: branch_reset_dispatch,
67 fetch: fetch_dispatch,
68 pull: pull_dispatch,
69 push: push_dispatch,
70 remote_add: remote_add_dispatch,
71 read_tree: read_tree_dispatch,
72 export: export_dispatch,
73 export_to_bytes: export_to_bytes_dispatch,
74 prune_residue: prune_residue_dispatch,
75 rename_mem_storage: rename_mem_storage_dispatch,
76 write_schema: write_schema_dispatch,
77 read_schema_file: read_schema_file_dispatch,
78 read_ref_schemas: read_ref_schemas_dispatch,
79};
80
81fn write_schema_dispatch(
85 gitdir: &std::path::Path,
86 name: &str,
87 version: &str,
88 files: &[(String, Vec<u8>)],
89) -> Result<String, memstead_base::backend::BackendError> {
90 crate::storage_memstead::write_schema_to_memstead_ref(gitdir, name, version, files)
91 .map(|outcome| outcome.commit_sha)
92 .map_err(|e| {
93 memstead_base::backend::BackendError::Other(format!(
94 "schema install onto __MEMSTEAD ref at {}: {e}",
95 gitdir.display(),
96 ))
97 })
98}
99
100fn read_ref_schemas_dispatch(
104 workspace_root: &std::path::Path,
105) -> Result<Vec<std::sync::Arc<memstead_schema::Schema>>, memstead_base::backend::BackendError> {
106 use crate::mem_repo_schemas::LoadOutcome;
107 match crate::mem_repo_schemas::load_schemas_from_ref(workspace_root) {
108 Ok(LoadOutcome::Schemas(schemas)) => Ok(schemas),
109 Ok(_) => Ok(Vec::new()),
110 Err(e) => Err(memstead_base::backend::BackendError::Other(format!(
111 "schema re-read from __MEMSTEAD ref at {}: {e}",
112 workspace_root.display(),
113 ))),
114 }
115}
116
117fn read_schema_file_dispatch(
121 gitdir: &std::path::Path,
122 name: &str,
123 version: &str,
124 rel: &str,
125) -> Result<Option<Vec<u8>>, memstead_base::backend::BackendError> {
126 crate::storage_memstead::read_schema_file_from_memstead_ref(gitdir, name, version, rel).map_err(
127 |e| {
128 memstead_base::backend::BackendError::Other(format!(
129 "schema file read from __MEMSTEAD ref at {}: {e}",
130 gitdir.display(),
131 ))
132 },
133 )
134}
135
136fn prune_residue_dispatch(
146 gitdir: &std::path::Path,
147 branch_full_path: &str,
148) -> Result<(), memstead_base::backend::BackendError> {
149 let ctx = memstead_base::vcs::CommitContext {
150 actor: memstead_base::vcs::Actor::Agent,
151 client: None,
152 tool: Some("memstead_mem_create (force_overwrite)"),
153 note: None,
154 role: Default::default(),
155 logical_operation_id: None,
156 entity_ids: None,
157 };
158 crate::storage_memstead::delete_mem_artifacts_at_gitdir(gitdir, branch_full_path, &ctx).map_err(
159 |e| {
160 memstead_base::backend::BackendError::Other(format!(
161 "force_overwrite prune at {}: {e}",
162 branch_full_path,
163 ))
164 },
165 )
166}
167
168fn rename_mem_storage_dispatch(
172 gitdir: &std::path::Path,
173 old_leaf: &str,
174 new_leaf: &str,
175) -> Result<(), memstead_base::backend::BackendError> {
176 let ctx = memstead_base::vcs::CommitContext {
177 actor: memstead_base::vcs::Actor::Agent,
178 client: None,
179 tool: Some("memstead mem rename"),
180 note: None,
181 role: Default::default(),
182 logical_operation_id: None,
183 entity_ids: None,
184 };
185 crate::storage_memstead::rename_mem_artifacts_at_gitdir(gitdir, old_leaf, new_leaf, &ctx)
186 .map_err(|e| {
187 memstead_base::backend::BackendError::Other(format!(
188 "mem rename {old_leaf} -> {new_leaf}: {e}",
189 ))
190 })
191}
192
193fn changes_since_dispatch(
194 gitdir: &std::path::Path,
195 branch: &str,
196 mem: &str,
197 since: &str,
198 rename_similarity: f32,
199) -> Result<memstead_base::ops::BackendChanges, memstead_base::backend::BackendError> {
200 let ref_name = if branch.starts_with("refs/") {
201 branch.to_string()
202 } else {
203 format!("refs/heads/{branch}")
204 };
205 let empty_store = memstead_base::Store::new();
206 let report = crate::ops::changes::changes_since(
207 &empty_store,
208 mem,
209 gitdir,
210 since,
211 rename_similarity,
212 Some(&ref_name),
213 )
214 .map_err(|e| {
215 match e {
221 crate::vcs::VcsError::ObjectNotFound(_) => {
222 memstead_base::backend::BackendError::Other(format!("COMMIT_NOT_FOUND:{since}"))
223 }
224 other => memstead_base::backend::BackendError::Other(format!(
225 "git-branch changes_since: {other}"
226 )),
227 }
228 })?;
229 Ok(memstead_base::ops::BackendChanges {
230 since: report.since,
231 head: report.head,
232 changes: report.changes,
233 notes: report.notes.unwrap_or_default(),
234 memstead_ref: report.memstead_ref,
235 })
236}
237
238#[allow(clippy::too_many_arguments)]
241fn export_dispatch(
242 gitdir: &std::path::Path,
243 branch: &str,
244 mem: &str,
245 config: &memstead_schema::MemConfig,
246 output_path: &std::path::Path,
247 workspace_root: Option<&std::path::Path>,
248 workspace_schemas_dir: Option<&std::path::Path>,
249 provenance_bytes: Option<&[u8]>,
250 anchors_bytes: Option<&[u8]>,
251) -> Result<memstead_base::ops::MemExportResult, memstead_base::backend::BackendError> {
252 let _ = branch;
253 crate::ops::export::export_mem_from_branch(
254 gitdir,
255 mem,
256 config,
257 output_path,
258 workspace_root,
259 workspace_schemas_dir,
260 provenance_bytes,
261 anchors_bytes,
262 )
263 .map_err(|e| {
264 memstead_base::backend::BackendError::Other(format!("export_mem_from_branch: {e}"))
265 })
266}
267
268fn read_tree_dispatch(
269 gitdir: &std::path::Path,
270 ref_name: &str,
271) -> Result<Vec<(String, String)>, memstead_base::backend::BackendError> {
272 #[cfg(feature = "git-object-storage")]
273 {
274 crate::ops::transport::read_md_blobs_at_ref(gitdir, ref_name)
275 }
276 #[cfg(not(feature = "git-object-storage"))]
277 {
278 let _ = (gitdir, ref_name);
279 Err(memstead_base::backend::BackendError::Other(
280 "read_tree: git-object-storage feature not enabled".to_string(),
281 ))
282 }
283}
284
285fn fetch_dispatch(
286 gitdir: &std::path::Path,
287 remote: &str,
288 refspecs: &[String],
289) -> Result<memstead_base::ops::FetchOutcome, memstead_base::backend::BackendError> {
290 #[cfg(feature = "git-object-storage")]
291 {
292 crate::ops::transport::fetch_in_gitdir(gitdir, remote, refspecs)
293 }
294 #[cfg(not(feature = "git-object-storage"))]
295 {
296 let _ = (gitdir, remote, refspecs);
297 Err(memstead_base::backend::BackendError::Other(
298 "fetch: git-object-storage feature not enabled".to_string(),
299 ))
300 }
301}
302
303fn pull_dispatch(
304 gitdir: &std::path::Path,
305 remote: &str,
306 mem: &str,
307) -> Result<memstead_base::ops::PullOutcome, memstead_base::backend::BackendError> {
308 #[cfg(feature = "git-object-storage")]
309 {
310 crate::ops::transport::pull_in_gitdir(gitdir, remote, mem)
311 }
312 #[cfg(not(feature = "git-object-storage"))]
313 {
314 let _ = (gitdir, remote, mem);
315 Err(memstead_base::backend::BackendError::Other(
316 "pull: git-object-storage feature not enabled".to_string(),
317 ))
318 }
319}
320
321fn push_dispatch(
322 gitdir: &std::path::Path,
323 remote: &str,
324 mem: &str,
325 force: bool,
326) -> Result<memstead_base::ops::PushOutcome, memstead_base::backend::BackendError> {
327 #[cfg(feature = "git-object-storage")]
328 {
329 crate::ops::transport::push_in_gitdir(gitdir, remote, mem, force)
330 }
331 #[cfg(not(feature = "git-object-storage"))]
332 {
333 let _ = (gitdir, remote, mem, force);
334 Err(memstead_base::backend::BackendError::Other(
335 "push: git-object-storage feature not enabled".to_string(),
336 ))
337 }
338}
339
340fn remote_add_dispatch(
341 gitdir: &std::path::Path,
342 name: &str,
343 url: &str,
344) -> Result<memstead_base::ops::RemoteAddOutcome, memstead_base::backend::BackendError> {
345 #[cfg(feature = "git-object-storage")]
346 {
347 crate::ops::transport::remote_add_in_gitdir(gitdir, name, url)
348 }
349 #[cfg(not(feature = "git-object-storage"))]
350 {
351 let _ = (gitdir, name, url);
352 Err(memstead_base::backend::BackendError::Other(
353 "remote_add: git-object-storage feature not enabled".to_string(),
354 ))
355 }
356}
357
358fn branch_reset_dispatch(
359 gitdir: &std::path::Path,
360 branch: &str,
361 target_sha: &str,
362 expected_head: Option<&str>,
363) -> Result<memstead_base::ops::BranchResetOutcome, memstead_base::backend::BackendError> {
364 #[cfg(feature = "git-object-storage")]
365 {
366 crate::ops::branch_reset::branch_reset_in_gitdir(gitdir, branch, target_sha, expected_head)
367 }
368 #[cfg(not(feature = "git-object-storage"))]
369 {
370 let _ = (gitdir, branch, target_sha);
371 Err(memstead_base::backend::BackendError::Other(
372 "branch_reset: git-object-storage feature not enabled".to_string(),
373 ))
374 }
375}
376
377fn diff_dispatch(
378 gitdir: &std::path::Path,
379 mem: &str,
380 ref_a: &str,
381 ref_b: &str,
382 config: &memstead_base::ops::DiffConfig,
383) -> Result<memstead_base::ops::Diff, memstead_base::backend::BackendError> {
384 #[cfg(feature = "git-object-storage")]
385 {
386 crate::ops::diff::diff_two_refs(gitdir, mem, ref_a, ref_b, config)
387 }
388 #[cfg(not(feature = "git-object-storage"))]
389 {
390 let _ = (gitdir, mem, ref_a, ref_b, config);
391 Err(memstead_base::backend::BackendError::Other(
392 "diff_two_refs: git-object-storage feature not enabled".to_string(),
393 ))
394 }
395}
396
397#[allow(clippy::too_many_arguments)]
398fn export_to_bytes_dispatch(
399 gitdir: &std::path::Path,
400 branch: &str,
401 mem: &str,
402 config: &memstead_schema::MemConfig,
403 workspace_root: Option<&std::path::Path>,
404 workspace_schemas_dir: Option<&std::path::Path>,
405 provenance_bytes: Option<&[u8]>,
406 anchors_bytes: Option<&[u8]>,
407) -> Result<memstead_base::ops::MemExportBytes, memstead_base::backend::BackendError> {
408 let _ = branch;
409 crate::ops::export::export_mem_from_branch_to_bytes(
410 gitdir,
411 mem,
412 config,
413 workspace_root,
414 workspace_schemas_dir,
415 provenance_bytes,
416 anchors_bytes,
417 )
418 .map_err(|e| {
419 memstead_base::backend::BackendError::Other(format!("export_mem_from_branch_to_bytes: {e}"))
420 })
421}