diff --git a/radicle-cob/src/object/collaboration.rs b/radicle-cob/src/object/collaboration.rs index a54a5503..ffc400e5 100644 --- a/radicle-cob/src/object/collaboration.rs +++ b/radicle-cob/src/object/collaboration.rs @@ -23,6 +23,9 @@ pub mod info; mod list; pub use list::list; +mod remove; +pub use remove::remove; + mod update; pub use update::{update, Update}; diff --git a/radicle-cob/src/object/collaboration/error.rs b/radicle-cob/src/object/collaboration/error.rs index b79c9997..0b1d45af 100644 --- a/radicle-cob/src/object/collaboration/error.rs +++ b/radicle-cob/src/object/collaboration/error.rs @@ -24,6 +24,13 @@ pub enum Create { SignerIsNotAuthor, } +#[derive(Debug, Error)] +#[error("failed to remove object: {err}")] +pub struct Remove { + #[source] + pub(crate) err: Box, +} + #[derive(Debug, Error)] pub enum Retrieve { #[error(transparent)] diff --git a/radicle-cob/src/object/collaboration/remove.rs b/radicle-cob/src/object/collaboration/remove.rs new file mode 100644 index 00000000..503ab028 --- /dev/null +++ b/radicle-cob/src/object/collaboration/remove.rs @@ -0,0 +1,33 @@ +// Copyright © 2022 The Radicle Link Contributors +// +// 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::{ObjectId, Store, TypeName}; + +use super::error; + +/// Remove a [`crate::CollaborativeObject`]. +/// +/// The `storage` is the backing storage for storing +/// [`crate::Change`]s at content-addressable locations. Please see +/// [`Store`] for further information. +/// +/// The `typename` is the type of object to be found, while the +/// `object_id` is the identifier for the particular object under that +/// type. +pub fn remove( + storage: &S, + identifier: &S::Identifier, + typename: &TypeName, + oid: &ObjectId, +) -> Result<(), error::Remove> +where + S: Store, +{ + storage + .remove(identifier, typename, oid) + .map_err(|e| error::Remove { err: e.into() })?; + + Ok(()) +} diff --git a/radicle-cob/src/object/storage.rs b/radicle-cob/src/object/storage.rs index 119be192..d0ce3382 100644 --- a/radicle-cob/src/object/storage.rs +++ b/radicle-cob/src/object/storage.rs @@ -61,6 +61,7 @@ pub trait Storage { type ObjectsError: Error + Send + Sync + 'static; type TypesError: Error + Send + Sync + 'static; type UpdateError: Error + Send + Sync + 'static; + type RemoveError: Error + Send + Sync + 'static; type Identifier; @@ -84,6 +85,14 @@ pub trait Storage { object_id: &ObjectId, change: &Change, ) -> Result<(), Self::UpdateError>; + + /// Remove a ref to a particular collaborative object + fn remove( + &self, + identifier: &Self::Identifier, + typename: &TypeName, + object_id: &ObjectId, + ) -> Result<(), Self::RemoveError>; } pub mod convert { diff --git a/radicle-cob/src/test/storage.rs b/radicle-cob/src/test/storage.rs index de479ab7..2178bd08 100644 --- a/radicle-cob/src/test/storage.rs +++ b/radicle-cob/src/test/storage.rs @@ -96,6 +96,7 @@ impl object::Storage for Storage { type ObjectsError = error::Objects; type TypesError = error::Objects; type UpdateError = git2::Error; + type RemoveError = git2::Error; type Identifier = Urn; @@ -157,4 +158,21 @@ impl object::Storage for Storage { self.raw.reference(&name, id.into(), true, "new change")?; Ok(()) } + + fn remove( + &self, + identifier: &Self::Identifier, + typename: &crate::TypeName, + object_id: &ObjectId, + ) -> Result<(), Self::RemoveError> { + let name = format!( + "refs/rad/{}/cobs/{}/{}", + identifier.to_path(), + typename, + object_id + ); + self.raw.find_reference(&name)?.delete()?; + + Ok(()) + } } diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 91855f63..b69c245b 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -705,6 +705,7 @@ impl cob::object::Storage for Repository { type ObjectsError = CobObjectsError; type TypesError = CobTypesError; type UpdateError = git2::Error; + type RemoveError = git2::Error; type Identifier = RemoteId; @@ -780,6 +781,19 @@ impl cob::object::Storage for Repository { Ok(()) } + + fn remove( + &self, + identifier: &Self::Identifier, + typename: &cob::TypeName, + object_id: &cob::ObjectId, + ) -> Result<(), Self::RemoveError> { + let mut reference = self + .backend + .find_reference(git::refs::storage::cob(identifier, typename, object_id).as_str())?; + + reference.delete().map_err(Self::RemoveError::from) + } } pub mod trailers {