Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Re-use `HEAD` reference if it exists
Alexis Sellier committed 3 years ago
commit 19061244975c18e709e618176a4549d86131c8f1
parent 2ec320acecd030e5c0040cf5a440980e21f6ebca
5 files changed +56 -20
modified radicle/src/git.rs
@@ -31,8 +31,12 @@ pub const PROTOCOL_PORT: u16 = 9418;

#[derive(thiserror::Error, Debug)]
pub enum RefError {
-
    #[error("invalid ref name '{0}'")]
-
    InvalidName(format::RefString),
+
    #[error("ref name is not valid UTF-8")]
+
    InvalidName,
+
    #[error("unexpected symbolic ref: {0}")]
+
    Symbolic(RefString),
+
    #[error("unexpected unqualified ref: {0}")]
+
    Unqualified(RefString),
    #[error("invalid ref format: {0}")]
    Format(#[from] format::Error),
    #[error("expected ref to begin with 'refs/namespaces' but found '{0}'")]
@@ -67,8 +71,20 @@ pub mod refs {
    /// Where project information is kept.
    pub static IDENTITY_BRANCH: Lazy<RefString> = Lazy::new(|| refname!("radicle/id"));

-
    pub mod storage {
+
    /// Try to get a qualified reference from a generic reference.
+
    pub fn qualified_from<'a>(r: &'a git2::Reference) -> Result<(Qualified<'a>, Oid), RefError> {
+
        let name = r.name().ok_or(RefError::InvalidName)?;
+
        let refstr = RefStr::try_from_str(name)?;
+
        let target = r
+
            .target()
+
            .ok_or_else(|| RefError::Symbolic(refstr.to_owned()))?;
+
        let qualified = Qualified::from_refstr(refstr)
+
            .ok_or_else(|| RefError::Unqualified(refstr.to_owned()))?;
+

+
        Ok((qualified, target.into()))
+
    }

+
    pub mod storage {
        use super::*;

        /// Create the [`Namespaced`] `branch` under the `remote` namespace, i.e.
@@ -157,7 +173,7 @@ where
    match input.to_namespaced() {
        None => {
            let refname = Qualified::from_refstr(input)
-
                .ok_or_else(|| RefError::InvalidName(input.to_owned()))?;
+
                .ok_or_else(|| RefError::Unqualified(input.to_owned()))?;

            Ok((None, refname))
        }
modified radicle/src/rad.rs
@@ -154,15 +154,13 @@ pub fn fork<G: Signer, S: storage::WriteStorage>(
) -> Result<(), ForkError> {
    let me = signer.public_key();
    let repository = storage.repository(proj)?;
-
    let (canonical_id, project) = repository.project_identity()?;
-
    let (canonical_head, _) = repository.head()?;
+
    // TODO: We should get the id branch pointer from a stored canonical reference.
+
    let (canonical_id, _) = repository.project_identity()?;
+
    let (canonical_branch, canonical_head) = repository.head()?;
    let raw = repository.raw();

-
    // TODO: We should only get the project HEAD once we've stored the canonical identity
-
    // branch on disk. This way it can use what we stored, instead of recomputing it.
-

    raw.reference(
-
        &git::refs::storage::branch(me, &project.default_branch),
+
        &canonical_branch.with_namespace(me.into()),
        *canonical_head,
        false,
        &format!("creating default branch for {me}"),
@@ -353,7 +351,7 @@ mod tests {
            .unwrap();

        let project_repo = storage.repository(proj).unwrap();
-
        let (head, _) = project_repo.head().unwrap();
+
        let (_, head) = project_repo.head().unwrap();

        // Test canonical refs.
        assert_eq!(project_repo.raw().refname_to_id("HEAD").unwrap(), *head);
modified radicle/src/storage.rs
@@ -242,10 +242,20 @@ pub trait ReadRepository {

    fn blob_at<'a>(&'a self, oid: Oid, path: &'a Path) -> Result<git2::Blob<'a>, git_ext::Error>;

-
    /// Get the canonical head of this repository.
+
    /// Get the head of this repository.
+
    ///
+
    /// Returns the value of `HEAD` if it is set, otherwise computes the canonical head
+
    /// using [`ReadRepository::canonical_head`].
+
    ///
+
    /// Returns the [`Oid`] as well as the qualified reference name.
+
    fn head(&self) -> Result<(Qualified, Oid), ProjectError>;
+

+
    /// Compute the canonical head of this repository.
+
    ///
+
    /// Ignores any existing `HEAD` reference.
    ///
    /// Returns the [`Oid`] as well as the qualified reference name.
-
    fn head(&self) -> Result<(Oid, Qualified), ProjectError>;
+
    fn canonical_head(&self) -> Result<(Qualified, Oid), ProjectError>;

    /// Get the `reference` for the given `remote`.
    ///
modified radicle/src/storage/git.rs
@@ -487,10 +487,18 @@ impl ReadRepository for Repository {
        Repository::project(self)
    }

-
    fn head(&self) -> Result<(Oid, Qualified), ProjectError> {
-
        // TODO: We shouldn't need to re-construct the history here; we should use the cached
-
        // document head of the "trusted" (local) user for this project.
-
        // In the `fork` function for example, we call Repository::project_identity again,
+
    fn head(&self) -> Result<(Qualified, Oid), ProjectError> {
+
        // If `HEAD` is already set locally, just return that.
+
        if let Ok(head) = self.backend.head() {
+
            if let Ok((name, oid)) = git::refs::qualified_from(&head) {
+
                return Ok((name.to_owned(), oid));
+
            }
+
        }
+
        self.canonical_head()
+
    }
+

+
    fn canonical_head(&self) -> Result<(Qualified, Oid), ProjectError> {
+
        // TODO: In the `fork` function for example, we call Repository::project_identity again,
        // This should only be necessary once.
        let (_, project) = self.project_identity()?;
        let branch_ref = Qualified::from(lit::refs_heads(&project.default_branch));
@@ -509,7 +517,7 @@ impl ReadRepository for Repository {
            heads => raw.merge_base_many(heads),
        }?;

-
        Ok((oid.into(), branch_ref))
+
        Ok((branch_ref, oid.into()))
    }
}

@@ -631,7 +639,7 @@ impl WriteRepository for Repository {

    fn set_head(&self) -> Result<Oid, ProjectError> {
        let head_ref = refname!("HEAD");
-
        let (head, branch_ref) = self.head()?;
+
        let (branch_ref, head) = self.canonical_head()?;

        log::debug!("Setting ref {:?} -> {:?}", &branch_ref, head);
        self.raw()
modified radicle/src/test/storage.rs
@@ -78,7 +78,11 @@ impl ReadRepository for MockRepository {
        Ok(true)
    }

-
    fn head(&self) -> Result<(Oid, fmt::Qualified), ProjectError> {
+
    fn head(&self) -> Result<(fmt::Qualified, Oid), ProjectError> {
+
        todo!()
+
    }
+

+
    fn canonical_head(&self) -> Result<(fmt::Qualified, Oid), ProjectError> {
        todo!()
    }