jacquardSnapshot

← snapshot

2298 bytes
//! The git bridge: jacquard repos remain clonable, pushable git repos.
//!
//! # Shape
//!
//! [`GitInterop`] is the port a real adapter (libgit2, gitoxide, or the git
//! CLI) will implement. The milestone-1 adapter is [`FakeGit`], which proves
//! the property that matters before any real plumbing exists: **a snapshot
//! exported to a git-shaped image and imported back yields the identical
//! [`SnapshotId`]** — because provenance, author, and timestamp ride in
//! commit trailers rather than in a side channel that a round trip would
//! drop.
//!
//! Trailers follow the git convention (`Key: value` lines at the end of the
//! commit message), so `git interpret-trailers` and every tool built on it
//! work unmodified on an exported repo.

pub mod fake;
pub mod image;

pub use fake::FakeGit;
pub use image::{GitCommitImage, TrailerKey};
use jac_core::SnapshotId;
use jac_object::{ObjectError, ObjectStore};
use thiserror::Error;

/// Failures crossing the bridge.
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum GitError {
    /// A referenced object could not be read from the store.
    #[error("object store error: {0}")]
    Store(#[from] ObjectError),
    /// An image's trailers were missing or unparseable.
    #[error("cannot reconstruct snapshot: {reason}")]
    MalformedImage {
        /// What was wrong.
        reason: &'static str,
    },
    /// A tree entry name or path in the image was invalid.
    #[error("invalid path in image")]
    InvalidPath,
}

/// How snapshots cross to git and back.
pub trait GitInterop {
    /// Renders a snapshot as a git-commit-shaped image.
    ///
    /// # Errors
    ///
    /// Returns [`GitError::Store`] if the snapshot or its tree cannot be
    /// read.
    fn export(
        &mut self,
        id: SnapshotId,
        store: &dyn ObjectStore,
    ) -> Result<GitCommitImage, GitError>;

    /// Reconstructs a snapshot from an image, writing objects into `store`.
    ///
    /// # Errors
    ///
    /// Returns [`GitError::MalformedImage`] if required trailers are absent
    /// or unparseable, or [`GitError::InvalidPath`] on a bad manifest path.
    fn import(
        &mut self,
        image: &GitCommitImage,
        store: &mut dyn ObjectStore,
    ) -> Result<SnapshotId, GitError>;
}