diff --git a/crates/radicle-cli/src/commands/block.rs b/crates/radicle-cli/src/commands/block.rs index c90e77a8..a1ad057a 100644 --- a/crates/radicle-cli/src/commands/block.rs +++ b/crates/radicle-cli/src/commands/block.rs @@ -4,7 +4,7 @@ use radicle::node::policy::Policy; use crate::terminal as term; -use args::Target; +use term::args::BlockTarget; pub use args::Args; pub(crate) use args::ABOUT; @@ -14,8 +14,8 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> { let mut policies = profile.policies_mut()?; let updated = match args.target { - Target::Node(nid) => policies.set_follow_policy(&nid, Policy::Block)?, - Target::Repo(rid) => policies.set_seed_policy(&rid, Policy::Block)?, + BlockTarget::Node(nid) => policies.set_follow_policy(&nid, Policy::Block)?, + BlockTarget::Repo(rid) => policies.set_seed_policy(&rid, Policy::Block)?, }; if updated { term::success!("Policy for {} set to 'block'", args.target); diff --git a/crates/radicle-cli/src/commands/block/args.rs b/crates/radicle-cli/src/commands/block/args.rs index 5f3aa003..1491f382 100644 --- a/crates/radicle-cli/src/commands/block/args.rs +++ b/crates/radicle-cli/src/commands/block/args.rs @@ -1,44 +1,9 @@ use clap::Parser; -use thiserror::Error; -use radicle::prelude::{NodeId, RepoId}; +use crate::terminal::args::BlockTarget; pub(crate) const ABOUT: &str = "Block repositories or nodes from being seeded or followed"; -#[derive(Clone, Debug)] -pub(super) enum Target { - Node(NodeId), - Repo(RepoId), -} - -#[derive(Debug, Error)] -#[error("invalid repository or node specified (RID parsing failed with: '{repo}', NID parsing failed with: '{node}'))")] -pub(super) struct ParseTargetError { - repo: radicle::identity::IdError, - node: radicle::crypto::PublicKeyError, -} - -impl std::str::FromStr for Target { - type Err = ParseTargetError; - - fn from_str(val: &str) -> Result { - val.parse::().map(Target::Repo).or_else(|repo| { - val.parse::() - .map(Target::Node) - .map_err(|node| ParseTargetError { repo, node }) - }) - } -} - -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), - } - } -} - #[derive(Parser, Debug)] #[command(about = ABOUT, disable_version_flag = true)] pub struct Args { @@ -46,7 +11,7 @@ pub struct Args { /// /// [example values: rad:z3Tr6bC7ctEg2EHmLvknUr29mEDLH, z6MkiswaKJ85vafhffCGBu2gdBsYoDAyHVBWRxL3j297fwS9] #[arg(value_name = "RID|NID")] - pub(super) target: Target, + pub(super) target: BlockTarget, } #[cfg(test)] diff --git a/crates/radicle-cli/src/terminal/args.rs b/crates/radicle-cli/src/terminal/args.rs index 33b2ee1f..19c697a0 100644 --- a/crates/radicle-cli/src/terminal/args.rs +++ b/crates/radicle-cli/src/terminal/args.rs @@ -4,8 +4,8 @@ use std::str::FromStr; use std::time; use anyhow::anyhow; - use clap::builder::TypedValueParser; +use thiserror::Error; use radicle::cob::{self, issue, patch}; use radicle::crypto; @@ -207,6 +207,43 @@ pub fn cob(val: &OsString) -> anyhow::Result { cob::ObjectId::from_str(&val).map_err(|_| anyhow!("invalid Object ID '{}'", val)) } +/// Targets used in the `block` and `unblock` commands +#[derive(Clone, Debug)] +pub(crate) enum BlockTarget { + Node(NodeId), + Repo(RepoId), +} + +#[derive(Debug, Error)] +#[error("invalid repository or node specified (RID parsing failed with: '{repo}', NID parsing failed with: '{node}'))")] +pub(crate) struct BlockTargetParseError { + repo: radicle::identity::IdError, + node: radicle::crypto::PublicKeyError, +} + +impl std::str::FromStr for BlockTarget { + type Err = BlockTargetParseError; + + fn from_str(val: &str) -> Result { + val.parse::() + .map(BlockTarget::Repo) + .or_else(|repo| { + val.parse::() + .map(BlockTarget::Node) + .map_err(|node| BlockTargetParseError { repo, node }) + }) + } +} + +impl std::fmt::Display for BlockTarget { + 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), + } + } +} + #[derive(Clone, Debug)] pub(crate) struct ScopeParser; @@ -231,3 +268,29 @@ impl TypedValueParser for ScopeParser { )) } } + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use super::BlockTarget; + use super::BlockTargetParseError; + + #[test] + fn should_parse_nid() { + let target = BlockTarget::from_str("z6MkiswaKJ85vafhffCGBu2gdBsYoDAyHVBWRxL3j297fwS9"); + assert!(target.is_ok()) + } + + #[test] + fn should_parse_rid() { + let target = BlockTarget::from_str("rad:z3Tr6bC7ctEg2EHmLvknUr29mEDLH"); + assert!(target.is_ok()) + } + + #[test] + fn should_not_parse() { + let err = BlockTarget::from_str("bee").unwrap_err(); + assert!(matches!(err, BlockTargetParseError { .. })); + } +}