diff --git a/crates/radicle-cli/examples/rad-init-private-clone.md b/crates/radicle-cli/examples/rad-init-private-clone.md index 6598511b..a5249881 100644 --- a/crates/radicle-cli/examples/rad-init-private-clone.md +++ b/crates/radicle-cli/examples/rad-init-private-clone.md @@ -10,7 +10,7 @@ $ rad clone rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --seed z6MknSLrJoTcukLrE435hVNQT4J Fetching rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu from the network, found 1 potential seed(s). ✗ Target not met: could not fetch from [z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi], and required 1 more seed(s) ! Warning: Failed to fetch from 1 seed(s). -! Warning: z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi: failed to perform fetch handshake +! Warning: z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi: failed to perform fetch handshake: [..] ✗ Error: no seeds found for rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu ``` diff --git a/crates/radicle-fetch/src/handle.rs b/crates/radicle-fetch/src/handle.rs index 821b1636..b7ae6a9c 100644 --- a/crates/radicle-fetch/src/handle.rs +++ b/crates/radicle-fetch/src/handle.rs @@ -83,8 +83,6 @@ impl Handle { } pub mod error { - use std::io; - use radicle::node::policy; use radicle::prelude::RepoId; use radicle::{git, storage}; @@ -92,8 +90,6 @@ pub mod error { #[derive(Debug, Error)] pub enum Init { - #[error(transparent)] - Io(#[from] io::Error), #[error(transparent)] Tracking(#[from] policy::config::Error), } diff --git a/crates/radicle-fetch/src/lib.rs b/crates/radicle-fetch/src/lib.rs index 348a6c72..432d69a6 100644 --- a/crates/radicle-fetch/src/lib.rs +++ b/crates/radicle-fetch/src/lib.rs @@ -9,7 +9,6 @@ mod refs; mod stage; mod state; -use std::io; use std::time::Instant; use gix_protocol::handshake; @@ -28,11 +27,8 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum Error { - #[error("failed to perform fetch handshake")] - Handshake { - #[source] - err: io::Error, - }, + #[error("failed to perform fetch handshake: {0}")] + Handshake(#[from] Box), #[error("failed to load `rad/id`")] Identity { #[source] @@ -128,8 +124,11 @@ fn perform_handshake(handle: &mut Handle) -> Result Result<(&mut Self::Read, &mut Self::Write), Self::Error>; + fn open(&mut self) -> (&mut Self::Read, &mut Self::Write); } /// The ability to signal EOF to the server side so that it can stop /// serving for this fetch request. pub trait SignalEof { - type Error: std::error::Error + Send + Sync + 'static; - /// Since the git protocol is tunneled over an existing /// connection, we can't signal the end of the protocol via the /// usual means, which is to close the connection. Git also @@ -48,7 +45,7 @@ pub trait SignalEof { /// the git protocol. This message can then be processed by the /// remote worker to end the protocol. We use the special "eof" /// control message for this. - fn eof(&mut self) -> Result<(), Self::Error>; + fn eof(&mut self) -> io::Result<()>; } /// Configuration for running a Git `handshake`, `ls-refs`, or @@ -59,6 +56,20 @@ pub struct Transport { stream: S, } +#[derive(Error, Debug)] +pub enum Error { + #[error("gix ls-refs error: {0}")] + LsRefs(#[from] gix_protocol::ls_refs::Error), + #[error("gix fetch error: {0}")] + Fetch(#[from] gix_protocol::fetch::Error), + #[error("empty or no packfile received")] + Empty, + #[error("wanted object not found: {0}")] + NotFound(Oid), + #[error("gix pack index error: {0}")] + PackIndex(#[from] gix_pack::index::init::Error), +} + impl Transport where S: ConnectionStream, @@ -79,16 +90,16 @@ where } /// Perform the handshake with the server side. - pub(crate) fn handshake(&mut self) -> io::Result { + pub(crate) fn handshake(&mut self) -> Result> { log::trace!(target: "fetch", "Performing handshake for {}", self.repo); - let (read, write) = self.stream.open().map_err(io_other)?; + let (read, write) = self.stream.open(); gix_protocol::fetch::handshake( &mut Connection::new(read, write, self.repo.clone()), |_| Ok(None), vec![], &mut progress::Discard, ) - .map_err(io_other) + .map_err(Box::new) } /// Perform ls-refs with the server side. @@ -96,11 +107,11 @@ where &mut self, mut prefixes: Vec, handshake: &handshake::Outcome, - ) -> io::Result> { + ) -> Result, Error> { prefixes.sort(); prefixes.dedup(); - let (read, write) = self.stream.open().map_err(io_other)?; - ls_refs::run( + let (read, write) = self.stream.open(); + Ok(ls_refs::run( ls_refs::Config { prefixes, repo: self.repo.clone(), @@ -108,8 +119,7 @@ where handshake, Connection::new(read, write, self.repo.clone()), &mut progress::Discard, - ) - .map_err(io_other) + )?) } /// Perform the fetch with the server side. @@ -118,7 +128,7 @@ where wants_haves: WantsHaves, interrupt: Arc, handshake: &handshake::Outcome, - ) -> io::Result> { + ) -> Result, Error> { log::trace!( target: "fetch", "Running fetch wants={:?}, haves={:?}", @@ -126,7 +136,7 @@ where wants_haves.haves ); let out = { - let (read, write) = self.stream.open().map_err(io_other)?; + let (read, write) = self.stream.open(); fetch::run( wants_haves.clone(), fetch::PackWriter { @@ -136,17 +146,11 @@ where handshake, Connection::new(read, write, self.repo.clone()), &mut progress::Discard, - ) - .map_err(io_other)? + )? }; let pack_path = out .pack - .ok_or_else(|| { - io::Error::new( - io::ErrorKind::UnexpectedEof, - "empty or no packfile received", - ) - })? + .ok_or(Error::Empty)? .index_path .expect("written packfile must have a path"); @@ -157,13 +161,10 @@ where { use gix_pack::index::File; - let idx = File::at(pack_path, gix_hash::Kind::Sha1).map_err(io_other)?; + let idx = File::at(pack_path, gix_hash::Kind::Sha1)?; for oid in wants_haves.wants { if idx.lookup(oid::to_object_id(oid)).is_none() { - return Err(io::Error::new( - io::ErrorKind::NotFound, - format!("wanted {oid} not found in pack"), - )); + return Err(Error::NotFound(oid)); } } } @@ -174,8 +175,8 @@ where /// Signal to the server side that we are done sending ls-refs and /// fetch commands. pub(crate) fn done(&mut self) -> io::Result<()> { - let (_, w) = self.stream.open().map_err(io_other)?; - w.eof().map_err(io_other) + let (_, w) = self.stream.open(); + w.eof() } } @@ -251,10 +252,6 @@ where } } -fn io_other(err: impl std::error::Error + Send + Sync + 'static) -> io::Error { - io::Error::other(err) -} - #[derive(Debug, Error)] pub enum WantsHavesError { #[error(transparent)] diff --git a/crates/radicle-fetch/src/transport/fetch.rs b/crates/radicle-fetch/src/transport/fetch.rs index 641fbfd9..5a038b34 100644 --- a/crates/radicle-fetch/src/transport/fetch.rs +++ b/crates/radicle-fetch/src/transport/fetch.rs @@ -22,8 +22,8 @@ pub mod error { #[derive(Debug, Error)] pub enum PackWriter { - #[error(transparent)] - Io(#[from] io::Error), + #[error("i/o error opening store: {0}")] + StoreOpen(#[from] io::Error), #[error(transparent)] Write(#[from] gix_pack::bundle::write::Error), } @@ -61,11 +61,10 @@ impl PackWriter { use_multi_pack_index: true, current_dir: Some(self.git_dir.clone()), }; - let thickener = Arc::new(gix_odb::Store::at_opts( - self.git_dir.join("objects"), - &mut [].into_iter(), - odb_opts, - )?); + let thickener = Arc::new( + gix_odb::Store::at_opts(self.git_dir.join("objects"), &mut [].into_iter(), odb_opts) + .map_err(error::PackWriter::StoreOpen)?, + ); let thickener = thickener.to_handle_arc(); Ok(pack::Bundle::write_to_directory( pack, diff --git a/crates/radicle-node/src/worker/channels.rs b/crates/radicle-node/src/worker/channels.rs index 1dd6f6b1..da994e0b 100644 --- a/crates/radicle-node/src/worker/channels.rs +++ b/crates/radicle-node/src/worker/channels.rs @@ -1,4 +1,3 @@ -use std::convert::Infallible; use std::io::{Read, Write}; use std::ops::Deref; use std::{fmt, io, time}; @@ -75,10 +74,9 @@ impl ChannelsFlush { impl radicle_fetch::transport::ConnectionStream for ChannelsFlush { type Read = ChannelReader; type Write = ChannelFlushWriter; - type Error = Infallible; - fn open(&mut self) -> Result<(&mut Self::Read, &mut Self::Write), Self::Error> { - Ok((&mut self.receiver, &mut self.sender)) + fn open(&mut self) -> (&mut Self::Read, &mut Self::Write) { + (&mut self.receiver, &mut self.sender) } } @@ -260,8 +258,6 @@ pub struct ChannelFlushWriter> { } impl radicle_fetch::transport::SignalEof for ChannelFlushWriter> { - type Error = io::Error; - fn eof(&mut self) -> io::Result<()> { self.writer.send(ChannelEvent::Eof)?; self.flush()