Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
radicle: use `git push` to avoid `libgit2` push
Fintan Halpenny committed 1 year ago
commit 8fd044833e40440e7b9d7a2c08281f404e5f5ed7
parent 433483e07aaee791c3c7ca6e9ffff1f24060ce26
2 files changed +64 -13
modified radicle-remote-helper/src/push.rs
@@ -1,7 +1,7 @@
#![allow(clippy::too_many_arguments)]
use std::collections::HashMap;
use std::io::IsTerminal;
-
use std::path::Path;
+
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{assert_eq, io};

@@ -30,6 +30,10 @@ use crate::{hint, read_line, warn, Options};

#[derive(Debug, Error)]
pub enum Error {
+
    #[error(
+
        "the Git repository found at {path:?} is a bare repository, expected a working directory"
+
    )]
+
    BareRepository { path: PathBuf },
    /// Public key doesn't match the remote namespace we're pushing to.
    #[error("cannot push to remote namespace owned by {0}")]
    KeyMismatch(Did),
@@ -777,12 +781,32 @@ fn push_ref(
    working: &git::raw::Repository,
    stored: &git::raw::Repository,
) -> Result<(), Error> {
-
    let mut remote = working.remote_anonymous(&git::url::File::new(stored.path()).to_string())?;
-
    let refspec = git::Refspec { src, dst, force };
-

+
    let url = git::url::File::new(stored.path()).to_string();
    // Nb. The *force* indicator (`+`) is processed by Git tooling before we even reach this code.
    // This happens during the `list for-push` phase.
-
    remote.push(&[refspec.to_string().as_str()], None)?;
+
    let refspec = git::Refspec { src, dst, force };
+
    let repo = working.workdir().ok_or(Error::BareRepository {
+
        path: working.path().to_path_buf(),
+
    })?;
+

+
    radicle::git::run::<_, _, &str, &str>(
+
        repo,
+
        [
+
            "push",
+
            url.to_string().as_str(),
+
            refspec.to_string().as_str(),
+
        ],
+
        [],
+
    )
+
    .map_err(|err| {
+
        Error::Io(std::io::Error::new(
+
            std::io::ErrorKind::Other,
+
            format!(
+
                "failed to run `git push {url} {refspec}` in {:?}: {err}",
+
                working.path()
+
            ),
+
        ))
+
    })?;

    Ok(())
}
modified radicle/src/rad.rs
@@ -1,6 +1,6 @@
#![allow(clippy::let_unit_value)]
use std::io;
-
use std::path::Path;
+
use std::path::{Path, PathBuf};
use std::str::FromStr;

use once_cell::sync::Lazy;
@@ -29,6 +29,10 @@ pub static PATCHES_REFNAME: Lazy<git::RefString> = Lazy::new(|| git::refname!("r

#[derive(Error, Debug)]
pub enum InitError {
+
    #[error(
+
        "the Git repository found at {path:?} is a bare repository, expected a working directory"
+
    )]
+
    BareRepository { path: PathBuf },
    #[error("doc: {0}")]
    Doc(#[from] DocError),
    #[error("repository: {0}")]
@@ -103,13 +107,36 @@ where

    git::configure_repository(repo)?;
    git::configure_remote(repo, &REMOTE_NAME, url, &url.clone().with_namespace(*pk))?;
-
    git::push(
-
        repo,
-
        &REMOTE_NAME,
-
        [(
-
            &git::fmt::lit::refs_heads(default_branch).into(),
-
            &git::fmt::lit::refs_heads(default_branch).into(),
-
        )],
+
    let branch = git::Qualified::from(git::fmt::lit::refs_heads(default_branch));
+
    // Pushes to default branch to the namespace of the `signer`
+
    let pushspec = git::Refspec {
+
        src: branch.clone(),
+
        dst: branch.with_namespace(git::Component::from(pk)),
+
        force: false,
+
    };
+
    git::run::<_, _, &str, &str>(
+
        repo.workdir().ok_or(InitError::BareRepository {
+
            path: repo.path().to_path_buf(),
+
        })?,
+
        [
+
            "push",
+
            &format!("{}", stored.path().canonicalize()?.display()),
+
            &pushspec.to_string(),
+
        ],
+
        [],
+
    )?;
+
    // N.b. we need to create the remote branch for the default branch
+
    let rad_remote =
+
        git::Qualified::from(git::lit::refs_remotes(&*REMOTE_COMPONENT)).join(default_branch);
+
    let oid = repo.refname_to_id(branch.as_str())?;
+
    repo.reference(
+
        rad_remote.as_str(),
+
        oid,
+
        false,
+
        &format!(
+
            "radicle: remote branch {}/{}",
+
            *REMOTE_COMPONENT, default_branch
+
        ),
    )?;
    stored.set_remote_identity_root_to(pk, identity)?;
    stored.set_identity_head_to(identity)?;