diff --git a/radicle-cli/examples/rad-sync-without-node.md b/radicle-cli/examples/rad-sync-without-node.md new file mode 100644 index 00000000..4fdd49d6 --- /dev/null +++ b/radicle-cli/examples/rad-sync-without-node.md @@ -0,0 +1,16 @@ +When you try to track, clone, or sync without your node running, it gives you an error: + +``` ~alice (fail) +$ rad track rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 --no-fetch +✗ Track failed: to track a repository, your node must be running. To start it, run `rad node start` +``` + +``` ~bob (fail) +$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 +✗ Clone failed: to clone a repository, your node must be running. To start it, run `rad node start` +``` + +``` ~eve (fail) +$ rad sync --fetch rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 --seed z6MksmpU5b1dS7oaqF2bHXhQi1DWy2hB7Mh9CuN7y1DN6QSz +✗ Sync failed: to sync a repository, your node must be running. To start it, run `rad node start` +``` diff --git a/radicle-cli/src/commands/clone.rs b/radicle-cli/src/commands/clone.rs index 3f54713d..633ba94a 100644 --- a/radicle-cli/src/commands/clone.rs +++ b/radicle-cli/src/commands/clone.rs @@ -106,6 +106,13 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let profile = ctx.profile()?; let signer = term::signer(&profile)?; let mut node = radicle::Node::new(profile.socket()); + + if !node.is_running() { + anyhow::bail!( + "to clone a repository, your node must be running. To start it, run `rad node start`" + ); + } + let (working, doc, proj) = clone( options.id, options.announce, diff --git a/radicle-cli/src/commands/sync.rs b/radicle-cli/src/commands/sync.rs index df3a0e13..92bb97ac 100644 --- a/radicle-cli/src/commands/sync.rs +++ b/radicle-cli/src/commands/sync.rs @@ -182,6 +182,11 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { } }; let mut node = radicle::Node::new(profile.socket()); + if !node.is_running() { + anyhow::bail!( + "to sync a repository, your node must be running. To start it, run `rad node start`" + ); + } let mode = options.sync.mode; if [SyncDirection::Fetch, SyncDirection::Both].contains(&options.sync.direction) { diff --git a/radicle-cli/src/commands/track.rs b/radicle-cli/src/commands/track.rs index e285bd40..15a479c3 100644 --- a/radicle-cli/src/commands/track.rs +++ b/radicle-cli/src/commands/track.rs @@ -3,6 +3,7 @@ use std::time; use anyhow::anyhow; +use radicle::node; use radicle::node::tracking::{Alias, Scope}; use radicle::node::{Handle, NodeId}; use radicle::{prelude::*, Node}; @@ -118,10 +119,14 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { match options.op { Operation::TrackNode { nid, alias } => { - track_node(nid, alias, &mut node)?; + if let Err(node::Error::Connect(_)) = track_node(nid, alias, &mut node) { + anyhow::bail!("to track another node, your node must be running. To start it, run `rad node start`"); + } } Operation::TrackRepo { rid, scope } => { - track_repo(rid, scope, &mut node)?; + if let Err(node::Error::Connect(_)) = track_repo(rid, scope, &mut node) { + anyhow::bail!("to track a repository, your node must be running. To start it, run `rad node start`"); + } if options.fetch { sync::fetch( @@ -136,7 +141,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { Ok(()) } -pub fn track_repo(rid: Id, scope: Scope, node: &mut Node) -> anyhow::Result<()> { +pub fn track_repo(rid: Id, scope: Scope, node: &mut Node) -> Result<(), node::Error> { let tracked = node.track_repo(rid, scope)?; let outcome = if tracked { "updated" } else { "exists" }; @@ -148,7 +153,7 @@ pub fn track_repo(rid: Id, scope: Scope, node: &mut Node) -> anyhow::Result<()> Ok(()) } -pub fn track_node(nid: NodeId, alias: Option, node: &mut Node) -> anyhow::Result<()> { +pub fn track_node(nid: NodeId, alias: Option, node: &mut Node) -> Result<(), node::Error> { let tracked = node.track_node(nid, alias.clone())?; let outcome = if tracked { "updated" } else { "exists" }; diff --git a/radicle-cli/tests/commands.rs b/radicle-cli/tests/commands.rs index 54613db4..3437f6db 100644 --- a/radicle-cli/tests/commands.rs +++ b/radicle-cli/tests/commands.rs @@ -587,6 +587,37 @@ fn rad_clone_connect() { .unwrap(); } +#[test] +fn rad_sync_without_node() { + let mut environment = Environment::new(); + let alice = environment.node(Config::test(Alias::new("alice"))); + let bob = environment.node(Config::test(Alias::new("bob"))); + let mut eve = environment.node(Config::test(Alias::new("eve"))); + + let rid = Id::from_urn("rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5").unwrap(); + eve.tracking.track_repo(&rid, Scope::All).unwrap(); + + formula(&environment.tmp(), "examples/rad-sync-without-node.md") + .unwrap() + .home( + "alice", + alice.home.path(), + [("RAD_HOME", alice.home.path().display())], + ) + .home( + "bob", + bob.home.path(), + [("RAD_HOME", bob.home.path().display())], + ) + .home( + "eve", + eve.home.path(), + [("RAD_HOME", eve.home.path().display())], + ) + .run() + .unwrap(); +} + #[test] fn rad_self() { let mut environment = Environment::new();