Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
cob: Add new history type, simplify `Content`
Alexis Sellier committed 3 years ago
commit 5526eceea020140a3c6604bb7e8e6a75e156d35e
parent 8dc655758ed515ae159cad3cb768d04d785c2bb1
12 files changed +80 -99
modified radicle-cob/src/backend/git/change.rs
@@ -96,13 +96,14 @@ impl change::Storage for git2::Repository {
    {
        let change::Create {
            typename,
+
            history_type,
            tips,
            message,
            contents,
        } = spec;
        let manifest = store::Manifest {
            typename,
-
            history_type: (&contents).into(),
+
            history_type,
        };

        let revision = write_manifest(self, &manifest, &contents)?;
@@ -200,7 +201,7 @@ fn load_contents(
    manifest: &store::Manifest,
) -> Result<entry::Contents, error::Load> {
    Ok(match manifest.history_type {
-
        HistoryType::Automerge => {
+
        HistoryType::Default | HistoryType::Automerge => {
            let contents_tree_entry = tree
                .get_name(CHANGE_BLOB_NAME)
                .ok_or_else(|| error::Load::NoChange(tree.id().into()))?;
@@ -208,7 +209,7 @@ fn load_contents(
            let contents_blob = contents_object
                .as_blob()
                .ok_or_else(|| error::Load::ChangeNotBlob(tree.id().into()))?;
-
            entry::Contents::automerge(contents_blob.content())
+
            contents_blob.content().to_owned()
        }
    })
}
modified radicle-cob/src/change/store.rs
@@ -47,6 +47,7 @@ pub trait Storage {

pub struct Create<Id> {
    pub typename: TypeName,
+
    pub history_type: HistoryType,
    pub tips: Vec<Id>,
    pub message: String,
    pub contents: Contents,
modified radicle-cob/src/history.rs
@@ -16,14 +16,17 @@ use crate::pruning_fold;
pub mod entry;
pub use entry::{Contents, Entry, EntryId};

-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
+
#[derive(
+
    Clone, Copy, Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
+
)]
+
#[serde(rename_all = "lowercase")]
pub enum HistoryType {
+
    #[default]
+
    Default,
    Automerge,
}

/// The DAG of changes making up the history of a collaborative object.
-
///
-
/// The `Author` represents the content address for the author of the change entry.
#[derive(Clone, Debug)]
pub struct History {
    graph: petgraph::Graph<Entry, (), petgraph::Directed, u32>,
modified radicle-cob/src/history/entry.rs
@@ -7,34 +7,9 @@ use git_ext::Oid;

use crate::pruning_fold;

-
use super::HistoryType;
-

-
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
-
pub enum Contents {
-
    Automerge(Vec<u8>),
-
}
-

-
impl Contents {
-
    pub fn automerge(bytes: &[u8]) -> Self {
-
        Self::Automerge(bytes.to_vec())
-
    }
-
}
-

-
impl From<&Contents> for HistoryType {
-
    fn from(c: &Contents) -> Self {
-
        match c {
-
            Contents::Automerge(..) => HistoryType::Automerge,
-
        }
-
    }
-
}
-

-
impl AsRef<[u8]> for Contents {
-
    fn as_ref(&self) -> &[u8] {
-
        match self {
-
            Self::Automerge(bytes) => bytes,
-
        }
-
    }
-
}
+
/// Entry contents.
+
/// This is the change payload.
+
pub type Contents = Vec<u8>;

/// A unique identifier for a history entry.
#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
modified radicle-cob/src/object/collaboration/create.rs
@@ -3,7 +3,7 @@
// This file is part of radicle-link, distributed under the GPLv3 with Radicle
// Linking Exception. For full terms see the included LICENSE file.

-
use crate::Store;
+
use crate::{HistoryType, Store};

use super::*;

@@ -11,6 +11,8 @@ use super::*;
pub struct Create<Author> {
    /// The identity of the author for this object's first change.
    pub author: Option<Author>,
+
    /// The type of history that will be used for this object.
+
    pub history_type: HistoryType,
    /// The CRDT history to initialize this object with.
    pub contents: Contents,
    /// The typename for this object.
@@ -23,6 +25,7 @@ impl<Author> Create<Author> {
    fn create_spec(&self) -> change::Create<git_ext::Oid> {
        change::Create {
            typename: self.typename.clone(),
+
            history_type: self.history_type,
            tips: Vec::new(),
            message: self.message.clone(),
            contents: self.contents.clone(),
modified radicle-cob/src/object/collaboration/update.rs
@@ -4,8 +4,8 @@
// Linking Exception. For full terms see the included LICENSE file.

use crate::{
-
    change, change_graph::ChangeGraph, identity::Identity, CollaborativeObject, Contents, ObjectId,
-
    Store, TypeName,
+
    change, change_graph::ChangeGraph, identity::Identity, CollaborativeObject, Contents,
+
    HistoryType, ObjectId, Store, TypeName,
};

use super::error;
@@ -14,6 +14,8 @@ use super::error;
pub struct Update<Author> {
    /// The identity of the author for the update of this object.
    pub author: Option<Author>,
+
    /// The type of history that will be used for this object.
+
    pub history_type: HistoryType,
    /// The CRDT changes to add to the object.
    pub changes: Contents,
    /// The object ID of the object to be updated.
@@ -60,6 +62,7 @@ where
        author,
        ref typename,
        object_id,
+
        history_type,
        changes,
        message,
    } = args;
@@ -89,6 +92,7 @@ where
        signer,
        change::Create {
            tips: object.tips().iter().cloned().collect(),
+
            history_type,
            contents: changes.clone(),
            typename: typename.clone(),
            message,
modified radicle-cob/src/tests.rs
@@ -6,7 +6,7 @@ use quickcheck::Arbitrary;
use radicle_crypto::Signer;

use crate::{
-
    create, get, history, list, object, test::arbitrary::Invalid, update, Create, ObjectId,
+
    create, get, list, object, test::arbitrary::Invalid, update, Create, HistoryType, ObjectId,
    TypeName, Update,
};

@@ -22,7 +22,6 @@ fn roundtrip() {
        project: proj,
        person: terry.clone(),
    };
-
    let contents = history::Contents::Automerge(Vec::new());
    let typename = "xyz.rad.issue".parse::<TypeName>().unwrap();
    let cob = create(
        &storage,
@@ -31,7 +30,8 @@ fn roundtrip() {
        &proj.identifier(),
        Create {
            author: Some(terry),
-
            contents,
+
            history_type: HistoryType::Automerge,
+
            contents: Vec::new(),
            typename: typename.clone(),
            message: "creating xyz.rad.issue".to_string(),
        },
@@ -63,7 +63,8 @@ fn list_cobs() {
        &proj.identifier(),
        Create {
            author: Some(terry.clone()),
-
            contents: history::Contents::Automerge(b"issue 1".to_vec()),
+
            history_type: HistoryType::Automerge,
+
            contents: b"issue 1".to_vec(),
            typename: typename.clone(),
            message: "creating xyz.rad.issue".to_string(),
        },
@@ -77,7 +78,8 @@ fn list_cobs() {
        &proj.identifier(),
        Create {
            author: Some(terry),
-
            contents: history::Contents::Automerge(b"issue 2".to_vec()),
+
            history_type: HistoryType::Automerge,
+
            contents: b"issue 2".to_vec(),
            typename: typename.clone(),
            message: "commenting xyz.rad.issue".to_string(),
        },
@@ -103,7 +105,6 @@ fn update_cob() {
        project: proj,
        person: terry.clone(),
    };
-
    let contents = history::Contents::Automerge(Vec::new());
    let typename = "xyz.rad.issue".parse::<TypeName>().unwrap();
    let cob = create(
        &storage,
@@ -112,7 +113,8 @@ fn update_cob() {
        &proj.identifier(),
        Create {
            author: Some(terry.clone()),
-
            contents,
+
            history_type: HistoryType::Automerge,
+
            contents: Vec::new(),
            typename: typename.clone(),
            message: "creating xyz.rad.issue".to_string(),
        },
@@ -130,7 +132,8 @@ fn update_cob() {
        &proj.identifier(),
        Update {
            author: Some(terry),
-
            changes: history::Contents::Automerge(b"issue 1".to_vec()),
+
            changes: b"issue 1".to_vec(),
+
            history_type: HistoryType::Automerge,
            object_id: *cob.id(),
            typename: typename.clone(),
            message: "commenting xyz.rad.issue".to_string(),
@@ -170,7 +173,8 @@ fn traverse_cobs() {
        &terry_proj.identifier(),
        Create {
            author: Some(terry),
-
            contents: history::Contents::Automerge(b"issue 1".to_vec()),
+
            contents: b"issue 1".to_vec(),
+
            history_type: HistoryType::Automerge,
            typename: typename.clone(),
            message: "creating xyz.rad.issue".to_string(),
        },
@@ -192,7 +196,8 @@ fn traverse_cobs() {
        &neil_proj.identifier(),
        Update {
            author: Some(neil),
-
            changes: history::Contents::Automerge(b"issue 2".to_vec()),
+
            changes: b"issue 2".to_vec(),
+
            history_type: HistoryType::Automerge,
            object_id: *cob.id(),
            typename,
            message: "commenting on xyz.rad.issue".to_string(),
@@ -210,7 +215,7 @@ fn traverse_cobs() {

        if let (Some(author), Some(project)) = (author, project) {
            if project.delegate_check(&author) {
-
                acc.push(entry.contents().as_ref().to_vec())
+
                acc.push(entry.contents().to_vec())
            }
        }
        ControlFlow::Continue(acc)
@@ -220,7 +225,7 @@ fn traverse_cobs() {

    // traverse over the history and filter by changes that were only authorized by neil
    let contents = updated.history().traverse(Vec::new(), |mut acc, entry| {
-
        acc.push(entry.contents().as_ref().to_vec());
+
        acc.push(entry.contents().to_vec());
        ControlFlow::Continue(acc)
    });

modified radicle/src/cob.rs
@@ -9,7 +9,7 @@ pub mod value;

pub use cob::{
    identity, object::collaboration::error, CollaborativeObject, Contents, Create, Entry, History,
-
    ObjectId, TypeName, Update,
+
    HistoryType, ObjectId, TypeName, Update,
};
pub use shared::Timestamp;
pub use store::Store;
modified radicle/src/cob/issue.rs
@@ -135,16 +135,13 @@ impl FromHistory for Issue {

    fn from_history(history: &History) -> Result<Self, Error> {
        let doc = history.traverse(Automerge::new(), |mut doc, entry| {
-
            match entry.contents() {
-
                Contents::Automerge(bytes) => {
-
                    match automerge::Change::from_bytes(bytes.clone()) {
-
                        Ok(change) => {
-
                            doc.apply_changes([change]).ok();
-
                        }
-
                        Err(_err) => {
-
                            // Ignore
-
                        }
-
                    }
+
            let bytes = entry.contents();
+
            match automerge::Change::from_bytes(bytes.clone()) {
+
                Ok(change) => {
+
                    doc.apply_changes([change]).ok();
+
                }
+
                Err(_err) => {
+
                    // Ignore
                }
            }
            ControlFlow::Continue(doc)
@@ -379,7 +376,7 @@ mod events {
            .map_err(|failure| failure.error)?
            .result;

-
        Ok(Contents::Automerge(doc.save_incremental()))
+
        Ok(doc.save_incremental())
    }

    pub fn comment(
@@ -414,7 +411,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = issue.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }

    pub fn lifecycle(
@@ -439,7 +436,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = issue.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }

    pub fn label(
@@ -466,7 +463,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = issue.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }

    pub fn reply(
@@ -503,7 +500,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = issue.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }

    pub fn react(
@@ -546,7 +543,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = issue.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }
}

modified radicle/src/cob/label.rs
@@ -43,16 +43,13 @@ impl TryFrom<&History> for Label {

    fn try_from(history: &History) -> Result<Self, Self::Error> {
        let doc = history.traverse(Automerge::new(), |mut doc, entry| {
-
            match entry.contents() {
-
                Contents::Automerge(bytes) => {
-
                    match automerge::Change::from_bytes(bytes.clone()) {
-
                        Ok(change) => {
-
                            doc.apply_changes([change]).ok();
-
                        }
-
                        Err(_err) => {
-
                            // Ignore
-
                        }
-
                    }
+
            let bytes = entry.contents();
+
            match automerge::Change::from_bytes(bytes.clone()) {
+
                Ok(change) => {
+
                    doc.apply_changes([change]).ok();
+
                }
+
                Err(_err) => {
+
                    // Ignore
                }
            }
            ControlFlow::Continue(doc)
@@ -143,7 +140,7 @@ mod events {
        )
        .map_err(|failure| failure.error)?;

-
        Ok(Contents::Automerge(doc.save_incremental()))
+
        Ok(doc.save_incremental())
    }
}

modified radicle/src/cob/patch.rs
@@ -161,16 +161,13 @@ impl TryFrom<&History> for Patch {

    fn try_from(history: &History) -> Result<Self, Self::Error> {
        let doc = history.traverse(Automerge::new(), |mut doc, entry| {
-
            match entry.contents() {
-
                Contents::Automerge(bytes) => {
-
                    match automerge::Change::from_bytes(bytes.clone()) {
-
                        Ok(change) => {
-
                            doc.apply_changes([change]).ok();
-
                        }
-
                        Err(_err) => {
-
                            // Ignore
-
                        }
-
                    }
+
            let bytes = entry.contents();
+
            match automerge::Change::from_bytes(bytes.clone()) {
+
                Ok(change) => {
+
                    doc.apply_changes([change]).ok();
+
                }
+
                Err(_err) => {
+
                    // Ignore
                }
            }
            ControlFlow::Continue(doc)
@@ -750,7 +747,7 @@ mod events {
            .map_err(|failure| failure.error)?
            .result;

-
        Ok(Contents::Automerge(doc.save_incremental()))
+
        Ok(doc.save_incremental())
    }

    pub fn comment(
@@ -788,7 +785,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = patch.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }

    pub fn update(
@@ -817,7 +814,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = patch.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok((revision_ix, Contents::Automerge(change)))
+
        Ok((revision_ix, change))
    }

    pub fn reply(
@@ -857,7 +854,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = patch.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }

    pub fn review(
@@ -888,7 +885,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = patch.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(((), Contents::Automerge(change)))
+
        Ok(((), change))
    }

    pub fn merge(
@@ -921,7 +918,7 @@ mod events {
        #[allow(clippy::unwrap_used)]
        let change = patch.get_last_local_change().unwrap().raw_bytes().to_vec();

-
        Ok(Contents::Automerge(change))
+
        Ok(change)
    }
}

modified radicle/src/cob/store.rs
@@ -11,7 +11,7 @@ use crate::cob::shared::Author;
use crate::cob::transaction::TransactionError;
use crate::cob::CollaborativeObject;
use crate::cob::{issue, label, patch};
-
use crate::cob::{Contents, Create, History, ObjectId, TypeName, Update};
+
use crate::cob::{Contents, Create, History, HistoryType, ObjectId, TypeName, Update};
use crate::crypto::PublicKey;
use crate::git;
use crate::identity::project;
@@ -134,6 +134,7 @@ impl<'a, T: FromHistory> Store<'a, T> {
            Update {
                author: Some(cob::Author::from(*signer.public_key())),
                object_id,
+
                history_type: HistoryType::Automerge,
                typename: T::type_name().clone(),
                message: message.to_owned(),
                changes,
@@ -154,6 +155,7 @@ impl<'a, T: FromHistory> Store<'a, T> {
            &self.project,
            Create {
                author: Some(cob::Author::from(*signer.public_key())),
+
                history_type: HistoryType::Automerge,
                typename: T::type_name().clone(),
                message: message.to_owned(),
                contents,
@@ -182,11 +184,7 @@ impl<'a, T: FromHistory> Store<'a, T> {
        };

        let doc = cob.history().traverse(Vec::new(), |mut doc, entry| {
-
            match entry.contents() {
-
                Contents::Automerge(bytes) => {
-
                    doc.extend(bytes);
-
                }
-
            }
+
            doc.extend(entry.contents());
            ControlFlow::Continue(doc)
        });