cli: Implement `rad block` command

Blocks repos & nodes from beeing seeded/followed.
This commit is contained in:
cloudhead 2024-02-07 15:47:51 +01:00
parent d37c52aade
commit e5fcbba4c0
No known key found for this signature in database
6 changed files with 161 additions and 0 deletions

View File

@ -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 │
╰───────────────────────────────────────────────────────╯
```

View File

@ -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"]

View File

@ -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(())
}

View File

@ -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,

View File

@ -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,

View File

@ -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();