cli: Give more control over `init` announcement

Instead of always announcing the inventory, by default we don't.
Users can run `rad push` to trigger an announcement.
This commit is contained in:
Alexis Sellier 2023-03-06 12:00:22 +01:00
parent 8c22012d61
commit e69be6051d
No known key found for this signature in database
11 changed files with 86 additions and 50 deletions

View File

@ -3,7 +3,7 @@ To create your first radicle project, navigate to a git repository, and run
the `init` command: the `init` command:
``` ```
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm $ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm --announce
Initializing local 🌱 project in . Initializing local 🌱 project in .
@ -14,11 +14,9 @@ Initializing local 🌱 project in .
"defaultBranch": "master" "defaultBranch": "master"
} }
✓ Syncing inventory.. ✓ Syncing inventory..
✓ Announcing inventory..
Your project id is rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji. You can show it any time by running: Your project id is rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji. You can show it any time by running:
rad . rad .
To publish your project to the network, run:
rad push
``` ```

View File

@ -3,7 +3,7 @@ To create your first radicle project, navigate to a git repository, and run
the `init` command: the `init` command:
``` ```
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm --no-sync --no-track $ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm --no-track
Initializing local 🌱 project in . Initializing local 🌱 project in .

View File

@ -33,8 +33,8 @@ Options
--default-branch The default branch of the project --default-branch The default branch of the project
--set-upstream, -u Setup the upstream of the default branch --set-upstream, -u Setup the upstream of the default branch
--setup-signing Setup the radicle key as a signing key for this repository --setup-signing Setup the radicle key as a signing key for this repository
--announce Announce the new project to the network
--no-confirm Don't ask for confirmation during setup --no-confirm Don't ask for confirmation during setup
--no-sync Don't announce the new project to the network
--help Print help --help Print help
"#, "#,
}; };
@ -48,7 +48,7 @@ pub struct Options {
pub interactive: Interactive, pub interactive: Interactive,
pub setup_signing: bool, pub setup_signing: bool,
pub set_upstream: bool, pub set_upstream: bool,
pub sync: bool, pub announce: bool,
pub track: bool, pub track: bool,
} }
@ -65,7 +65,7 @@ impl Args for Options {
let mut interactive = Interactive::Yes; let mut interactive = Interactive::Yes;
let mut set_upstream = false; let mut set_upstream = false;
let mut setup_signing = false; let mut setup_signing = false;
let mut sync = true; let mut announce = false;
let mut track = true; let mut track = true;
while let Some(arg) = parser.next()? { while let Some(arg) = parser.next()? {
@ -108,15 +108,12 @@ impl Args for Options {
Long("setup-signing") => { Long("setup-signing") => {
setup_signing = true; setup_signing = true;
} }
Long("announce") => {
announce = true;
}
Long("no-confirm") => { Long("no-confirm") => {
interactive = Interactive::No; interactive = Interactive::No;
} }
Long("sync") => {
sync = true;
}
Long("no-sync") => {
sync = false;
}
Long("no-track") => { Long("no-track") => {
track = false; track = false;
} }
@ -139,7 +136,7 @@ impl Args for Options {
interactive, interactive,
set_upstream, set_upstream,
setup_signing, setup_signing,
sync, announce,
track, track,
}, },
vec![], vec![],
@ -241,7 +238,8 @@ pub fn init(options: Options, profile: &profile::Profile) -> anyhow::Result<()>
// Setup radicle signing key. // Setup radicle signing key.
self::setup_signing(profile.id(), &repo, interactive)?; self::setup_signing(profile.id(), &repo, interactive)?;
} }
if options.sync {
if node.is_running() {
let spinner = term::spinner("Syncing inventory.."); let spinner = term::spinner("Syncing inventory..");
if let Err(e) = node.sync_inventory() { if let Err(e) = node.sync_inventory() {
spinner.error(e); spinner.error(e);
@ -250,6 +248,15 @@ pub fn init(options: Options, profile: &profile::Profile) -> anyhow::Result<()>
} }
} }
if options.announce {
let spinner = term::spinner("Announcing inventory..");
if let Err(e) = node.announce_inventory() {
spinner.error(e);
} else {
spinner.finish();
}
}
term::blank(); term::blank();
term::info!( term::info!(
"Your project id is {}. You can show it any time by running:", "Your project id is {}. You can show it any time by running:",
@ -257,9 +264,11 @@ pub fn init(options: Options, profile: &profile::Profile) -> anyhow::Result<()>
); );
term::indented(term::format::secondary("rad .")); term::indented(term::format::secondary("rad ."));
term::blank(); if !options.announce {
term::info!("To publish your project to the network, run:"); term::blank();
term::indented(term::format::secondary("rad push")); term::info!("To publish your project to the network, run:");
term::indented(term::format::secondary("rad push"));
}
term::blank(); term::blank();
} }
Err(err) => { Err(err) => {

View File

@ -15,15 +15,13 @@ pub const HELP: Help = Help {
usage: r#" usage: r#"
Usage Usage
rad push [--all] [--[no-]sync] [<option>...] rad push [--all] [<option>...]
By default, only the current branch is synced. By default, only the current branch is pushed.
Options Options
--all Push all branches (default: false) --all Push all branches (default: false)
--sync Sync after pushing to the "rad" remote (default: false)
--no-sync Do not sync after pushing to the "rad" remote
--help Print help --help Print help
Git options Git options
@ -40,7 +38,6 @@ pub struct Options {
pub force: bool, pub force: bool,
pub all: bool, pub all: bool,
pub set_upstream: bool, pub set_upstream: bool,
pub sync: bool,
} }
impl Args for Options { impl Args for Options {
@ -51,7 +48,6 @@ impl Args for Options {
let mut verbose = false; let mut verbose = false;
let mut force = false; let mut force = false;
let mut all = false; let mut all = false;
let mut sync = None;
let mut set_upstream = false; let mut set_upstream = false;
while let Some(arg) = parser.next()? { while let Some(arg) = parser.next()? {
@ -68,16 +64,6 @@ impl Args for Options {
Long("set-upstream") | Short('u') => { Long("set-upstream") | Short('u') => {
set_upstream = true; set_upstream = true;
} }
Long("sync") => {
// Falls back to `--no-sync` in case of ambiguity.
// eg. `rad push --no-sync --sync`
if sync.is_none() {
sync = Some(true);
}
}
Long("no-sync") => {
sync = Some(false);
}
Long("force") | Short('f') => { Long("force") | Short('f') => {
force = true; force = true;
} }
@ -92,7 +78,6 @@ impl Args for Options {
force, force,
all, all,
set_upstream, set_upstream,
sync: sync.unwrap_or_default(),
verbose, verbose,
}, },
vec![], vec![],
@ -130,9 +115,5 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Err(err) => return Err(err.into()), Err(err) => return Err(err.into()),
} }
if options.sync {
term::warning("the `--sync` option is not yet supported");
}
Ok(()) Ok(())
} }

View File

@ -388,6 +388,7 @@ fn test_replication_via_seed() {
"Radicle Heartwood Protocol & Stack", "Radicle Heartwood Protocol & Stack",
"--default-branch", "--default-branch",
"master", "master",
"--announce",
], ],
working.join("alice"), working.join("alice"),
) )

