Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
storage/refs/sigrefs: migrate object::Reader to ObjectReader
Fintan Halpenny committed 24 days ago
commit 8c9729176b3fbcb323e35e36b8ec22253d08cd5f
parent fb408ba1bb1170e7e01cd6f7e4720b4339f36d9a
7 files changed +128 -87
modified crates/radicle/src/storage/refs.rs
@@ -19,6 +19,7 @@ use thiserror::Error;
use crate::git;
use crate::git::Oid;
use crate::git::raw::ErrorExt as _;
+
use crate::git::repository::ObjectReader;
use crate::storage;
use crate::storage::RemoteId;
use crate::storage::refs::sigrefs::read::Tip;
@@ -78,7 +79,7 @@ impl Refs {
        signer: &S,
    ) -> Result<SignedRefs, Error>
    where
-
        R: sigrefs::git::object::Reader + sigrefs::git::object::Writer,
+
        R: ObjectReader + sigrefs::git::object::Writer,
        R: sigrefs::git::reference::Reader + sigrefs::git::reference::Writer,
        R: HasRepoId,
        S: signature::Signer<crypto::Signature>,
@@ -96,7 +97,7 @@ impl Refs {
        signer: &S,
    ) -> Result<SignedRefs, Error>
    where
-
        R: sigrefs::git::object::Reader + sigrefs::git::object::Writer,
+
        R: ObjectReader + sigrefs::git::object::Writer,
        R: sigrefs::git::reference::Reader + sigrefs::git::reference::Writer,
        R: HasRepoId,
        S: signature::Signer<crypto::Signature>,
@@ -114,7 +115,7 @@ impl Refs {
        force: bool,
    ) -> Result<SignedRefs, Error>
    where
-
        R: sigrefs::git::object::Reader + sigrefs::git::object::Writer,
+
        R: ObjectReader + sigrefs::git::object::Writer,
        R: sigrefs::git::reference::Reader + sigrefs::git::reference::Writer,
        R: HasRepoId,
        S: signature::Signer<crypto::Signature>,
