cob: Change history type to a string
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
0dc34dc15d
commit
5a47023ac0
|
|
@ -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,20 +210,15 @@ 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 {
|
let contents_tree_entry = tree
|
||||||
HistoryType::Radicle | HistoryType::Automerge => {
|
.get_name(CHANGE_BLOB_NAME)
|
||||||
let contents_tree_entry = tree
|
.ok_or_else(|| error::Load::NoChange(tree.id().into()))?;
|
||||||
.get_name(CHANGE_BLOB_NAME)
|
let contents_object = contents_tree_entry.to_object(repo)?;
|
||||||
.ok_or_else(|| error::Load::NoChange(tree.id().into()))?;
|
let contents_blob = contents_object
|
||||||
let contents_object = contents_tree_entry.to_object(repo)?;
|
.as_blob()
|
||||||
let contents_blob = contents_object
|
.ok_or_else(|| error::Load::ChangeNotBlob(tree.id().into()))?;
|
||||||
.as_blob()
|
Ok(contents_blob.content().to_owned())
|
||||||
.ok_or_else(|| error::Load::ChangeNotBlob(tree.id().into()))?;
|
|
||||||
contents_blob.content().to_owned()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_commit<O>(
|
fn write_commit<O>(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
typename: args.typename,
|
manifest: Manifest {
|
||||||
|
typename: args.typename,
|
||||||
|
history_type: args.history_type,
|
||||||
|
},
|
||||||
history,
|
history,
|
||||||
id: init_change.id().into(),
|
id: init_change.id().into(),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue