cob: Change history type to a string

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-11-30 11:48:21 +01:00
parent 0dc34dc15d
commit 5a47023ac0
No known key found for this signature in database
11 changed files with 54 additions and 59 deletions

View File

@ -13,7 +13,7 @@ use crate::{
change::{self, store, Change}, change::{self, store, Change},
history::entry, history::entry,
signatures::{Signature, Signatures}, signatures::{Signature, Signatures},
trailers, HistoryType, trailers,
}; };
const MANIFEST_BLOB_NAME: &str = "manifest"; const MANIFEST_BLOB_NAME: &str = "manifest";
@ -154,7 +154,7 @@ impl change::Storage for git2::Repository {
let tree = self.find_tree(commit.tree())?; let tree = self.find_tree(commit.tree())?;
let manifest = load_manifest(self, &tree)?; let manifest = load_manifest(self, &tree)?;
let contents = load_contents(self, &tree, &manifest)?; let contents = load_contents(self, &tree)?;
Ok(Change { Ok(Change {
id, id,
@ -210,10 +210,7 @@ fn load_manifest(
fn load_contents( fn load_contents(
repo: &git2::Repository, repo: &git2::Repository,
tree: &git2::Tree, tree: &git2::Tree,
manifest: &store::Manifest,
) -> Result<entry::Contents, error::Load> { ) -> Result<entry::Contents, error::Load> {
Ok(match manifest.history_type {
HistoryType::Radicle | HistoryType::Automerge => {
let contents_tree_entry = tree let contents_tree_entry = tree
.get_name(CHANGE_BLOB_NAME) .get_name(CHANGE_BLOB_NAME)
.ok_or_else(|| error::Load::NoChange(tree.id().into()))?; .ok_or_else(|| error::Load::NoChange(tree.id().into()))?;
@ -221,9 +218,7 @@ fn load_contents(
let contents_blob = contents_object let contents_blob = contents_object
.as_blob() .as_blob()
.ok_or_else(|| error::Load::ChangeNotBlob(tree.id().into()))?; .ok_or_else(|| error::Load::ChangeNotBlob(tree.id().into()))?;
contents_blob.content().to_owned() Ok(contents_blob.content().to_owned())
}
})
} }
fn write_commit<O>( fn write_commit<O>(

View File

@ -7,10 +7,7 @@ use std::{error::Error, fmt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{history::Contents, signatures, TypeName};
history::{Contents, HistoryType},
signatures, TypeName,
};
pub trait Storage { pub trait Storage {
type CreateError: Error + Send + Sync + 'static; type CreateError: Error + Send + Sync + 'static;
@ -47,7 +44,7 @@ pub trait Storage {
pub struct Create<Id> { pub struct Create<Id> {
pub typename: TypeName, pub typename: TypeName,
pub history_type: HistoryType, pub history_type: String,
pub tips: Vec<Id>, pub tips: Vec<Id>,
pub message: String, pub message: String,
pub contents: Contents, pub contents: Contents,
@ -126,10 +123,10 @@ where
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Manifest { pub struct Manifest {
/// The name given to the type of collaborative object. /// The name given to the type of collaborative object.
pub typename: TypeName, pub typename: TypeName,
/// The type of history for the collaborative oject. /// The type of history for the collaborative oject.
pub history_type: HistoryType, pub history_type: String,
} }

View File

@ -102,9 +102,9 @@ impl ChangeGraph {
// This is okay because we check that the graph has a root node in // This is okay because we check that the graph has a root node in
// GraphBuilder::build // GraphBuilder::build
let root = roots.first().unwrap(); let root = roots.first().unwrap();
let typename = { let manifest = {
let first_node = &self.graph[*root]; let first_node = &self.graph[*root];
first_node.typename().clone() first_node.manifest.clone()
}; };
let topo = Topo::new(&self.graph); let topo = Topo::new(&self.graph);
let items = topo.iter(&self.graph).map(|idx| { let items = topo.iter(&self.graph).map(|idx| {
@ -121,7 +121,7 @@ impl ChangeGraph {
evaluate(*root_change.id(), &self.graph, items) evaluate(*root_change.id(), &self.graph, items)
}; };
CollaborativeObject { CollaborativeObject {
typename, manifest,
history, history,
id: self.object_id, id: self.object_id,
} }

View File

@ -17,16 +17,6 @@ use crate::pruning_fold;
pub mod entry; pub mod entry;
pub use entry::{Clock, Contents, Entry, EntryId, EntryWithClock}; pub use entry::{Clock, Contents, Entry, EntryId, EntryWithClock};
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "lowercase")]
pub enum HistoryType {
#[default]
Radicle,
Automerge,
}
/// The DAG of changes making up the history of a collaborative object. /// The DAG of changes making up the history of a collaborative object.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct History { pub struct History {

View File

@ -92,7 +92,7 @@ pub use change::Change;
pub mod identity; pub mod identity;
pub mod history; pub mod history;
pub use history::{Contents, Entry, History, HistoryType}; pub use history::{Contents, Entry, History};
mod pruning_fold; mod pruning_fold;

View File

@ -7,6 +7,7 @@ use std::collections::BTreeSet;
use git_ext::Oid; use git_ext::Oid;
use crate::change::store::Manifest;
use crate::{change, identity::Identity, Contents, History, ObjectId, TypeName}; use crate::{change, identity::Identity, Contents, History, ObjectId, TypeName};
pub mod error; pub mod error;
@ -28,8 +29,8 @@ pub use update::{update, Update};
/// A collaborative object /// A collaborative object
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct CollaborativeObject { pub struct CollaborativeObject {
/// The typename of this object /// The manifest of this object
pub(crate) typename: TypeName, pub(crate) manifest: Manifest,
/// The CRDT history we know about for this object /// The CRDT history we know about for this object
pub(crate) history: History, pub(crate) history: History,
/// The id of the object /// The id of the object
@ -46,7 +47,11 @@ impl CollaborativeObject {
} }
pub fn typename(&self) -> &TypeName { pub fn typename(&self) -> &TypeName {
&self.typename &self.manifest.typename
}
pub fn manifest(&self) -> &Manifest {
&self.manifest
} }
fn tips(&self) -> BTreeSet<Oid> { fn tips(&self) -> BTreeSet<Oid> {

View File

@ -3,7 +3,7 @@
// This file is part of radicle-link, distributed under the GPLv3 with Radicle // This file is part of radicle-link, distributed under the GPLv3 with Radicle
// Linking Exception. For full terms see the included LICENSE file. // Linking Exception. For full terms see the included LICENSE file.
use crate::{HistoryType, Store}; use crate::Store;
use super::*; use super::*;
@ -12,7 +12,7 @@ pub struct Create<Author> {
/// The identity of the author for this object's first change. /// The identity of the author for this object's first change.
pub author: Option<Author>, pub author: Option<Author>,
/// The type of history that will be used for this object. /// The type of history that will be used for this object.
pub history_type: HistoryType, pub history_type: String,
/// The CRDT history to initialize this object with. /// The CRDT history to initialize this object with.
pub contents: Contents, pub contents: Contents,
/// The typename for this object. /// The typename for this object.
@ -25,7 +25,7 @@ impl<Author> Create<Author> {
fn create_spec(&self) -> change::Create<git_ext::Oid> { fn create_spec(&self) -> change::Create<git_ext::Oid> {
change::Create { change::Create {
typename: self.typename.clone(), typename: self.typename.clone(),
history_type: self.history_type, history_type: self.history_type.clone(),
tips: Vec::new(), tips: Vec::new(),
message: self.message.clone(), message: self.message.clone(),
contents: self.contents.clone(), contents: self.contents.clone(),
@ -101,7 +101,10 @@ where
.map_err(|err| error::Create::Refs { err: Box::new(err) })?; .map_err(|err| error::Create::Refs { err: Box::new(err) })?;
Ok(CollaborativeObject { Ok(CollaborativeObject {
manifest: Manifest {
typename: args.typename, typename: args.typename,
history_type: args.history_type,
},
history, history,
id: init_change.id().into(), id: init_change.id().into(),
}) })

View File

@ -4,8 +4,8 @@
// Linking Exception. For full terms see the included LICENSE file. // Linking Exception. For full terms see the included LICENSE file.
use crate::{ use crate::{
change, change_graph::ChangeGraph, identity::Identity, CollaborativeObject, Contents, change, change_graph::ChangeGraph, identity::Identity, CollaborativeObject, Contents, ObjectId,
HistoryType, ObjectId, Store, TypeName, Store, TypeName,
}; };
use super::error; use super::error;
@ -15,7 +15,7 @@ pub struct Update<Author> {
/// The identity of the author for the update of this object. /// The identity of the author for the update of this object.
pub author: Option<Author>, pub author: Option<Author>,
/// The type of history that will be used for this object. /// The type of history that will be used for this object.
pub history_type: HistoryType, pub history_type: String,
/// The CRDT changes to add to the object. /// The CRDT changes to add to the object.
pub changes: Contents, pub changes: Contents,
/// The object ID of the object to be updated. /// The object ID of the object to be updated.

View File

@ -6,8 +6,7 @@ use quickcheck::Arbitrary;
use radicle_crypto::Signer; use radicle_crypto::Signer;
use crate::{ use crate::{
create, get, list, object, test::arbitrary::Invalid, update, Create, HistoryType, ObjectId, create, get, list, object, test::arbitrary::Invalid, update, Create, ObjectId, TypeName, Update,
TypeName, Update,
}; };
use super::test; use super::test;
@ -30,7 +29,7 @@ fn roundtrip() {
&proj.identifier(), &proj.identifier(),
Create { Create {
author: Some(terry), author: Some(terry),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
contents: Vec::new(), contents: Vec::new(),
typename: typename.clone(), typename: typename.clone(),
message: "creating xyz.rad.issue".to_string(), message: "creating xyz.rad.issue".to_string(),
@ -63,7 +62,7 @@ fn list_cobs() {
&proj.identifier(), &proj.identifier(),
Create { Create {
author: Some(terry.clone()), author: Some(terry.clone()),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
contents: b"issue 1".to_vec(), contents: b"issue 1".to_vec(),
typename: typename.clone(), typename: typename.clone(),
message: "creating xyz.rad.issue".to_string(), message: "creating xyz.rad.issue".to_string(),
@ -78,7 +77,7 @@ fn list_cobs() {
&proj.identifier(), &proj.identifier(),
Create { Create {
author: Some(terry), author: Some(terry),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
contents: b"issue 2".to_vec(), contents: b"issue 2".to_vec(),
typename: typename.clone(), typename: typename.clone(),
message: "commenting xyz.rad.issue".to_string(), message: "commenting xyz.rad.issue".to_string(),
@ -113,7 +112,7 @@ fn update_cob() {
&proj.identifier(), &proj.identifier(),
Create { Create {
author: Some(terry.clone()), author: Some(terry.clone()),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
contents: Vec::new(), contents: Vec::new(),
typename: typename.clone(), typename: typename.clone(),
message: "creating xyz.rad.issue".to_string(), message: "creating xyz.rad.issue".to_string(),
@ -133,7 +132,7 @@ fn update_cob() {
Update { Update {
author: Some(terry), author: Some(terry),
changes: b"issue 1".to_vec(), changes: b"issue 1".to_vec(),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
object_id: *cob.id(), object_id: *cob.id(),
typename: typename.clone(), typename: typename.clone(),
message: "commenting xyz.rad.issue".to_string(), message: "commenting xyz.rad.issue".to_string(),
@ -174,7 +173,7 @@ fn traverse_cobs() {
Create { Create {
author: Some(terry), author: Some(terry),
contents: b"issue 1".to_vec(), contents: b"issue 1".to_vec(),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
typename: typename.clone(), typename: typename.clone(),
message: "creating xyz.rad.issue".to_string(), message: "creating xyz.rad.issue".to_string(),
}, },
@ -197,7 +196,7 @@ fn traverse_cobs() {
Update { Update {
author: Some(neil), author: Some(neil),
changes: b"issue 2".to_vec(), changes: b"issue 2".to_vec(),
history_type: HistoryType::Automerge, history_type: "test".to_string(),
object_id: *cob.id(), object_id: *cob.id(),
typename, typename,
message: "commenting on xyz.rad.issue".to_string(), message: "commenting on xyz.rad.issue".to_string(),

View File

@ -6,7 +6,7 @@ pub mod thread;
pub use cob::{ pub use cob::{
identity, object::collaboration::error, CollaborativeObject, Contents, Create, Entry, History, identity, object::collaboration::error, CollaborativeObject, Contents, Create, Entry, History,
HistoryType, ObjectId, TypeName, Update, ObjectId, TypeName, Update,
}; };
pub use common::*; pub use common::*;

View File

@ -8,13 +8,16 @@ use serde::Serialize;
use crate::cob; use crate::cob;
use crate::cob::common::Author; use crate::cob::common::Author;
use crate::cob::CollaborativeObject; use crate::cob::CollaborativeObject;
use crate::cob::{Create, History, HistoryType, ObjectId, TypeName, Update}; use crate::cob::{Create, History, ObjectId, TypeName, Update};
use crate::crypto::PublicKey; use crate::crypto::PublicKey;
use crate::git; use crate::git;
use crate::identity::project; use crate::identity::project;
use crate::prelude::*; use crate::prelude::*;
use crate::storage::git as storage; use crate::storage::git as storage;
/// History type for standard radicle COBs.
pub const HISTORY_TYPE: &str = "radicle";
/// A type that can be materialized from an event history. /// A type that can be materialized from an event history.
/// All collaborative objects implement this trait. /// All collaborative objects implement this trait.
pub trait FromHistory: Sized { pub trait FromHistory: Sized {
@ -102,7 +105,7 @@ where
Update { Update {
author: Some(cob::Author::from(*signer.public_key())), author: Some(cob::Author::from(*signer.public_key())),
object_id, object_id,
history_type: HistoryType::default(), history_type: HISTORY_TYPE.to_owned(),
typename: T::type_name().clone(), typename: T::type_name().clone(),
message: message.to_owned(), message: message.to_owned(),
changes, changes,
@ -125,7 +128,7 @@ where
&self.project, &self.project,
Create { Create {
author: Some(cob::Author::from(*signer.public_key())), author: Some(cob::Author::from(*signer.public_key())),
history_type: HistoryType::default(), history_type: HISTORY_TYPE.to_owned(),
typename: T::type_name().clone(), typename: T::type_name().clone(),
message: message.to_owned(), message: message.to_owned(),
contents, contents,
@ -141,6 +144,9 @@ where
let cob = cob::get(self.raw, T::type_name(), id)?; let cob = cob::get(self.raw, T::type_name(), id)?;
if let Some(cob) = cob { if let Some(cob) = cob {
if cob.manifest().history_type != HISTORY_TYPE {
panic!();
}
let (obj, clock) = T::from_history(cob.history())?; let (obj, clock) = T::from_history(cob.history())?;
Ok(Some((obj, clock))) Ok(Some((obj, clock)))
} else { } else {