radicle_cli/commands/
block.rs

1use std::ffi::OsString;
2
3use radicle::node::policy::Policy;
4use radicle::prelude::{NodeId, RepoId};
5
6use crate::terminal as term;
7use crate::terminal::args;
8use crate::terminal::args::{Args, Error, Help};
9
10pub const HELP: Help = Help {
11    name: "block",
12    description: "Block repositories or nodes from being seeded or followed",
13    version: env!("RADICLE_VERSION"),
14    usage: r#"
15Usage
16
17    rad block <rid> [<option>...]
18    rad block <nid> [<option>...]
19
20    Blocks a repository from being seeded or a node from being followed.
21
22Options
23
24    --help          Print help
25"#,
26};
27
28enum Target {
29    Node(NodeId),
30    Repo(RepoId),
31}
32
33impl std::fmt::Display for Target {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            Self::Node(nid) => nid.fmt(f),
37            Self::Repo(rid) => rid.fmt(f),
38        }
39    }
40}
41
42pub struct Options {
43    target: Target,
44}
45
46impl Args for Options {
47    fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
48        use lexopt::prelude::*;
49
50        let mut parser = lexopt::Parser::from_args(args);
51        let mut target = None;
52
53        while let Some(arg) = parser.next()? {
54            match arg {
55                Long("help") | Short('h') => {
56                    return Err(Error::Help.into());
57                }
58                Value(val) if target.is_none() => {
59                    if let Ok(rid) = args::rid(&val) {
60                        target = Some(Target::Repo(rid));
61                    } else if let Ok(nid) = args::nid(&val) {
62                        target = Some(Target::Node(nid));
63                    } else {
64                        anyhow::bail!(
65                            "invalid repository or node specified, see `rad block --help`"
66                        )
67                    }
68                }
69                _ => anyhow::bail!(arg.unexpected()),
70            }
71        }
72
73        Ok((
74            Options {
75                target: target.ok_or(anyhow::anyhow!(
76                    "a repository or node to block must be specified, see `rad block --help`"
77                ))?,
78            },
79            vec![],
80        ))
81    }
82}
83
84pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
85    let profile = ctx.profile()?;
86    let mut policies = profile.policies_mut()?;
87
88    let updated = match options.target {
89        Target::Node(nid) => policies.set_follow_policy(&nid, Policy::Block)?,
90        Target::Repo(rid) => policies.set_seed_policy(&rid, Policy::Block)?,
91    };
92    if updated {
93        term::success!("Policy for {} set to 'block'", options.target);
94    }
95    Ok(())
96}