Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
storage/refs/sigrefs: migrate object::Writer to ObjectWriter
Fintan Halpenny committed 24 days ago
commit 1556131936a632adc06e4ad4e0984b80ae7b0ec0
parent 5aadb262b301b30eaca3a70eceb1c06c6a6213f1
6 files changed +83 -104
modified crates/radicle/src/storage/refs.rs
@@ -19,7 +19,7 @@ use thiserror::Error;
use crate::git;
use crate::git::Oid;
use crate::git::raw::ErrorExt as _;
-
use crate::git::repository::{ObjectReader, RefReader};
+
use crate::git::repository::{ObjectReader, ObjectWriter, RefReader};
use crate::storage;
use crate::storage::RemoteId;
use crate::storage::refs::sigrefs::read::Tip;
@@ -79,8 +79,8 @@ impl Refs {
        signer: &S,
    ) -> Result<SignedRefs, Error>
    where
-
        R: ObjectReader + sigrefs::git::object::Writer,
        R: RefReader + sigrefs::git::reference::Writer,
+
        R: ObjectReader + ObjectWriter,
        R: HasRepoId,
        S: signature::Signer<crypto::Signature>,
        S: signature::Verifier<crypto::Signature>,
@@ -97,8 +97,8 @@ impl Refs {
        signer: &S,
    ) -> Result<SignedRefs, Error>
    where
-
        R: ObjectReader + sigrefs::git::object::Writer,
        R: RefReader + sigrefs::git::reference::Writer,
+
        R: ObjectReader + ObjectWriter,
        R: HasRepoId,
        S: signature::Signer<crypto::Signature>,
        S: signature::Verifier<crypto::Signature>,
@@ -115,8 +115,8 @@ impl Refs {
        force: bool,
    ) -> Result<SignedRefs, Error>
    where
-
        R: ObjectReader + sigrefs::git::object::Writer,
        R: RefReader + sigrefs::git::reference::Writer,
+
        R: ObjectReader + ObjectWriter,
        R: HasRepoId,
        S: signature::Signer<crypto::Signature>,
        S: signature::Verifier<crypto::Signature>,