@@ -425,7 +426,7 @@ impl SignedRefs {
    pub fn load<R>(remote: RemoteId, repo: &R) -> Result<Option<Self>, sigrefs::read::error::Read>
    where
        R: HasRepoId,
-
        R: sigrefs::git::object::Reader + sigrefs::git::reference::Reader,
+
        R: ObjectReader + sigrefs::git::reference::Reader,
    {
        Self::load_internal(remote, repo, sigrefs::read::Tip::Reference(remote))
    }
@@ -437,7 +438,7 @@ impl SignedRefs {
    ) -> Result<Option<Self>, sigrefs::read::error::Read>
    where
        R: HasRepoId,
-
        R: sigrefs::git::object::Reader + sigrefs::git::reference::Reader,
+
        R: ObjectReader + sigrefs::git::reference::Reader,
    {
        Self::load_internal(remote, repo, sigrefs::read::Tip::Commit(oid))
    }
@@ -449,7 +450,7 @@ impl SignedRefs {
    ) -> Result<Option<Self>, sigrefs::read::error::Read>
    where
        R: HasRepoId,
-
        R: sigrefs::git::object::Reader + sigrefs::git::reference::Reader,
+
        R: ObjectReader + sigrefs::git::reference::Reader,
    {
        let root = repo.rid();
        match sigrefs::SignedRefsReader::new(root, tip, repo, &remote).read() {
modified crates/radicle/src/storage/refs/sigrefs/read.rs
@@ -16,8 +16,9 @@ use radicle_git_metadata::commit::CommitData;
use radicle_oid::Oid;

use crate::git;
+
use crate::git::repository::ObjectReader;
use crate::identity::doc;
-
use crate::storage::refs::sigrefs::git::{object, reference};
+
use crate::storage::refs::sigrefs::git::reference;
use crate::storage::refs::{
    FeatureLevel, IDENTITY_ROOT, REFS_BLOB_PATH, Refs, SIGNATURE_BLOB_PATH, SIGREFS_BRANCH,
    SignedRefs,
@@ -128,7 +129,7 @@ impl std::fmt::Display for FeatureLevels {

impl<'a, R, V> SignedRefsReader<'a, R, V>
where
-
    R: object::Reader + reference::Reader,
+
    R: ObjectReader + reference::Reader,
    V: signature::Verifier<crypto::Signature>,
{
    /// Construct a new [`SignedRefsReader`].
@@ -440,7 +441,7 @@ pub(super) struct CommitReader<'a, R> {

impl<'a, R> CommitReader<'a, R>
where
-
    R: object::Reader,
+
    R: ObjectReader,
{
    pub(super) fn new(commit: Oid, repository: &'a R) -> Self {
        Self { commit, repository }
@@ -466,15 +467,10 @@ where
    }

    fn read_commit_data(&self) -> Result<CommitData<Oid, Oid>, error::Commit> {
-
        let bytes = self
-
            .repository
-
            .read_commit(&self.commit)
+
        self.repository
+
            .commit(self.commit)
            .map_err(error::Commit::Read)?
-
            .ok_or(error::Commit::Missing { oid: self.commit })?;
-
        CommitData::from_bytes(&bytes).map_err(|err| error::Commit::Parse {
-
            oid: self.commit,
-
            source: err,
-
        })
+
            .ok_or(error::Commit::Missing { oid: self.commit })
    }

    /// Extract the single parent [`Oid`] from a [`CommitData`], if any.
@@ -509,7 +505,7 @@ struct TreeReader<'a, R> {

impl<'a, R> TreeReader<'a, R>
where
-
    R: object::Reader,
+
    R: ObjectReader,
{
    fn new(commit: Oid, repository: &'a R) -> Self {
        Self { commit, repository }
@@ -517,40 +513,42 @@ where

    fn read(self) -> Result<Tree, error::Tree> {
        let (refs, signature) = self.try_handle_blobs()?;
-
        let refs = Refs::from_canonical(&refs.bytes).map_err(error::Tree::ParseRefs)?;
-
        let signature = crypto::Signature::try_from(signature.bytes.as_slice())
+
        let refs = Refs::from_canonical(&refs.content).map_err(error::Tree::ParseRefs)?;
+
        let signature = crypto::Signature::try_from(signature.content.as_slice())
            .map_err(error::Tree::ParseSignature)?;
        Ok(Tree { refs, signature })
    }

    /// Fetch the refs blob and signature blob from the repository, returning a
    /// descriptive error if either or both are missing.
-
    fn try_handle_blobs(&self) -> Result<(object::Blob, object::Blob), error::Tree> {
-
        let commit = &self.commit;
+
    fn try_handle_blobs(
+
        &self,
+
    ) -> Result<(git::repository::Blob, git::repository::Blob), error::Tree> {
+
        let commit = self.commit;
        let refs_path = Path::new(REFS_BLOB_PATH);
        let sig_path = Path::new(SIGNATURE_BLOB_PATH);

-
        let refs_bytes = self
+
        let refs_blob = self
            .repository
-
            .read_blob(commit, refs_path)
+
            .blob_at(commit, &refs_path)
            .map_err(error::Tree::Refs)?;
-
        let sig_bytes = self
+
        let sig_blob = self
            .repository
-
            .read_blob(commit, sig_path)
+
            .blob_at(commit, &sig_path)
            .map_err(error::Tree::Signature)?;

-
        let result = match (refs_bytes, sig_bytes) {
+
        let result = match (refs_blob, sig_blob) {
            (None, None) => Err(error::MissingBlobs::Both {
-
                commit: *commit,
+
                commit,
                refs: refs_path.to_path_buf(),
                signature: sig_path.to_path_buf(),
            }),
            (None, Some(_)) => Err(error::MissingBlobs::Signature {
-
                commit: *commit,
+
                commit,
                path: sig_path.to_path_buf(),
            }),
            (Some(_), None) => Err(error::MissingBlobs::Refs {
-
                commit: *commit,
+
                commit,
                path: refs_path.to_path_buf(),
            }),
            (Some(refs), Some(sig)) => Ok((refs, sig)),
@@ -573,7 +571,7 @@ struct IdentityRootReader<'a, 'b, R> {

impl<'a, 'b, R> IdentityRootReader<'a, 'b, R>
where
-
    R: object::Reader,
+
    R: ObjectReader,
{
    fn new(refs: &'a Refs, repository: &'b R) -> Self {
        Self { refs, repository }
@@ -590,11 +588,11 @@ where

    fn read_blob(&self, commit: &Oid) -> Result<RepoId, error::IdentityRoot> {
        let path = Path::new("embeds").join(*doc::PATH);
-
        let object::Blob { oid, .. } = self
+
        let blob = self
            .repository
-
            .read_blob(commit, &path)
+
            .blob_at(*commit, &path)
            .map_err(error::IdentityRoot::Blob)?
            .ok_or_else(|| error::IdentityRoot::MissingIdentity { commit: *commit })?;
-
        Ok(RepoId::from(oid))
+
        Ok(RepoId::from(blob.oid))
    }
}
modified crates/radicle/src/storage/refs/sigrefs/read/error.rs
@@ -6,7 +6,8 @@ use radicle_git_metadata::commit;
use radicle_oid::Oid;
use thiserror::Error;

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

@@ -48,7 +49,7 @@ pub enum Commit {
    #[error(transparent)]
    TooManyParents(Parent),
    #[error(transparent)]
-
    Read(object::error::ReadCommit),
+
    Read(object::error::read::CommitError),
}

#[derive(Debug, Error)]
@@ -75,9 +76,9 @@ impl fmt::Display for Parent {
#[non_exhaustive]
pub enum Tree {
    #[error(transparent)]
-
    Refs(object::error::ReadBlob),
+
    Refs(object::error::read::BlobAtError),
    #[error(transparent)]
-
    Signature(object::error::ReadBlob),
+
    Signature(object::error::read::BlobAtError),
    #[error(transparent)]
    ParseRefs(canonical::Error),
    #[error(transparent)]
@@ -104,7 +105,7 @@ pub enum MissingBlobs {
#[non_exhaustive]
pub enum IdentityRoot {
    #[error(transparent)]
-
    Blob(object::error::ReadBlob),
+
    Blob(object::error::read::BlobAtError),
    #[error("missing repository identity commit '{commit}'")]
    MissingIdentity { commit: Oid },
}
modified crates/radicle/src/storage/refs/sigrefs/read/iter.rs
@@ -1,6 +1,6 @@
use radicle_oid::Oid;

-
use crate::storage::refs::sigrefs::git::object;
+
use crate::git::repository::ObjectReader;

use super::{Commit, CommitReader, error};

@@ -18,7 +18,7 @@ impl<'a, R> Walk<'a, R> {
    }
}

-
impl<'a, R: object::Reader> Iterator for Walk<'a, R> {
+
impl<'a, R: ObjectReader> Iterator for Walk<'a, R> {
    type Item = Result<Commit, error::Commit>;

    fn next(&mut self) -> Option<Self::Item> {
modified crates/radicle/src/storage/refs/sigrefs/read/test/mock.rs
@@ -1,5 +1,7 @@
-
//! Mock implementations of [`object::Reader`] and [`reference::Reader`] for
+
//! Mock implementations of [`ObjectReader`] and [`reference::Reader`] for
//! unit-testing.
+
//!
+
//! [`ObjectReader`]: crate::git::repository::ObjectReader

use std::collections::HashMap;
use std::path::{Path, PathBuf};
@@ -12,13 +14,16 @@ use radicle_git_metadata::commit::trailers::OwnedTrailer;
use radicle_oid::Oid;

use crate::git;
+
use crate::git::repository::ObjectReader;
+
use crate::git::repository::object;
+
use crate::git::repository::types::{Blob, Commit};
use crate::identity::doc;
-
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};

pub(crate) const MOCKED_IDENTITY: u8 = 99u8;

-
/// A configurable in-memory repository implementing [`object::Reader`] and
+
/// A configurable in-memory repository implementing [`ObjectReader`] and
/// [`reference::Reader`].
/// All behaviour is set at construction time via the builder methods; the mock
/// is fully deterministic.
@@ -29,20 +34,20 @@ pub struct MockRepository {
}

enum CommitBehavior {
-
    /// [`object::Reader::read_commit`] returns `Ok(Some(bytes))`.
+
    /// [`ObjectReader::commit`] returns `Ok(Some(commit))`.
    Present(Box<CommitData<Oid, Oid>>),
-
    /// [`object::Reader::read_commit`] returns `Ok(None)`.
+
    /// [`ObjectReader::commit`] returns `Ok(None)`.
    Missing,
-
    /// [`object::Reader::read_commit`] returns `Err(…)`.
+
    /// [`ObjectReader::commit`] returns `Err(…)`.
    Error,
}

enum BlobBehavior {
-
    /// [`object::Reader::read_blob`] returns `Ok(Some(blob))`.
+
    /// [`ObjectReader::blob_at`] returns `Ok(Some(blob))`.
    Present(Vec<u8>),
-
    /// [`object::Reader::read_blob`] returns `Ok(None)`.
+
    /// [`ObjectReader::blob_at`] returns `Ok(None)`.
    Missing,
-
    /// [`object::Reader::read_blob`] returns `Err(…)`.
+
    /// [`ObjectReader::blob_at`] returns `Err(…)`.
    Error,
}

@@ -164,38 +169,51 @@ impl MockRepository {
    }
}

-
impl object::Reader for MockRepository {
-
    fn read_commit(&self, oid: &Oid) -> Result<Option<Vec<u8>>, object::error::ReadCommit> {
-
        match self.commits.get(oid) {
-
            Some(CommitBehavior::Present(data)) => Ok(Some(data.to_string().as_bytes().to_vec())),
-
            Some(CommitBehavior::Missing) | None => Ok(None),
-
            Some(CommitBehavior::Error) => Err(object::error::ReadCommit::other(
-
                std::io::Error::other("mock commit error"),
-
            )),
-
        }
+
impl ObjectReader for MockRepository {
+
    fn blob(&self, _oid: Oid) -> Result<Option<Blob>, object::error::read::BlobError> {
+
        unimplemented!("MockRepository::blob")
    }

-
    fn read_blob(
+
    fn blob_at<P: AsRef<Path>>(
        &self,
-
        commit: &Oid,
-
        path: &Path,
-
    ) -> Result<Option<object::Blob>, object::error::ReadBlob> {
-
        let key = (*commit, path.to_path_buf());
+
        commit: Oid,
+
        path: &P,
+
    ) -> 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(object::Blob {
+
            Some(BlobBehavior::Present(bytes)) => Ok(Some(Blob {
                // The blob OID is returned as the commit OID.  This is
                // intentional: IdentityRootReader converts blob.oid into a
                // RepoId, so callers can predict which RepoId results from a
                // given identity-root commit OID.
-
                oid: *commit,
-
                bytes: bytes.clone(),
+
                oid: commit,
+
                content: bytes.clone(),
            })),
            Some(BlobBehavior::Missing) | None => Ok(None),
-
            Some(BlobBehavior::Error) => Err(object::error::ReadBlob::other(
+
            Some(BlobBehavior::Error) => Err(object::error::read::BlobAtError::backend(
                std::io::Error::other("mock blob error"),
            )),
        }
    }
+

+
    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| object::error::read::CommitError::Parse { oid, source: e })?;
+
                Ok(Some(parsed))
+
            }
+
            Some(CommitBehavior::Missing) | None => Ok(None),
+
            Some(CommitBehavior::Error) => Err(object::error::read::CommitError::backend(
+
                std::io::Error::other("mock commit error"),
+
            )),
+
        }
+
    }
+

+
    fn exists(&self, _oid: Oid) -> Result<bool, object::error::read::ExistsError> {
+
        unimplemented!("MockRepository::exists")
+
    }
}

impl reference::Reader for MockRepository {
modified crates/radicle/src/storage/refs/sigrefs/write.rs
@@ -13,6 +13,7 @@ use radicle_git_metadata::commit::{CommitData, headers::Headers, trailers::Owned
use radicle_oid::Oid;

use crate::git;
+
use crate::git::repository::ObjectReader;
use crate::storage::refs::SignedRefs;
use crate::storage::refs::sigrefs::git::{Committer, object, reference};
use crate::storage::refs::sigrefs::read::CommitReader;
@@ -72,7 +73,7 @@ pub struct SignedRefsWriter<'a, R, S> {

impl<'a, R, S> SignedRefsWriter<'a, R, S>
where
-
    R: object::Writer + object::Reader + reference::Writer + reference::Reader,
+
    R: object::Writer + ObjectReader + reference::Writer + reference::Reader,
    S: Signer<crypto::Signature>,
    S: signature::Verifier<crypto::Signature>,
{
@@ -372,7 +373,7 @@ struct HeadReader<'a, 'b, 'c, R, V> {

impl<'a, 'b, 'c, R, V> HeadReader<'a, 'b, 'c, R, V>
where
-
    R: object::Reader + reference::Reader,
+
    R: ObjectReader + reference::Reader,
    V: signature::Verifier<crypto::Signature>,
{
    /// Construct a [`HeadReader`] with the `reference` that is being read from
modified crates/radicle/src/storage/refs/sigrefs/write/test/mock.rs
@@ -10,6 +10,9 @@ use radicle_git_metadata::commit::trailers::OwnedTrailer;
use radicle_oid::Oid;

use crate::git;
+
use crate::git::repository;
+
use crate::git::repository::ObjectReader;
+
use crate::git::repository::types::{Blob, Commit};
use crate::identity::doc;
use crate::storage::HasRepoId;
use crate::storage::refs::sigrefs::git::{object, reference};
@@ -200,31 +203,50 @@ impl HasRepoId for MockRepository {
    }
}

-
impl object::Reader for MockRepository {
-
    fn read_commit(&self, oid: &Oid) -> Result<Option<Vec<u8>>, object::error::ReadCommit> {
-
        match self.commits.get(oid) {
-
            Some(CommitBehavior::Present(data)) => Ok(Some(data.to_string().as_bytes().to_vec())),
-
            None => Ok(None),
-
        }
+
impl ObjectReader for MockRepository {
+
    fn blob(&self, _oid: Oid) -> Result<Option<Blob>, repository::object::error::read::BlobError> {
+
        unimplemented!("MockRepository::blob")
    }

-
    fn read_blob(
+
    fn blob_at<P: AsRef<Path>>(
        &self,
-
        commit: &Oid,
-
        path: &Path,
-
    ) -> Result<Option<object::Blob>, object::error::ReadBlob> {
-
        let key = (*commit, path.to_path_buf());
+
        commit: Oid,
+
        path: &P,
+
    ) -> Result<Option<Blob>, repository::object::error::read::BlobAtError> {
+
        let key = (commit, path.as_ref().to_path_buf());
        match self.blobs.get(&key) {
-
            Some(BlobBehavior::Present(bytes)) => Ok(Some(object::Blob {
-
                oid: *commit,
-
                bytes: bytes.clone(),
+
            Some(BlobBehavior::Present(bytes)) => Ok(Some(Blob {
+
                oid: commit,
+
                content: bytes.clone(),
            })),
            Some(BlobBehavior::Missing) | None => Ok(None),
-
            Some(BlobBehavior::Error) => Err(object::error::ReadBlob::other(
-
                std::io::Error::other("mock blob error"),
-
            )),
+
            Some(BlobBehavior::Error) => {
+
                Err(repository::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> {
+
        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 }
+
                })?;
+
                Ok(Some(parsed))
+
            }
+
            None => Ok(None),
        }
    }
+

+
    fn exists(&self, _oid: Oid) -> Result<bool, repository::object::error::read::ExistsError> {
+
        unimplemented!("MockRepository::exists")
+
    }
}

impl reference::Reader for MockRepository {