From 729a6e057ed1f78be62e1da0c98993226b1527df Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Mon, 30 Sep 2024 13:57:09 +0200 Subject: [PATCH] cobs: Fix COB drafts to work correctly --- .../src/commands/patch/review/builder.rs | 6 +- radicle-cob/src/object/collaboration/error.rs | 6 +- radicle/src/cob/patch.rs | 7 +- radicle/src/git.rs | 17 ++-- radicle/src/storage/git/cob.rs | 83 ++++++++----------- 5 files changed, 51 insertions(+), 68 deletions(-) diff --git a/radicle-cli/src/commands/patch/review/builder.rs b/radicle-cli/src/commands/patch/review/builder.rs index be420a51..f99911ff 100644 --- a/radicle-cli/src/commands/patch/review/builder.rs +++ b/radicle-cli/src/commands/patch/review/builder.rs @@ -635,11 +635,7 @@ impl<'a, G: Signer> ReviewBuilder<'a, G> { Brain::new(self.patch_id, signer.public_key(), base, repo)? }; let diff = self.diff(&brain.accepted, &tree, repo, opts)?; - let drafts = DraftStore::new(*signer.public_key(), self.repo).with( - signer.public_key(), - &cob::patch::TYPENAME, - &patch_id, - )?; + let drafts = DraftStore::new(self.repo, *signer.public_key()); let mut patches = cob::patch::Cache::no_cache(&drafts)?; let mut patch = patches.get_mut(&patch_id)?; let mut queue = ReviewQueue::from(diff); diff --git a/radicle-cob/src/object/collaboration/error.rs b/radicle-cob/src/object/collaboration/error.rs index d123bd7c..4b85b4c9 100644 --- a/radicle-cob/src/object/collaboration/error.rs +++ b/radicle-cob/src/object/collaboration/error.rs @@ -10,7 +10,7 @@ pub enum Create { Evaluate(Box), #[error(transparent)] CreateChange(#[from] git::change::error::Create), - #[error("failed to updated references for during object creation")] + #[error("failed to updated references for during object creation: {err}")] Refs { #[source] err: Box, @@ -40,7 +40,7 @@ pub enum Retrieve { Evaluate(Box), #[error(transparent)] Git(#[from] git2::Error), - #[error("failed to get references during object retrieval")] + #[error("failed to get references during object retrieval: {err}")] Refs { #[source] err: Box, @@ -63,7 +63,7 @@ pub enum Update { NoSuchObject, #[error(transparent)] CreateChange(#[from] git::change::error::Create), - #[error("failed to get references during object update")] + #[error("failed to get references during object update: {err}")] Refs { #[source] err: Box, diff --git a/radicle/src/cob/patch.rs b/radicle/src/cob/patch.rs index 19a1b575..b83f2ebc 100644 --- a/radicle/src/cob/patch.rs +++ b/radicle/src/cob/patch.rs @@ -3208,7 +3208,12 @@ mod test { let alice = test::setup::NodeWithRepo::default(); let checkout = alice.repo.checkout(); let branch = checkout.branch_with([("README", b"Hello World!")]); - let mut patches = Cache::no_cache(&*alice.repo).unwrap(); + let mut patches = { + let path = alice.tmp.path().join("cobs.db"); + let db = cob::cache::Store::open(path).unwrap(); + let store = cob::patch::Patches::open(&*alice.repo).unwrap(); + cob::patch::Cache::open(store, db) + }; let mut patch = patches .create( "My first patch", diff --git a/radicle/src/git.rs b/radicle/src/git.rs index 8677a1ae..19da1c6d 100644 --- a/radicle/src/git.rs +++ b/radicle/src/git.rs @@ -324,18 +324,15 @@ pub mod refs { .with_namespace(remote.into()) } - /// Draft collaborative objects of a type. + /// All draft collaborative object, identified by `typename` and `object_id`, for all remotes. /// - /// `refs/namespaces//refs/drafts/cobs//*` + /// `refs/namespaces/*/refs/drafts/cobs//` /// - pub fn cobs(remote: &RemoteId, typename: &cob::TypeName) -> PatternString { - Qualified::from_components( - component!("drafts"), - component!("cobs"), - Some(Component::from(typename)), - ) - .with_namespace(remote.into()) - .to_pattern(refspec::pattern!("*")) + pub fn cobs(typename: &cob::TypeName, object_id: &cob::ObjectId) -> PatternString { + refspec::pattern!("refs/namespaces/*") + .join(refname!("refs/drafts/cobs")) + .join(Component::from(typename)) + .join(Component::from(object_id)) } } diff --git a/radicle/src/storage/git/cob.rs b/radicle/src/storage/git/cob.rs index e7111b4a..a232e538 100644 --- a/radicle/src/storage/git/cob.rs +++ b/radicle/src/storage/git/cob.rs @@ -32,6 +32,8 @@ pub enum ObjectsError { Convert(#[from] cob::object::storage::convert::Error), #[error(transparent)] Git(#[from] git2::Error), + #[error(transparent)] + GitExt(#[from] git_ext::Error), } #[derive(Error, Debug)] @@ -178,38 +180,13 @@ impl cob::object::Storage for Repository { // which allows for some of the features needed for code review. For // example, users can draft comments and later decide to publish them. pub struct DraftStore<'a, R> { - remote: RemoteId, repo: &'a R, -} - -impl<'a, R: storage::WriteRepository> DraftStore<'a, R> { - /// Create this draft store with an existing COB from storage, so that changes applied - /// to this COB can evaluate properly. This creates a symbolic reference to the COB - /// pointing to the public COB reference. - pub fn with( - self, - remote: &RemoteId, - typename: &cob::TypeName, - id: &ObjectId, - ) -> Result { - let target = git::refs::storage::cob(remote, typename, id); - let name = git::refs::storage::draft::cob(remote, typename, id); - let repo = self.repo.raw(); - - repo.reference_symbolic( - name.as_str(), - target.as_str(), - true, // The reference may already exist, overwrite it if so. - format!("Link to COB {id} of type {typename}").as_str(), - )?; - - Ok(self) - } + remote: RemoteId, } impl<'a, R> DraftStore<'a, R> { - pub fn new(remote: RemoteId, repo: &'a R) -> Self { - Self { remote, repo } + pub fn new(repo: &'a R, remote: RemoteId) -> Self { + Self { repo, remote } } } @@ -398,33 +375,41 @@ impl<'a, R: storage::WriteRepository> cob::object::Storage for DraftStore<'a, R> typename: &cob::TypeName, object_id: &cob::ObjectId, ) -> Result { - // Nb. There can only be one draft per COB, per remote. - let Ok(r) = self.repo.raw().find_reference( - git::refs::storage::draft::cob(&self.remote, typename, object_id).as_str(), - ) else { - return Ok(Objects::default()); - }; - let r = cob::object::Reference::try_from(r).map_err(Self::ObjectsError::from)?; + let mut objs = Objects::default(); - Ok(Objects::new(r)) + // First get the signed COB tips of all remotes for this object. + let signed = self + .repo + .references_glob(&git::refs::storage::cobs(typename, object_id))?; + + for (r, id) in signed { + let r = cob::object::Reference { + name: r.to_ref_string(), + target: cob::object::Commit { id }, + }; + objs.push(r); + } + + // Then get the draft COB tip that belongs to us only, if any. + let draft_ref = &git::refs::storage::draft::cob(&self.remote, typename, object_id); + if let Ok(draft_oid) = self + .repo + .reference_oid(&self.remote, &draft_ref.strip_namespace()) + { + objs.push(cob::object::Reference { + name: draft_ref.to_ref_string(), + target: cob::object::Commit { id: draft_oid }, + }) + } + + Ok(objs) } fn types( &self, - typename: &cob::TypeName, + _typename: &cob::TypeName, ) -> Result, Self::TypesError> { - let glob = git::refs::storage::draft::cobs(&self.remote, typename); - let references = self.repo.references_glob(&glob)?; - let mut objs = BTreeMap::new(); - - for (name, id) in references { - let r = cob::object::Reference { - name: name.into_refstring(), - target: cob::object::Commit { id }, - }; - objs.insert(id.into(), Objects::new(r)); - } - Ok(objs) + unimplemented!() } fn update(