diff --git a/radicle-cob/src/object/storage.rs b/radicle-cob/src/object/storage.rs index 5cc8e130..1dcfe443 100644 --- a/radicle-cob/src/object/storage.rs +++ b/radicle-cob/src/object/storage.rs @@ -83,3 +83,49 @@ pub trait Storage { change: &Change, ) -> Result<(), Self::UpdateError>; } + +pub mod convert { + use std::str; + + use git_ref_format::RefString; + use thiserror::Error; + + use super::{Commit, Reference}; + + #[derive(Debug, Error)] + pub enum Error { + #[error("the reference '{name}' does not point to a commit object")] + NotCommit { + name: RefString, + #[source] + err: git2::Error, + }, + #[error(transparent)] + Ref(#[from] git_ref_format::Error), + #[error(transparent)] + Utf8(#[from] str::Utf8Error), + } + + impl<'a> TryFrom> for Reference { + type Error = Error; + + fn try_from(value: git2::Reference<'a>) -> Result { + let name = RefString::try_from(str::from_utf8(value.name_bytes())?)?; + let target = Commit::from(value.peel_to_commit().map_err(|err| Error::NotCommit { + name: name.clone(), + err, + })?); + Ok(Self { name, target }) + } + } + + impl<'a> From> for Commit { + fn from(commit: git2::Commit<'a>) -> Self { + let parents = commit.parents().map(Commit::from).collect(); + Commit { + id: commit.id().into(), + parents, + } + } + } +} diff --git a/radicle-cob/src/test/storage.rs b/radicle-cob/src/test/storage.rs index a5ac73e0..142e25b1 100644 --- a/radicle-cob/src/test/storage.rs +++ b/radicle-cob/src/test/storage.rs @@ -1,11 +1,10 @@ use std::{collections::HashMap, convert::TryFrom as _}; -use git_ref_format::RefString; use tempfile::TempDir; use crate::{ change, - object::{self, Commit, Reference}, + object::{self, Reference}, ObjectId, Store, }; @@ -14,6 +13,8 @@ use super::identity::{RemoteProject, Urn}; pub mod error { use thiserror::Error; + use crate::object::storage::convert; + #[derive(Debug, Error)] pub enum Identity { #[error(transparent)] @@ -28,6 +29,8 @@ pub mod error { #[derive(Debug, Error)] pub enum Objects { + #[error(transparent)] + Conversion(#[from] convert::Error), #[error(transparent)] Git(#[from] git2::Error), #[error(transparent)] @@ -122,12 +125,15 @@ impl object::Storage for Storage { ); let local = { let r = self.raw.find_reference(&name)?; - Some(resolve_reference(r)?) + Some(Reference::try_from(r)?) }; let remotes = self .raw .references_glob(&glob)? - .map(|r| r.map_err(error::Objects::from).and_then(resolve_reference)) + .map(|r| { + r.map_err(error::Objects::from) + .and_then(|r| Reference::try_from(r).map_err(error::Objects::from)) + }) .collect::, _>>()?; Ok(object::Objects { local, remotes }) } @@ -150,7 +156,7 @@ impl object::Storage for Storage { objects.insert( oid, object::Objects { - local: Some(resolve_reference(r)?), + local: Some(Reference::try_from(r)?), remotes: Vec::new(), }, ); @@ -177,23 +183,3 @@ impl object::Storage for Storage { Ok(()) } } - -fn resolve_reference(r: git2::Reference) -> Result { - let commit = r.peel_to_commit()?; - let target = resolve_parents(commit)?; - Ok(Reference { - name: RefString::try_from(r.name().unwrap().to_owned())?, - target, - }) -} - -fn resolve_parents(commit: git2::Commit) -> Result { - let parents = commit - .parents() - .map(resolve_parents) - .collect::, _>>()?; - Ok(Commit { - id: commit.id().into(), - parents, - }) -}