radicle-cob: Reference conversion from git2::Reference

It will be common for Reference to be converted from a
`git2::Reference` when one is implementing `object::Storage`.

Provide a `TryFrom` implementation between `git2::Reference` and
`Reference`.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2022-11-07 12:30:12 +00:00
parent 6b303bdc97
commit 4112b0fdc5
No known key found for this signature in database
GPG Key ID: 2552FB6F64066CB7
2 changed files with 57 additions and 25 deletions

View File

@ -83,3 +83,49 @@ pub trait Storage {
change: &Change, change: &Change,
) -> Result<(), Self::UpdateError>; ) -> 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<git2::Reference<'a>> for Reference {
type Error = Error;
fn try_from(value: git2::Reference<'a>) -> Result<Self, Self::Error> {
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<git2::Commit<'a>> for Commit {
fn from(commit: git2::Commit<'a>) -> Self {
let parents = commit.parents().map(Commit::from).collect();
Commit {
id: commit.id().into(),
parents,
}
}
}
}

View File

@ -1,11 +1,10 @@
use std::{collections::HashMap, convert::TryFrom as _}; use std::{collections::HashMap, convert::TryFrom as _};
use git_ref_format::RefString;
use tempfile::TempDir; use tempfile::TempDir;
use crate::{ use crate::{
change, change,
object::{self, Commit, Reference}, object::{self, Reference},
ObjectId, Store, ObjectId, Store,
}; };
@ -14,6 +13,8 @@ use super::identity::{RemoteProject, Urn};
pub mod error { pub mod error {
use thiserror::Error; use thiserror::Error;
use crate::object::storage::convert;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Identity { pub enum Identity {
#[error(transparent)] #[error(transparent)]
@ -28,6 +29,8 @@ pub mod error {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Objects { pub enum Objects {
#[error(transparent)]
Conversion(#[from] convert::Error),
#[error(transparent)] #[error(transparent)]
Git(#[from] git2::Error), Git(#[from] git2::Error),
#[error(transparent)] #[error(transparent)]
@ -122,12 +125,15 @@ impl object::Storage for Storage {
); );
let local = { let local = {
let r = self.raw.find_reference(&name)?; let r = self.raw.find_reference(&name)?;
Some(resolve_reference(r)?) Some(Reference::try_from(r)?)
}; };
let remotes = self let remotes = self
.raw .raw
.references_glob(&glob)? .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::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
Ok(object::Objects { local, remotes }) Ok(object::Objects { local, remotes })
} }
@ -150,7 +156,7 @@ impl object::Storage for Storage {
objects.insert( objects.insert(
oid, oid,
object::Objects { object::Objects {
local: Some(resolve_reference(r)?), local: Some(Reference::try_from(r)?),
remotes: Vec::new(), remotes: Vec::new(),
}, },
); );
@ -177,23 +183,3 @@ impl object::Storage for Storage {
Ok(()) Ok(())
} }
} }
fn resolve_reference(r: git2::Reference) -> Result<Reference, error::Objects> {
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<Commit, git2::Error> {
let parents = commit
.parents()
.map(resolve_parents)
.collect::<Result<Vec<_>, _>>()?;
Ok(Commit {
id: commit.id().into(),
parents,
})
}