From 4bf15bf7ca867baa5e9d838d3fadd9036fb933b4 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Mon, 22 May 2023 11:38:59 +0200 Subject: [PATCH] remote-helper: Don't use external command for sync We use the library function which gives us more control over the output and removes the need to create a sub-process. --- radicle-remote-helper/src/push.rs | 71 ++++++++++++++++--------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/radicle-remote-helper/src/push.rs b/radicle-remote-helper/src/push.rs index 2171c1c9..5a5217d4 100644 --- a/radicle-remote-helper/src/push.rs +++ b/radicle-remote-helper/src/push.rs @@ -1,15 +1,16 @@ use std::collections::HashSet; -use std::ffi::OsStr; -use std::os::fd::{AsRawFd, FromRawFd}; use std::path::Path; use std::str::FromStr; -use std::{assert_eq, io, process}; +use std::time; +use std::{assert_eq, io}; use thiserror::Error; use radicle::cob::patch; use radicle::crypto::{PublicKey, Signer}; +use radicle::node; use radicle::node::{Handle, NodeId}; +use radicle::prelude::Id; use radicle::storage::git::cob::object::ParseObjectId; use radicle::storage::git::transport::local::Url; use radicle::storage::WriteRepository; @@ -20,6 +21,9 @@ use radicle_cli::terminal as cli; use crate::read_line; +/// Default timeout for syncing to the network after a push. +const DEFAULT_SYNC_TIMEOUT: time::Duration = time::Duration::from_secs(9); + #[derive(Debug, Error)] pub enum Error { /// Public key doesn't match the remote namespace we're pushing to. @@ -194,14 +198,10 @@ pub fn run( // Connect to local node and announce refs to the network. // If our node is not running, we simply skip this step, as the // refs will be announced eventually, when the node restarts. - if radicle::Node::new(profile.socket()).is_running() { - let rid = stored.id.to_string(); - let stderr = io::stderr().as_raw_fd(); + let node = radicle::Node::new(profile.socket()); + if node.is_running() { // Nb. allow this to fail. The push to local storage was still successful. - execute("rad", ["sync", &rid, "--announce", "--verbose"], unsafe { - process::Stdio::from_raw_fd(stderr) - }) - .ok(); + sync(stored.id, node).ok(); } } @@ -446,31 +446,32 @@ fn push_ref( Ok(()) } -/// Execute a command as a child process, redirecting its stdout to the given `Stdio`. -fn execute>( - name: &str, - args: impl IntoIterator, - stdout: process::Stdio, -) -> Result { - let mut cmd = process::Command::new(name); - cmd.args(args) - .stdout(stdout) - .stderr(process::Stdio::inherit()); +/// Sync with the network. +fn sync(rid: Id, mut node: radicle::Node) -> Result<(), radicle::node::Error> { + let seeds = node.seeds(rid)?; + let connected = seeds.connected().cloned().collect::>(); - let child = cmd.spawn()?; - let output = child.wait_with_output()?; - let status = output.status; - - if !status.success() { - let cmd = format!( - "{} {}", - cmd.get_program().to_string_lossy(), - cmd.get_args() - .collect::>() - .join(OsStr::new(" ")) - .to_string_lossy() - ); - return Err(Error::CommandFailed(cmd, status.code().unwrap_or(-1))); + if connected.is_empty() { + eprintln!("Not connected to any seeds."); + return Ok(()); } - Ok(String::from_utf8_lossy(&output.stdout).to_string()) + let mut spinner = cli::spinner_to( + format!("Syncing with {} node(s)..", connected.len()), + io::stderr(), + io::stderr(), + ); + let result = node.announce(rid, connected, DEFAULT_SYNC_TIMEOUT, |event| match event { + node::AnnounceEvent::Announced => {} + node::AnnounceEvent::RefsSynced { remote } => { + spinner.message(format!("Synced with {remote}..")); + } + })?; + + if result.synced.is_empty() { + spinner.failed(); + } else { + spinner.message(format!("Synced with {} node(s)", result.synced.len())); + spinner.finish(); + } + Ok(()) }