Add TypeName & ObjectId parser

Added the `parse_refname` function for parsing a reference into its
`TypeName` and `ObjectId`, if possible.

This replaces the `cob_suffix` function in `radicle`.

This change also fixes the `FromStr` instance of `ObjectId` to use
`from_str` instead of `TryFrom` for bytes.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2022-11-16 14:05:13 +00:00
parent b4bc032113
commit a985e067a5
No known key found for this signature in database
GPG Key ID: 2552FB6F64066CB7
4 changed files with 45 additions and 17 deletions

View File

@ -11,7 +11,9 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
pub mod collaboration;
pub use collaboration::{create, get, info, list, update, CollaborativeObject, Create, Update};
pub use collaboration::{
create, get, info, list, parse_refstr, update, CollaborativeObject, Create, Update,
};
pub mod storage;
pub use storage::{Commit, Objects, Reference, Storage};
@ -30,7 +32,7 @@ impl FromStr for ObjectId {
type Err = ParseObjectId;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let oid = Oid::try_from(s.as_bytes())?;
let oid = Oid::from_str(s)?;
Ok(ObjectId(oid))
}
}

View File

@ -53,3 +53,43 @@ impl CollaborativeObject {
self.history.tips().into_iter().map(Oid::from).collect()
}
}
/// Takes a `refname` and performs a best attempt to extract out the
/// [`TypeName`] and [`ObjectId`] from it.
///
/// This assumes that the `refname` is in a
/// [`git_ref_format::Qualified`] format. If it has any
/// `refs/namespaces`, they will be stripped to access the underlying
/// [`git_ref_format::Qualified`] format.
///
/// In the [`git_ref_format::Qualified`] format it assumes that the
/// reference name is of the form:
///
/// `refs/<category>/<typename>/<object_id>[/<rest>*]`
///
/// Note that their may be more components to the path after the
/// [`ObjectId`] but they are ignored.
///
/// Also note that this will return `None` if:
///
/// * The `refname` is not [`git_ref_format::Qualified`]
/// * The parsing of the [`ObjectId`] fails
/// * The parsing of the [`TypeName`] fails
pub fn parse_refstr<R>(name: &R) -> Option<(TypeName, ObjectId)>
where
R: AsRef<git_ref_format::RefStr>,
{
use git_ref_format::Qualified;
let name = name.as_ref();
let refs_cobs = match name.to_namespaced() {
None => Qualified::from_refstr(name)?,
Some(ns) => ns.strip_namespace_recursive(),
};
let (_refs, _cobs, typename, mut object_id) = refs_cobs.non_empty_components();
let object = object_id
.next()
.and_then(|oid| oid.parse::<ObjectId>().ok())?;
let name = typename.parse::<TypeName>().ok()?;
Some((name, object))
}

View File

@ -141,20 +141,6 @@ pub mod refs {
.join(Component::from(typename))
.join(Component::from(object_id))
}
pub fn cob_suffix<R>(cob: &R) -> Option<(cob::TypeName, cob::ObjectId)>
where
R: AsRef<RefStr>,
{
let cob = cob.as_ref().to_namespaced()?;
let cob = cob.strip_namespace();
let (_refs, _cobs, typename, mut object_id) = cob.non_empty_components();
let object_id = object_id
.next()
.and_then(|oid| oid.parse::<git2::Oid>().ok())?;
let typename = typename.parse::<cob::TypeName>().ok()?;
Some((typename, object_id.into()))
}
}
pub mod workdir {

View File

@ -736,7 +736,7 @@ impl cob::object::Storage for Repository {
let reference = reference.ok()?;
match RefStr::try_from_str(reference.name()?) {
Ok(name) => {
let (ty, object_id) = git::refs::storage::cob_suffix(&name)?;
let (ty, object_id) = cob::object::parse_refstr(&name)?;
if ty == *typename {
Some(
cob::object::Reference::try_from(reference)