From 51e18c27fce03d536df9c797b289d364b6727368 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Fri, 23 Sep 2022 20:08:58 +0200 Subject: [PATCH] Add `rad-push` Signed-off-by: Alexis Sellier --- radicle-tools/Cargo.toml | 4 ++++ radicle-tools/src/rad-push.rs | 19 +++++++++++++++++++ radicle/src/git.rs | 24 ++++++++++++++++++++++++ radicle/src/rad.rs | 15 ++++++++++++++- radicle/src/storage/git.rs | 18 +++++++++++------- radicle/src/storage/refs.rs | 2 +- 6 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 radicle-tools/src/rad-push.rs diff --git a/radicle-tools/Cargo.toml b/radicle-tools/Cargo.toml index 3a30e69d..35c31b65 100644 --- a/radicle-tools/Cargo.toml +++ b/radicle-tools/Cargo.toml @@ -23,3 +23,7 @@ path = "src/rad-auth.rs" [[bin]] name = "rad-self" path = "src/rad-self.rs" + +[[bin]] +name = "rad-push" +path = "src/rad-push.rs" diff --git a/radicle-tools/src/rad-push.rs b/radicle-tools/src/rad-push.rs new file mode 100644 index 00000000..b8b35fe0 --- /dev/null +++ b/radicle-tools/src/rad-push.rs @@ -0,0 +1,19 @@ +use std::path::Path; + +use radicle::storage::WriteStorage; + +fn main() -> anyhow::Result<()> { + let cwd = Path::new(".").canonicalize()?; + let repo = radicle::git::raw::Repository::open(&cwd)?; + let profile = radicle::Profile::load()?; + let (_, id) = radicle::rad::remote(&repo)?; + + let output = radicle::git::run(&cwd, &["push", "rad"])?; + println!("{}", output); + + let project = profile.storage.repository(&id)?; + let sigrefs = profile.storage.sign_refs(&project, &profile.signer)?; + println!("ok: {}", sigrefs.signature); + + Ok(()) +} diff --git a/radicle/src/git.rs b/radicle/src/git.rs index 67bfc607..ff5f42e6 100644 --- a/radicle/src/git.rs +++ b/radicle/src/git.rs @@ -1,4 +1,6 @@ +use std::io; use std::path::Path; +use std::process::Command; use std::str::FromStr; use git_ref_format as format; @@ -238,3 +240,25 @@ pub fn set_upstream( Ok(()) } + +/// Execute a git command by spawning a child process. +pub fn run, S: AsRef>( + repo: &P, + args: impl IntoIterator, +) -> Result { + let output = Command::new("git").current_dir(repo).args(args).output()?; + + if output.status.success() { + let out = if output.stdout.is_empty() { + &output.stderr + } else { + &output.stdout + }; + return Ok(String::from_utf8_lossy(out).into()); + } + + Err(io::Error::new( + io::ErrorKind::Other, + String::from_utf8_lossy(&output.stderr), + )) +} diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index 47b34dc2..931dc928 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -1,6 +1,7 @@ #![allow(clippy::let_unit_value)] use std::io; use std::path::Path; +use std::str::FromStr; use thiserror::Error; @@ -57,7 +58,7 @@ pub fn init( ) .verified()?; - let (id, _, project) = doc.create(pk, "Initialize Radicle", storage)?; + let (id, _, project) = doc.create(pk, "Initialize Radicle\n", storage)?; let url = storage.url(&id); git::set_upstream( @@ -299,6 +300,18 @@ pub fn checkout, S: storage::ReadStorage>( Ok(repo) } +/// Get the radicle ("rad") remote of a repository, and return the associated project id. +pub fn remote(repo: &git2::Repository) -> Result<(git2::Remote<'_>, Id), git2::Error> { + let remote = repo.find_remote(REMOTE_NAME)?; + let url = remote.url_bytes(); + let url = git::Url::from_bytes(url).unwrap(); + let path = url.path.to_string(); + let id = path.split('/').last().unwrap(); + let id = Id::from_str(id).unwrap(); + + Ok((remote, id)) +} + #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 093a93c6..ac1e71f6 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -91,13 +91,7 @@ impl WriteStorage for Storage { repository: &Repository, signer: G, ) -> Result, Error> { - let remote = signer.public_key(); - let refs = repository.references(remote)?; - let signed = refs.signed(&signer)?; - - signed.save(remote, repository)?; - - Ok(signed) + repository.sign_refs(signer) } fn fetch(&self, proj_id: &Id, remote: &Url) -> Result, FetchError> { @@ -370,6 +364,16 @@ impl Repository { ); Ok(remotes) } + + pub fn sign_refs(&self, signer: G) -> Result, Error> { + let remote = signer.public_key(); + let refs = self.references(remote)?; + let signed = refs.signed(&signer)?; + + signed.save(remote, self)?; + + Ok(signed) + } } impl ReadRepository for Repository { diff --git a/radicle/src/storage/refs.rs b/radicle/src/storage/refs.rs index 8c8841fc..36c833fc 100644 --- a/radicle/src/storage/refs.rs +++ b/radicle/src/storage/refs.rs @@ -288,7 +288,7 @@ impl SignedRefs { Some(&sigref), &author, &author, - &format!("Update {} for {}", sigref, remote), + &format!("Update signature for {}\n", remote), &tree, &parent.iter().collect::>(), );