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:
```
$ 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 .
@ -14,11 +14,9 @@ Initializing local 🌱 project in .
"defaultBranch": "master"
}
✓ Syncing inventory..
✓ Announcing inventory..
Your project id is rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji. You can show it any time by running:
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:
```
$ 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 .

View File

@ -33,8 +33,8 @@ Options
--default-branch The default branch of the project
--set-upstream, -u Setup the upstream of the default branch
--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-sync Don't announce the new project to the network
--help Print help
"#,
};
@ -48,7 +48,7 @@ pub struct Options {
pub interactive: Interactive,
pub setup_signing: bool,
pub set_upstream: bool,
pub sync: bool,
pub announce: bool,
pub track: bool,
}
@ -65,7 +65,7 @@ impl Args for Options {
let mut interactive = Interactive::Yes;
let mut set_upstream = false;
let mut setup_signing = false;
let mut sync = true;
let mut announce = false;
let mut track = true;
while let Some(arg) = parser.next()? {
@ -108,15 +108,12 @@ impl Args for Options {
Long("setup-signing") => {
setup_signing = true;
}
Long("announce") => {
announce = true;
}
Long("no-confirm") => {
interactive = Interactive::No;
}
Long("sync") => {
sync = true;
}
Long("no-sync") => {
sync = false;
}
Long("no-track") => {
track = false;
}
@ -139,7 +136,7 @@ impl Args for Options {
interactive,
set_upstream,
setup_signing,
sync,
announce,
track,
},
vec![],
@ -241,7 +238,8 @@ pub fn init(options: Options, profile: &profile::Profile) -> anyhow::Result<()>
// Setup radicle signing key.
self::setup_signing(profile.id(), &repo, interactive)?;
}
if options.sync {
if node.is_running() {
let spinner = term::spinner("Syncing inventory..");
if let Err(e) = node.sync_inventory() {
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::info!(
"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::blank();
term::info!("To publish your project to the network, run:");
term::indented(term::format::secondary("rad push"));
if !options.announce {
term::blank();
term::info!("To publish your project to the network, run:");
term::indented(term::format::secondary("rad push"));
}
term::blank();
}
Err(err) => {

View File

@ -15,15 +15,13 @@ pub const HELP: Help = Help {
usage: r#"
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
--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
Git options
@ -40,7 +38,6 @@ pub struct Options {
pub force: bool,
pub all: bool,
pub set_upstream: bool,
pub sync: bool,
}
impl Args for Options {
@ -51,7 +48,6 @@ impl Args for Options {
let mut verbose = false;
let mut force = false;
let mut all = false;
let mut sync = None;
let mut set_upstream = false;
while let Some(arg) = parser.next()? {
@ -68,16 +64,6 @@ impl Args for Options {
Long("set-upstream") | Short('u') => {
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') => {
force = true;
}
@ -92,7 +78,6 @@ impl Args for Options {
force,
all,
set_upstream,
sync: sync.unwrap_or_default(),
verbose,
},
vec![],
@ -130,9 +115,5 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Err(err) => return Err(err.into()),
}
if options.sync {
term::warning("the `--sync` option is not yet supported");
}
Ok(())
}

View File

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

View File

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

View File

@ -165,6 +165,12 @@ fn command<H: Handle<Error = runtime::HandleError>>(
}
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() {
Ok(updated) => {
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))
}
fn announce_inventory(&mut self) -> Result<(), Error> {
self.command(service::Command::AnnounceInventory)
}
fn sync_inventory(&mut self) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1);
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 {
/// Announce repository references for given repository to peers.
AnnounceRefs(Id),
/// Announce local repositories to peers.
AnnounceInventory,
/// Announce local inventory to peers.
SyncInventory(chan::Sender<bool>),
/// 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 {
match self {
Self::AnnounceRefs(id) => write!(f, "AnnounceRefs({id})"),
Self::AnnounceInventory => write!(f, "AnnounceInventory"),
Self::SyncInventory(_) => write!(f, "SyncInventory(..)"),
Self::Connect(id, addr) => write!(f, "Connect({id}, {addr})"),
Self::Seeds(id, _) => write!(f, "Seeds({id})"),
@ -516,10 +519,19 @@ where
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) => {
let updated = self
.sync_and_announce_inventory()
.expect("Service::command: error syncing and announcing inventory");
.sync_inventory()
.expect("Service::command: error syncing inventory");
resp.send(!updated.is_empty()).ok();
}
Command::QueryState(query, sender) => {
@ -620,8 +632,21 @@ where
// cases.
// Announce the newly fetched repository to the network, if necessary.
if let Err(e) = self.sync_and_announce_inventory() {
error!(target: "service", "Failed to sync announce new inventory: {e}");
match self.sync_inventory() {
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.
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 updated = self.sync_routing(&inventory, self.node_id(), self.time())?;
if !updated.is_empty() {
self.announce_inventory(inventory)?;
}
Ok(updated)
}

View File

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

View File

@ -110,6 +110,8 @@ impl From<net::SocketAddr> for Address {
pub enum CommandName {
/// Announce repository references for given repository to peers.
AnnounceRefs,
/// Announce local repositories to peers.
AnnounceInventory,
/// Sync local inventory with node.
SyncInventory,
/// 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>;
/// Untrack the given node.
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>;
/// Announce local inventory.
fn announce_inventory(&mut self) -> Result<(), Self::Error>;
/// Notify the service that our inventory was updated.
fn sync_inventory(&mut self) -> Result<bool, Self::Error>;
/// Ask the service to shutdown.
@ -525,6 +529,13 @@ impl Handle for Node {
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> {
let mut line = self.call::<&str, _>(CommandName::SyncInventory, [])?;
let response: CommandResult = line.next().ok_or(Error::EmptyResponse {