node: Use git oid for project id

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-09-18 00:29:37 +02:00
parent 84119b0265
commit 6353d6115b
No known key found for this signature in database
5 changed files with 42 additions and 38 deletions

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::crypto::{self, Verified};
use crate::hash;
use crate::git;
use crate::serde_ext;
use crate::storage::Remotes;
@ -17,14 +17,14 @@ pub use doc::{Delegate, Doc};
#[derive(Error, Debug)]
pub enum IdError {
#[error("invalid digest: {0}")]
InvalidDigest(#[from] hash::DecodeError),
#[error("invalid git object id: {0}")]
InvalidOid(#[from] git2::Error),
#[error(transparent)]
Multibase(#[from] multibase::Error),
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id(hash::Digest);
pub struct Id(git::Oid);
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -40,12 +40,12 @@ impl fmt::Debug for Id {
impl Id {
pub fn to_human(&self) -> String {
multibase::encode(multibase::Base::Base58Btc, &self.0.as_ref())
multibase::encode(multibase::Base::Base58Btc, self.0.as_bytes())
}
pub fn from_human(s: &str) -> Result<Self, IdError> {
let (_, bytes) = multibase::decode(s)?;
let array: hash::Digest = bytes.as_slice().try_into()?;
let array: git::Oid = bytes.as_slice().try_into()?;
Ok(Self(array))
}
@ -68,14 +68,20 @@ impl TryFrom<OsString> for Id {
}
}
impl From<hash::Digest> for Id {
fn from(digest: hash::Digest) -> Self {
Self(digest)
impl From<git::Oid> for Id {
fn from(oid: git::Oid) -> Self {
Self(oid)
}
}
impl From<git2::Oid> for Id {
fn from(oid: git2::Oid) -> Self {
Self(oid.into())
}
}
impl Deref for Id {
type Target = hash::Digest;
type Target = git::Oid;
fn deref(&self) -> &Self::Target {
&self.0

View File

@ -12,7 +12,6 @@ use thiserror::Error;
use crate::crypto;
use crate::crypto::{Signature, Unverified, Verified};
use crate::git;
use crate::hash;
use crate::identity::{Did, Id};
use crate::storage::git::trailers;
use crate::storage::{BranchName, ReadRepository, RemoteId};
@ -79,22 +78,17 @@ pub struct Doc<V> {
}
impl Doc<Verified> {
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<Id, Error> {
pub fn encode(&self) -> Result<(Id, Vec<u8>), Error> {
let mut buf = Vec::new();
let mut ser =
let mut serializer =
serde_json::Serializer::with_formatter(&mut buf, olpc_cjson::CanonicalFormatter::new());
self.serialize(&mut ser)?;
self.serialize(&mut serializer)?;
let digest = hash::Digest::new(&buf);
let id = Id::from(digest);
let oid = git2::Oid::hash_object(git2::ObjectType::Blob, &buf)?;
let id = Id::from(oid);
// TODO: Currently, we serialize the document in canonical JSON. This isn't strictly
// necessary, as we could use CJSON just to get the hash, but then write a prettified
// version to disk to make it easier for users to edit.
writer.write_all(&buf)?;
Ok(id)
Ok((id, buf))
}
}
@ -367,9 +361,7 @@ mod test {
#[quickcheck]
fn prop_encode_decode(doc: Doc<Verified>) {
let mut bytes = Vec::new();
doc.write(&mut bytes).unwrap();
let (_, bytes) = doc.encode().unwrap();
assert_eq!(Doc::from_json(&bytes).unwrap().verified().unwrap(), doc);
}
}

View File

@ -47,17 +47,15 @@ pub fn init<'r, G: Signer, S: storage::WriteStorage<'r>>(
name: String::from("anonymous"),
id: identity::Did::from(*pk),
};
let doc = identity::Doc::initial(
let (id, doc) = identity::Doc::initial(
name.to_owned(),
description.to_owned(),
default_branch.clone(),
delegate,
)
.verified()?;
.verified()?
.encode()?;
let filename = *identity::doc::PATH;
let mut doc_bytes = Vec::new();
let id = doc.write(&mut doc_bytes)?;
let project = storage.repository(&id)?;
{
@ -70,11 +68,14 @@ pub fn init<'r, G: Signer, S: storage::WriteStorage<'r>>(
// git fetch rad
// git checkout -b radicle/id remotes/rad/radicle/id
//
let filename = *identity::doc::PATH;
let repo = project.raw();
let tree = {
let id_blob = repo.blob(&doc_bytes)?;
let doc_blob = repo.blob(&doc)?;
let mut builder = repo.treebuilder(None)?;
builder.insert(filename, id_blob, 0o100_644)?;
builder.insert(filename, doc_blob, 0o100_644)?;
assert_eq!(git::Oid::from(doc_blob), *id);
let tree_id = builder.write()?;
repo.find_tree(tree_id)

View File

@ -52,6 +52,10 @@ impl<const N: usize> ByteArray<N> {
pub fn into_inner(self) -> [u8; N] {
self.0
}
pub fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
}
impl<const N: usize> Arbitrary for ByteArray<N> {
@ -174,9 +178,8 @@ impl Arbitrary for MockStorage {
impl Arbitrary for Project {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut buf = Vec::new();
let doc = Doc::<Verified>::arbitrary(g);
let id = doc.write(&mut buf).unwrap();
let (id, _) = doc.encode().unwrap();
let remotes = storage::Remotes::arbitrary(g);
let path = PathBuf::arbitrary(g);
@ -311,8 +314,10 @@ impl Arbitrary for MockSigner {
impl Arbitrary for Id {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let digest = hash::Digest::arbitrary(g);
Id::from(digest)
let bytes = ByteArray::<20>::arbitrary(g);
let oid = git::Oid::try_from(bytes.as_slice()).unwrap();
Id::from(oid)
}
}

View File

@ -375,9 +375,9 @@ impl Decode for git::Url {
impl Decode for Id {
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
let digest: Digest = Decode::decode(reader)?;
let oid: git::Oid = Decode::decode(reader)?;
Ok(Self::from(digest))
Ok(Self::from(oid))
}
}