modified crates/radicle/src/storage/refs/sigrefs/git.rs
@@ -180,31 +180,11 @@ mod git2_impls {
            refs: RefsEntry,
            signature: SignatureEntry,
        ) -> Result<Oid, object::error::WriteTree> {
-
            use object::error::WriteTree;
-

-
            let odb = self.odb().map_err(WriteTree::write_error)?;
-

-
            let refs_oid = odb
-
                .write(git2::ObjectType::Blob, &refs.content)
-
                .map_err(WriteTree::refs_error)?;
-

-
            let sig_oid = odb
-
                .write(git2::ObjectType::Blob, &signature.content)
-
                .map_err(WriteTree::signature_error)?;
-

-
            let mut builder = self.treebuilder(None).map_err(WriteTree::write_error)?;
-

-
            builder
-
                .insert(&refs.path, refs_oid, git2::FileMode::Blob.into())
-
                .map_err(WriteTree::refs_error)?;
-

-
            builder
-
                .insert(&signature.path, sig_oid, git2::FileMode::Blob.into())
-
                .map_err(WriteTree::signature_error)?;
-

-
            let tree_oid = builder.write().map_err(WriteTree::write_error)?;
-

-
            Ok(Oid::from(tree_oid))
+
            crate::git::repository::ObjectWriter::write_tree(
+
                self,
+
                &[refs.into_inner(), signature.into_inner()],
+
            )
+
            .map_err(|e| object::error::WriteTree::Write(Box::new(e)))
        }

        fn write_commit(&self, bytes: &[u8]) -> Result<Oid, object::error::WriteCommit> {
modified crates/radicle/src/storage/refs/sigrefs/git/object.rs
@@ -6,10 +6,12 @@

pub mod error;

-
use std::path::{Path, PathBuf};
+
use std::path::Path;

use radicle_oid::Oid;

+
use crate::git::repository::types::TreeEntry;
+

/// A Git blob object, returned by [`Reader::read_blob`].
pub struct Blob {
    /// The [`Oid`] of the Git blob.
@@ -46,30 +48,42 @@ pub trait Reader {
    fn read_blob(&self, commit: &Oid, path: &Path) -> Result<Option<Blob>, error::ReadBlob>;
}

-
/// Input to the [`Writer::write_tree`] method.
-
///
-
/// The entry describes where in the Git tree to write the [`Refs`] content
-
/// blob.
-
///
-
/// [`Refs`]: crate::storage::refs::Refs
+
/// A [`TreeEntry`] for the signed references payload blob.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-
pub struct RefsEntry {
-
    /// Path in the Git tree to write to.
-
    pub path: PathBuf,
-
    /// The contents of the Git blob.
-
    pub content: Vec<u8>,
+
pub struct RefsEntry(TreeEntry);
+

+
impl RefsEntry {
+
    /// Create a new entry with the canonical refs bytes.
+
    pub fn new(content: Vec<u8>) -> Self {
+
        Self(TreeEntry::Blob {
+
            path: Path::new(crate::storage::refs::REFS_BLOB_PATH).into(),
+
            content,
+
        })
+
    }
+

+
    /// Unwrap into the underlying [`TreeEntry`].
+
    pub fn into_inner(self) -> TreeEntry {
+
        self.0
+
    }
}

-
/// Input to the [`Writer::write_tree`] method.
-
///
-
/// The entry describes where in the Git tree to write the signature content
-
/// blob.
+
/// A [`TreeEntry`] for the cryptographic signature blob.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-
pub struct SignatureEntry {
-
    /// Path in the Git tree to write to.
-
    pub path: PathBuf,
-
    /// The contents of the Git blob.
-
    pub content: Vec<u8>,
+
pub struct SignatureEntry(TreeEntry);
+

+
impl SignatureEntry {
+
    /// Create a new entry with the signature bytes.
+
    pub fn new(content: Vec<u8>) -> Self {
+
        Self(TreeEntry::Blob {
+
            path: Path::new(crate::storage::refs::SIGNATURE_BLOB_PATH).into(),
+
            content,
+
        })
+
    }
+

+
    /// Unwrap into the underlying [`TreeEntry`].
+
    pub fn into_inner(self) -> TreeEntry {
+
        self.0
+
    }
}

/// Git object writer, generally a Git repository, or its corresponding Object
modified crates/radicle/src/storage/refs/sigrefs/write.rs
@@ -3,8 +3,6 @@ pub mod error;
#[cfg(test)]
mod test;

-
use std::path::Path;
-

use crypto::PublicKey;
use crypto::signature::{self, Signer};
use radicle_core::{NodeId, RepoId};
@@ -13,15 +11,12 @@ use radicle_git_metadata::commit::{CommitData, headers::Headers, trailers::Owned
use radicle_oid::Oid;

use crate::git;
-
use crate::git::repository::{ObjectReader, RefReader};
+
use crate::git::repository::{ObjectReader, ObjectWriter, RefReader};
use crate::storage::refs::SignedRefs;
use crate::storage::refs::sigrefs::git::{Committer, object, reference};
use crate::storage::refs::sigrefs::read::CommitReader;
use crate::storage::refs::sigrefs::{VerifiedCommit, read};
-
use crate::storage::refs::{
-
    FeatureLevel, IDENTITY_ROOT, REFS_BLOB_PATH, Refs, SIGNATURE_BLOB_PATH, SIGREFS_BRANCH,
-
    SIGREFS_PARENT,
-
};
+
use crate::storage::refs::{FeatureLevel, IDENTITY_ROOT, Refs, SIGREFS_BRANCH, SIGREFS_PARENT};

/// The result of attempting to write signed references using
/// [`SignedRefsWriter`].
@@ -73,7 +68,7 @@ pub struct SignedRefsWriter<'a, R, S> {

impl<'a, R, S> SignedRefsWriter<'a, R, S>
where
-
    R: object::Writer + ObjectReader + reference::Writer + RefReader,
+
    R: ObjectWriter + ObjectReader + reference::Writer + RefReader,
    S: Signer<crypto::Signature>,
    S: signature::Verifier<crypto::Signature>,
{
@@ -228,7 +223,7 @@ struct CommitWriter<'a, R, S> {

impl<'a, R, S> CommitWriter<'a, R, S>
where
-
    R: object::Writer,
+
    R: ObjectWriter,
    S: Signer<crypto::Signature>,
{
    fn root(refs: Refs, author: Author, message: String, repository: &'a R, signer: &'a S) -> Self {
@@ -311,7 +306,7 @@ struct TreeWriter<'a, R, S> {

impl<'a, R, S> TreeWriter<'a, R, S>
where
-
    R: object::Writer,
+
    R: ObjectWriter,
    S: Signer<crypto::Signature>,
{
    fn new(refs: Refs, repository: &'a R, signer: &'a S) -> Self {
@@ -328,17 +323,11 @@ where
            .signer
            .try_sign(&canonical)
            .map_err(error::Tree::Sign)?;
-
        let refs = object::RefsEntry {
-
            path: Path::new(REFS_BLOB_PATH).to_path_buf(),
-
            content: canonical,
-
        };
-
        let sig = object::SignatureEntry {
-
            path: Path::new(SIGNATURE_BLOB_PATH).to_path_buf(),
-
            content: signature.to_vec(),
-
        };
+
        let refs = object::RefsEntry::new(canonical);
+
        let sig = object::SignatureEntry::new(signature.to_vec());
        let oid = self
            .repository
-
            .write_tree(refs, sig)
+
            .write_tree(&[refs.into_inner(), sig.into_inner()])
            .map_err(error::Tree::Write)?;
        Ok(Tree {
            oid,
modified crates/radicle/src/storage/refs/sigrefs/write/error.rs
@@ -2,7 +2,8 @@ use radicle_oid::Oid;
use thiserror::Error;

use crate::git::repository;
-
use crate::storage::refs::sigrefs::git::{object, reference};
+
use crate::git::repository::object;
+
use crate::storage::refs::sigrefs::git::reference;

// TODO: use commit NID (and RID?) for traceability
#[derive(Debug, Error)]
@@ -23,7 +24,7 @@ pub enum Commit {
    #[error(transparent)]
    Tree(Tree),
    #[error(transparent)]
-
    Write(object::error::WriteCommit),
+
    Write(object::error::write::CommitError),
}

// TODO: use commit OID for traceability
@@ -33,7 +34,7 @@ pub enum Tree {
    #[error("failed to sign references payload")]
    Sign(crypto::signature::Error),
    #[error(transparent)]
-
    Write(object::error::WriteTree),
+
    Write(object::error::write::TreeError),
}

// TODO: use commit OID for traceability
modified crates/radicle/src/storage/refs/sigrefs/write/test/mock.rs
@@ -11,23 +11,24 @@ use radicle_oid::Oid;

use crate::git;
use crate::git::repository;
-
use crate::git::repository::types::{Blob, Commit};
-
use crate::git::repository::{ObjectReader, RefReader};
+
use crate::git::repository::object;
+
use crate::git::repository::types::{Blob, Commit, TreeEntry};
+
use crate::git::repository::{ObjectReader, ObjectWriter, RefReader};
use crate::identity::doc;
use crate::storage::HasRepoId;
-
use crate::storage::refs::sigrefs::git::{object, reference};
+
use crate::storage::refs::sigrefs::git::reference;
use crate::storage::refs::{REFS_BLOB_PATH, Refs, SIGNATURE_BLOB_PATH, SIGREFS_BRANCH};

const MOCKED_IDENTITY: u8 = 99u8;

enum WriteTreeBehavior {
-
    /// [`object::Writer::write_tree`] returns `Ok(oid)`.
+
    /// [`ObjectWriter::write_tree`] returns `Ok(oid)`.
    Ok(Oid),
-
    /// [`object::Writer::write_tree`] returns `Err(…)`.
+
    /// [`ObjectWriter::write_tree`] returns `Err(…)`.
    Error,
}

-
/// [`object::Writer::write_commit`] returns `Ok(oid)`.
+
/// [`ObjectWriter::write_commit`] returns `Ok(oid)`.
struct WriteCommitBehavior(Oid);

enum WriteReferenceBehavior {
@@ -204,7 +205,7 @@ impl HasRepoId for MockRepository {
}

impl ObjectReader for MockRepository {
-
    fn blob(&self, _oid: Oid) -> Result<Option<Blob>, repository::object::error::read::BlobError> {
+
    fn blob(&self, _oid: Oid) -> Result<Option<Blob>, object::error::read::BlobError> {
        unimplemented!("MockRepository::blob")
    }

@@ -212,7 +213,7 @@ impl ObjectReader for MockRepository {
        &self,
        commit: Oid,
        path: &P,
-
    ) -> Result<Option<Blob>, repository::object::error::read::BlobAtError> {
+
    ) -> Result<Option<Blob>, object::error::read::BlobAtError> {
        let key = (commit, path.as_ref().to_path_buf());
        match self.blobs.get(&key) {
            Some(BlobBehavior::Present(bytes)) => Ok(Some(Blob {
@@ -220,31 +221,25 @@ impl ObjectReader for MockRepository {
                content: bytes.clone(),
            })),
            Some(BlobBehavior::Missing) | None => Ok(None),
-
            Some(BlobBehavior::Error) => {
-
                Err(repository::object::error::read::BlobAtError::backend(
-
                    std::io::Error::other("mock blob error"),
-
                ))
-
            }
+
            Some(BlobBehavior::Error) => Err(object::error::read::BlobAtError::backend(
+
                std::io::Error::other("mock blob error"),
+
            )),
        }
    }

-
    fn commit(
-
        &self,
-
        oid: Oid,
-
    ) -> Result<Option<Commit>, repository::object::error::read::CommitError> {
+
    fn commit(&self, oid: Oid) -> Result<Option<Commit>, object::error::read::CommitError> {
        match self.commits.get(&oid) {
            Some(CommitBehavior::Present(data)) => {
                let bytes = data.to_string();
-
                let parsed = Commit::from_bytes(bytes.as_bytes()).map_err(|e| {
-
                    repository::object::error::read::CommitError::Parse { oid, source: e }
-
                })?;
+
                let parsed = Commit::from_bytes(bytes.as_bytes())
+
                    .map_err(|e| object::error::read::CommitError::Parse { oid, source: e })?;
                Ok(Some(parsed))
            }
            None => Ok(None),
        }
    }

-
    fn exists(&self, _oid: Oid) -> Result<bool, repository::object::error::read::ExistsError> {
+
    fn exists(&self, _oid: Oid) -> Result<bool, object::error::read::ExistsError> {
        unimplemented!("MockRepository::exists")
    }
}
@@ -280,26 +275,26 @@ impl RefReader for MockRepository {
    }
}

-
impl object::Writer for MockRepository {
-
    fn write_tree(
-
        &self,
-
        _refs: object::RefsEntry,
-
        _signature: object::SignatureEntry,
-
    ) -> Result<Oid, object::error::WriteTree> {
+
impl ObjectWriter for MockRepository {
+
    fn write_blob(&self, _content: &[u8]) -> Result<Oid, object::error::write::BlobError> {
+
        unimplemented!("MockRepository::write_blob")
+
    }
+

+
    fn write_tree(&self, _entries: &[TreeEntry]) -> Result<Oid, object::error::write::TreeError> {
        match &self.write_tree {
            Some(WriteTreeBehavior::Ok(oid)) => Ok(*oid),
-
            Some(WriteTreeBehavior::Error) | None => Err(object::error::WriteTree::write_error(
+
            Some(WriteTreeBehavior::Error) | None => Err(object::error::write::TreeError::backend(
                std::io::Error::other("mock write_tree error"),
            )),
        }
    }

-
    fn write_commit(&self, _bytes: &[u8]) -> Result<Oid, object::error::WriteCommit> {
+
    fn write_commit(&self, _bytes: &[u8]) -> Result<Oid, object::error::write::CommitError> {
        match &self.write_commit {
            Some(WriteCommitBehavior(oid)) => Ok(*oid),
-
            None => Err(object::error::WriteCommit::other(std::io::Error::other(
-
                "mock write_commit error",
-
            ))),
+
            None => Err(object::error::write::CommitError::backend(
+
                std::io::Error::other("mock write_commit error"),
+
            )),
        }
    }
}