View File

@ -95,7 +95,7 @@ pub fn seed(dir: &Path) -> Context {
interactive: false.into(), interactive: false.into(),
setup_signing: false, setup_signing: false,
set_upstream: false, set_upstream: false,
sync: false, announce: false,
track: false, track: false,
}, },
&profile, &profile,

View File

@ -165,6 +165,12 @@ fn command<H: Handle<Error = runtime::HandleError>>(
} }
CommandResult::ok().to_writer(writer).ok(); CommandResult::ok().to_writer(writer).ok();
} }
CommandName::AnnounceInventory => {
if let Err(e) = handle.announce_inventory() {
return Err(CommandError::Runtime(e));
}
CommandResult::ok().to_writer(writer).ok();
}
CommandName::SyncInventory => match handle.sync_inventory() { CommandName::SyncInventory => match handle.sync_inventory() {
Ok(updated) => { Ok(updated) => {
CommandResult::Okay { updated }.to_writer(writer)?; CommandResult::Okay { updated }.to_writer(writer)?;

View File

@ -159,6 +159,10 @@ impl<G: Signer + Ecdh + 'static> radicle::node::Handle for Handle<G> {
self.command(service::Command::AnnounceRefs(id)) self.command(service::Command::AnnounceRefs(id))
} }
fn announce_inventory(&mut self) -> Result<(), Error> {
self.command(service::Command::AnnounceInventory)
}
fn sync_inventory(&mut self) -> Result<bool, Error> { fn sync_inventory(&mut self) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.command(service::Command::SyncInventory(sender))?; self.command(service::Command::SyncInventory(sender))?;

View File

@ -104,6 +104,8 @@ pub type QueryState = dyn Fn(&dyn ServiceState) -> Result<(), CommandError> + Se
pub enum Command { pub enum Command {
/// Announce repository references for given repository to peers. /// Announce repository references for given repository to peers.
AnnounceRefs(Id), AnnounceRefs(Id),
/// Announce local repositories to peers.
AnnounceInventory,
/// Announce local inventory to peers. /// Announce local inventory to peers.
SyncInventory(chan::Sender<bool>), SyncInventory(chan::Sender<bool>),
/// Connect to node with the given address. /// Connect to node with the given address.
@ -128,6 +130,7 @@ impl fmt::Debug for Command {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::AnnounceRefs(id) => write!(f, "AnnounceRefs({id})"), Self::AnnounceRefs(id) => write!(f, "AnnounceRefs({id})"),
Self::AnnounceInventory => write!(f, "AnnounceInventory"),
Self::SyncInventory(_) => write!(f, "SyncInventory(..)"), Self::SyncInventory(_) => write!(f, "SyncInventory(..)"),
Self::Connect(id, addr) => write!(f, "Connect({id}, {addr})"), Self::Connect(id, addr) => write!(f, "Connect({id}, {addr})"),
Self::Seeds(id, _) => write!(f, "Seeds({id})"), Self::Seeds(id, _) => write!(f, "Seeds({id})"),
@ -516,10 +519,19 @@ where
error!("Error announcing refs: {}", err); error!("Error announcing refs: {}", err);
} }
} }
Command::AnnounceInventory => {
if let Err(err) = self
.storage
.inventory()
.and_then(|i| self.announce_inventory(i))
{
error!("Error announcing inventory: {}", err);
}
}
Command::SyncInventory(resp) => { Command::SyncInventory(resp) => {
let updated = self let updated = self
.sync_and_announce_inventory() .sync_inventory()
.expect("Service::command: error syncing and announcing inventory"); .expect("Service::command: error syncing inventory");
resp.send(!updated.is_empty()).ok(); resp.send(!updated.is_empty()).ok();
} }
Command::QueryState(query, sender) => { Command::QueryState(query, sender) => {
@ -620,8 +632,21 @@ where
// cases. // cases.
// Announce the newly fetched repository to the network, if necessary. // Announce the newly fetched repository to the network, if necessary.
if let Err(e) = self.sync_and_announce_inventory() { match self.sync_inventory() {
error!(target: "service", "Failed to sync announce new inventory: {e}"); Ok(updated) => {
if !updated.is_empty() {
if let Err(e) = self
.storage
.inventory()
.and_then(|i| self.announce_inventory(i))
{
error!(target: "service", "Failed to announce inventory: {e}");
}
}
}
Err(e) => {
error!(target: "service", "Failed to sync inventory: {e}");
}
} }
} }
@ -1073,13 +1098,10 @@ where
} }
/// Sync, and if needed, announce our local inventory. /// Sync, and if needed, announce our local inventory.
fn sync_and_announce_inventory(&mut self) -> Result<Vec<Id>, Error> { fn sync_inventory(&mut self) -> Result<Vec<Id>, Error> {
let inventory = self.storage.inventory()?; let inventory = self.storage.inventory()?;
let updated = self.sync_routing(&inventory, self.node_id(), self.time())?; let updated = self.sync_routing(&inventory, self.node_id(), self.time())?;
if !updated.is_empty() {
self.announce_inventory(inventory)?;
}
Ok(updated) Ok(updated)
} }

