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.
This commit is contained in:
Alexis Sellier 2023-05-22 11:38:59 +02:00
parent cfc386ed0e
commit 4bf15bf7ca
No known key found for this signature in database
1 changed files with 36 additions and 35 deletions

View File

@ -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<S: AsRef<std::ffi::OsStr>>(
name: &str,
args: impl IntoIterator<Item = S>,
stdout: process::Stdio,
) -> Result<String, Error> {
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::<Vec<_>>();
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::<Vec<_>>()
.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(())
}