Skip to content
This repository was archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
cli: Implement rad block command
Browse files Browse the repository at this point in the history
Blocks repos & nodes from beeing seeded/followed.
  • Loading branch information
cloudhead committed Feb 7, 2024
1 parent d37c52a commit e5fcbba
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 0 deletions.
43 changes: 43 additions & 0 deletions radicle-cli/examples/rad-block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
When using an open seeding policy, it can be useful to block individual
repositories from being seeded.

For instance, if our default policy is to seed, any unknown repository will
have its policy set to allow seeding:
```
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --policy
Repository rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji is being seeded with scope `followed`
```

Since there is no policy specific to this repository, there's nothing to be
removed.

```
$ rad seed
No seeding policies to show.
```

But if we wanted to prevent this repository from being seeded, while
allowing all other repositories, we could use `rad block`:

```
$ rad block rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji
✓ Policy for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji set to 'block'
```

We can see that it is now no longer seeded:

```
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --policy
Repository rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji is not being seeded
```

And a 'block' policy was added:

```
$ rad seed
╭───────────────────────────────────────────────────────╮
│ RID Scope Policy │
├───────────────────────────────────────────────────────┤
│ rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji followed block │
╰───────────────────────────────────────────────────────╯
```
2 changes: 2 additions & 0 deletions radicle-cli/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#[path = "commands/auth.rs"]
pub mod rad_auth;
#[path = "commands/block.rs"]
pub mod rad_block;
#[path = "commands/checkout.rs"]
pub mod rad_checkout;
#[path = "commands/clean.rs"]
Expand Down
96 changes: 96 additions & 0 deletions radicle-cli/src/commands/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use std::ffi::OsString;

use radicle::node::policy::Policy;
use radicle::prelude::{NodeId, RepoId};

use crate::terminal as term;
use crate::terminal::args;
use crate::terminal::args::{Args, Error, Help};

pub const HELP: Help = Help {
name: "block",
description: "Block repositories or nodes from being seeded or followed",
version: env!("CARGO_PKG_VERSION"),
usage: r#"
Usage
rad block <rid> [<option>...]
rad block <nid> [<option>...]
Blocks a repository from being seeded or a node from being followed.
Options
--help Print help
"#,
};

enum Target {
Node(NodeId),
Repo(RepoId),
}

impl std::fmt::Display for Target {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Node(nid) => nid.fmt(f),
Self::Repo(rid) => rid.fmt(f),
}
}
}

pub struct Options {
target: Target,
}

impl Args for Options {
fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
use lexopt::prelude::*;

let mut parser = lexopt::Parser::from_args(args);
let mut target = None;

while let Some(arg) = parser.next()? {
match arg {
Long("help") | Short('h') => {
return Err(Error::Help.into());
}
Value(val) if target.is_none() => {
if let Ok(rid) = args::rid(&val) {
target = Some(Target::Repo(rid));
} else if let Ok(nid) = args::nid(&val) {
target = Some(Target::Node(nid));
} else {
return Err(anyhow::anyhow!(
"invalid repository or node specified, see `rad block --help`"
));
}
}
_ => return Err(anyhow::anyhow!(arg.unexpected())),
}
}

Ok((
Options {
target: target.ok_or(anyhow::anyhow!(
"a repository or node to block must be specified, see `rad block --help`"
))?,
},
vec![],
))
}
}

pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let profile = ctx.profile()?;
let mut policies = profile.policies_mut()?;

let updated = match options.target {
Target::Node(nid) => policies.set_follow_policy(&nid, Policy::Block)?,
Target::Repo(rid) => policies.set_seed_policy(&rid, Policy::Block)?,
};
if updated {
term::success!("Policy for {} set to 'block'", options.target);
}
Ok(())
}
1 change: 1 addition & 0 deletions radicle-cli/src/commands/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub const HELP: Help = Help {

const COMMANDS: &[Help] = &[
rad_auth::HELP,
rad_block::HELP,
rad_checkout::HELP,
rad_clone::HELP,
rad_config::HELP,
Expand Down
7 changes: 7 additions & 0 deletions radicle-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyhow::Error>>
args.to_vec(),
);
}
"block" => {
term::run_command_args::<rad_block::Options, _>(
rad_block::HELP,
rad_block::run,
args.to_vec(),
);
}
"checkout" => {
term::run_command_args::<rad_checkout::Options, _>(
rad_checkout::HELP,
Expand Down
12 changes: 12 additions & 0 deletions radicle-cli/tests/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,18 @@ fn rad_unseed() {
test("examples/rad-unseed.md", working, Some(&alice.home), []).unwrap();
}

#[test]
fn rad_block() {
let mut environment = Environment::new();
let alice = environment.node(Config {
policy: Policy::Allow,
..Config::test(Alias::new("alice"))
});
let working = tempfile::tempdir().unwrap();

test("examples/rad-block.md", working, Some(&alice.home), []).unwrap();
}

#[test]
fn rad_clone() {
let mut environment = Environment::new();
Expand Down

0 comments on commit e5fcbba

Please sign in to comment.