View File

@ -59,6 +59,10 @@ impl radicle::node::Handle for Handle {
Ok(()) Ok(())
} }
fn announce_inventory(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn sync_inventory(&mut self) -> Result<bool, Self::Error> { fn sync_inventory(&mut self) -> Result<bool, Self::Error> {
unimplemented!() unimplemented!()
} }

View File

@ -110,6 +110,8 @@ impl From<net::SocketAddr> for Address {
pub enum CommandName { pub enum CommandName {
/// Announce repository references for given repository to peers. /// Announce repository references for given repository to peers.
AnnounceRefs, AnnounceRefs,
/// Announce local repositories to peers.
AnnounceInventory,
/// Sync local inventory with node. /// Sync local inventory with node.
SyncInventory, SyncInventory,
/// Connect to node with the given address. /// Connect to node with the given address.
@ -382,8 +384,10 @@ pub trait Handle {
fn untrack_repo(&mut self, id: Id) -> Result<bool, Self::Error>; fn untrack_repo(&mut self, id: Id) -> Result<bool, Self::Error>;
/// Untrack the given node. /// Untrack the given node.
fn untrack_node(&mut self, id: NodeId) -> Result<bool, Self::Error>; fn untrack_node(&mut self, id: NodeId) -> Result<bool, Self::Error>;
/// Notify the service that a project has been updated. /// Notify the service that a project has been updated, and announce local refs.
fn announce_refs(&mut self, id: Id) -> Result<(), Self::Error>; fn announce_refs(&mut self, id: Id) -> Result<(), Self::Error>;
/// Announce local inventory.
fn announce_inventory(&mut self) -> Result<(), Self::Error>;
/// Notify the service that our inventory was updated. /// Notify the service that our inventory was updated.
fn sync_inventory(&mut self) -> Result<bool, Self::Error>; fn sync_inventory(&mut self) -> Result<bool, Self::Error>;
/// Ask the service to shutdown. /// Ask the service to shutdown.
@ -525,6 +529,13 @@ impl Handle for Node {
Ok(()) Ok(())
} }
fn announce_inventory(&mut self) -> Result<(), Error> {
for line in self.call::<&str, CommandResult>(CommandName::AnnounceInventory, [])? {
line?;
}
Ok(())
}
fn sync_inventory(&mut self) -> Result<bool, Error> { fn sync_inventory(&mut self) -> Result<bool, Error> {
let mut line = self.call::<&str, _>(CommandName::SyncInventory, [])?; let mut line = self.call::<&str, _>(CommandName::SyncInventory, [])?;
let response: CommandResult = line.next().ok_or(Error::EmptyResponse { let response: CommandResult = line.next().ok_or(Error::EmptyResponse {