diff --git a/radicle/src/identity/doc.rs b/radicle/src/identity/doc.rs index c5c7fa52..f6aa04aa 100644 --- a/radicle/src/identity/doc.rs +++ b/radicle/src/identity/doc.rs @@ -18,6 +18,7 @@ use crate::crypto; use crate::crypto::{Signature, Unverified, Verified}; use crate::git; use crate::identity::{project::Project, Did}; +use crate::storage; use crate::storage::git::trailers; use crate::storage::{ReadRepository, RemoteId}; @@ -142,6 +143,13 @@ pub struct Doc { } impl Doc { + pub fn canonical_head(repo: &storage::git::Repository) -> Result { + repo.backend + .refname_to_id(storage::git::CANONICAL_IDENTITY.as_str()) + .map(Oid::from) + .map_err(DocError::from) + } + pub fn head(remote: &RemoteId, repo: &R) -> Result { repo.reference_oid(remote, &git::refs::storage::IDENTITY_BRANCH) .map_err(DocError::from) @@ -215,6 +223,11 @@ impl Doc { Ok((oid, sig)) } + pub fn canonical(repo: &storage::git::Repository) -> Result { + let oid = Self::canonical_head(repo)?; + Self::load_at(oid, repo) + } + pub fn load_at(oid: Oid, repo: &R) -> Result { let blob = Self::blob_at(oid, repo)?; let doc = Doc::from_json(blob.content())?.verified()?; diff --git a/radicle/src/storage.rs b/radicle/src/storage.rs index 7bfb8f00..e5e0ca31 100644 --- a/radicle/src/storage.rs +++ b/radicle/src/storage.rs @@ -353,6 +353,17 @@ pub trait ReadRepository { /// Returns the [`Oid`] as well as the qualified reference name. fn canonical_head(&self) -> Result<(Qualified, Oid), IdentityError>; + /// Get the head of the `rad/id` reference in this repository. + /// + /// Returns the reference pointed to by `rad/id` if it is set. Otherwise, computes the canonical + /// `rad/id` using [`ReadRepository::canonical_identity_head`]. + fn identity_head(&self) -> Result; + + /// Compute the canonical `rad/id` of this repository. + /// + /// Ignores any existing `rad/id` reference. + fn canonical_identity_head(&self) -> Result; + /// Get the `reference` for the given `remote`. /// /// Returns `None` is the reference did not exist. @@ -403,6 +414,8 @@ pub trait WriteRepository: ReadRepository { /// Set the repository head to the canonical branch. /// This computes the head based on the delegate set. fn set_head(&self) -> Result; + /// Set the repository 'rad/id' to the canonical commit, agreed by quorum. + fn set_identity_head(&self) -> Result; /// Sign the repository's refs under the `refs/rad/sigrefs` branch. fn sign_refs(&self, signer: &G) -> Result, Error>; /// Get the underlying git repository. diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 54ac640c..0e0a3131 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -28,6 +28,13 @@ pub static NAMESPACES_GLOB: Lazy = Lazy::new(|| refspec::pattern!("refs/namespaces/*")); pub static SIGREFS_GLOB: Lazy = Lazy::new(|| refspec::pattern!("refs/namespaces/*/rad/sigrefs")); +pub static CANONICAL_IDENTITY: Lazy = Lazy::new(|| { + git::Qualified::from_components( + git::name::component!("rad"), + git::name::component!("id"), + None, + ) +}); /// A parsed Git reference. #[derive(Debug, Clone, PartialEq, Eq)] @@ -584,6 +591,18 @@ impl ReadRepository for Repository { Ok((branch_ref, oid.into())) } + + fn identity_head(&self) -> Result { + match Doc::::canonical_head(self) { + Ok(oid) => Ok(oid), + Err(err) if err.is_not_found() => self.canonical_identity_head(), + Err(err) => Err(err.into()), + } + } + + fn canonical_identity_head(&self) -> Result { + Repository::identity_head(self) + } } impl WriteRepository for Repository { @@ -602,6 +621,20 @@ impl WriteRepository for Repository { Ok(head) } + fn set_identity_head(&self) -> Result { + let head = self.canonical_identity_head()?; + + log::debug!(target: "storage", "Setting ref: {} -> {}", *CANONICAL_IDENTITY, head); + self.raw().reference( + CANONICAL_IDENTITY.as_str(), + *head, + true, + "set-local-branch (radicle)", + )?; + + Ok(head) + } + fn sign_refs(&self, signer: &G) -> Result, Error> { let remote = signer.public_key(); let refs = self.references_of(remote)?; diff --git a/radicle/src/test/storage.rs b/radicle/src/test/storage.rs index 600a0b3d..8740485d 100644 --- a/radicle/src/test/storage.rs +++ b/radicle/src/test/storage.rs @@ -194,6 +194,14 @@ impl ReadRepository for MockRepository { ) -> Result<(Oid, crate::identity::Doc), IdentityError> { Ok((git2::Oid::zero().into(), self.doc.clone().unverified())) } + + fn identity_head(&self) -> Result { + todo!() + } + + fn canonical_identity_head(&self) -> Result { + todo!() + } } impl WriteRepository for MockRepository { @@ -211,4 +219,8 @@ impl WriteRepository for MockRepository { ) -> Result, Error> { todo!() } + + fn set_identity_head(&self) -> Result { + todo!() + } }