diff --git a/radicle-cli/src/commands/clone.rs b/radicle-cli/src/commands/clone.rs index 4ca572e0..5679b30e 100644 --- a/radicle-cli/src/commands/clone.rs +++ b/radicle-cli/src/commands/clone.rs @@ -175,28 +175,33 @@ pub fn clone( // Get seeds. This consults the local routing table only. let mut seeds = node.seeds(id)?; - if !seeds.has_connections() { - return Err(CloneError::NotFound(id)); - } - // Fetch from all seeds. - for seed in seeds.connected() { - let spinner = term::spinner(format!( - "Fetching {} from {}..", - term::format::tertiary(id), - term::format::tertiary(term::format::node(seed)) - )); + if seeds.has_connections() { + // Fetch from all seeds. + for seed in seeds.connected() { + let spinner = term::spinner(format!( + "Fetching {} from {}..", + term::format::tertiary(id), + term::format::tertiary(term::format::node(seed)) + )); - // TODO: If none of them succeeds, output an error. Otherwise tell the caller - // how many succeeded. - match node.fetch(id, *seed)? { - FetchResult::Success { .. } => { - spinner.finish(); - } - FetchResult::Failed { reason } => { - spinner.error(reason); + // TODO: If none of them succeeds, output an error. Otherwise tell the caller + // how many succeeded. + match node.fetch(id, *seed)? { + FetchResult::Success { .. } => { + spinner.finish(); + } + FetchResult::Failed { reason } => { + spinner.error(reason); + } } } } + // TODO: Warn if no seeds were found, and we might be checking out stale data. + // If we don't have the project locally, even after attempting to fetch, + // there's nothing we can do. + if !storage.contains(&id)? { + return Err(CloneError::NotFound(id)); + } // Create a local fork of the project, under our own id. { diff --git a/radicle-cli/tests/commands.rs b/radicle-cli/tests/commands.rs index 14ecbc59..b30ae2f4 100644 --- a/radicle-cli/tests/commands.rs +++ b/radicle-cli/tests/commands.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use std::{thread, time}; use radicle::git; +use radicle::node::Handle as _; use radicle::prelude::Id; use radicle::profile::Home; use radicle::storage::{ReadRepository, ReadStorage}; @@ -293,6 +294,29 @@ fn rad_init_sync_and_clone() { .unwrap(); } +#[test] +// User tries to clone; no seeds are available, but user has the repo locally. +fn test_clone_without_seeds() { + logger::init(log::Level::Debug); + + let mut environment = Environment::new(); + let mut alice = environment.node("alice"); + let working = environment.tmp().join("working"); + let rid = alice.project("heartwood", "Radicle Heartwood Protocol & Stack"); + let mut alice = alice.spawn(Config::default()); + let seeds = alice.handle.seeds(rid).unwrap(); + + assert!(!seeds.has_connections()); + + alice + .rad("clone", &[rid.to_string().as_str()], working.as_path()) + .unwrap(); + + alice + .rad("inspect", &[], working.join("heartwood").as_path()) + .unwrap(); +} + #[test] // // alice -- seed -- bob diff --git a/radicle-node/src/test/environment.rs b/radicle-node/src/test/environment.rs index cca8f149..5b61e92e 100644 --- a/radicle-node/src/test/environment.rs +++ b/radicle-node/src/test/environment.rs @@ -1,3 +1,4 @@ +use std::io::BufRead as _; use std::mem::ManuallyDrop; use std::path::{Path, PathBuf}; use std::{ @@ -209,15 +210,21 @@ impl NodeHandle { .args(args) .output()?; + for line in io::BufReader::new(io::Cursor::new(&result.stdout)) + .lines() + .flatten() + { + log::debug!(target: "test", "rad {cmd}: {line}"); + } + log::debug!( target: "test", "Ran command `rad {cmd}` (status={})", result.status.code().unwrap() ); if !result.status.success() { - log::debug!(target: "test", "Command: {result:#?}"); + return Err(io::ErrorKind::Other.into()); } - Ok(()) } } diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index cffd5d14..23440e86 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -158,12 +158,12 @@ pub fn fork_remote( } pub fn fork( - proj: Id, + rid: Id, signer: &G, storage: &S, ) -> Result<(), ForkError> { let me = signer.public_key(); - let repository = storage.repository_mut(proj)?; + let repository = storage.repository_mut(rid)?; // TODO: We should get the id branch pointer from a stored canonical reference. let (canonical_id, _) = repository.identity_doc()?; let (canonical_branch, canonical_head) = repository.head()?;