cli/fork: Use clap

This commit is contained in:
Lorenz Leutgeb 2025-10-01 23:07:02 +02:00 committed by Erik Kundt
parent 3992d519c3
commit 7b8da0e72f
4 changed files with 53 additions and 51 deletions

View File

@ -1,66 +1,23 @@
use std::ffi::OsString;
mod args;
use anyhow::Context as _;
use radicle::prelude::RepoId;
use radicle::rad;
use crate::terminal as term;
use crate::terminal::args;
use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help {
name: "fork",
description: "Create a fork of a repository",
version: env!("RADICLE_VERSION"),
usage: r#"
Usage
pub use args::Args;
pub(crate) use args::ABOUT;
rad fork [<rid>] [<option>...]
Options
--help Print help
"#,
};
pub struct Options {
rid: Option<RepoId>,
}
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 rid = None;
if let Some(arg) = parser.next()? {
match arg {
Long("help") | Short('h') => {
return Err(Error::Help.into());
}
Value(val) if rid.is_none() => {
rid = Some(args::rid(&val)?);
}
_ => anyhow::bail!(arg.unexpected()),
}
}
Ok((Options { rid }, vec![]))
}
}
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
let profile = ctx.profile()?;
let signer = profile.signer()?;
let storage = &profile.storage;
let rid = match options.rid {
let rid = match args.rid {
Some(rid) => rid,
None => {
let (_, rid) =
radicle::rad::cwd().context("Current directory is not a Radicle repository")?;
let (_, rid) = rad::cwd().context("Current directory is not a Radicle repository")?;
rid
}

View File

@ -0,0 +1,39 @@
use radicle::identity::RepoId;
pub(crate) const ABOUT: &str = "Create a fork of a repository";
#[derive(Debug, clap::Parser)]
#[command(about = ABOUT, disable_version_flag = true)]
pub struct Args {
/// The Repository ID of the repository to fork
///
/// [example values: rad:z3Tr6bC7ctEg2EHmLvknUr29mEDLH, z3Tr6bC7ctEg2EHmLvknUr29mEDLH]
#[arg(value_name = "RID")]
pub(super) rid: Option<RepoId>,
}
#[cfg(test)]
mod test {
use super::Args;
use clap::error::ErrorKind;
use clap::Parser;
#[test]
fn should_parse_rid_non_urn() {
let args = Args::try_parse_from(["fork", "z3Tr6bC7ctEg2EHmLvknUr29mEDLH"]);
assert!(args.is_ok())
}
#[test]
fn should_parse_rid_urn() {
let args = Args::try_parse_from(["fork", "rad:z3Tr6bC7ctEg2EHmLvknUr29mEDLH"]);
assert!(args.is_ok())
}
#[test]
fn should_not_parse_rid_url() {
let err =
Args::try_parse_from(["fork", "rad://z3Tr6bC7ctEg2EHmLvknUr29mEDLH"]).unwrap_err();
assert_eq!(err.kind(), ErrorKind::ValueValidation);
}
}

View File

@ -52,7 +52,10 @@ const COMMANDS: &[CommandItem] = &[
name: "debug",
about: crate::commands::debug::ABOUT,
},
CommandItem::Lexopt(crate::commands::fork::HELP),
CommandItem::Clap {
name: "fork",
about: crate::commands::fork::ABOUT,
},
CommandItem::Lexopt(crate::commands::help::HELP),
CommandItem::Lexopt(crate::commands::id::HELP),
CommandItem::Lexopt(crate::commands::init::HELP),

View File

@ -49,6 +49,7 @@ enum Commands {
Clean(clean::Args),
Clone(clone::Args),
Debug(debug::Args),
Fork(fork::Args),
Issue(issue::Args),
Path(path::Args),
Stats(stats::Args),
@ -215,7 +216,9 @@ pub(crate) fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyho
term::run_command_args::<follow::Options, _>(follow::HELP, follow::run, args.to_vec());
}
"fork" => {
term::run_command_args::<fork::Options, _>(fork::HELP, fork::run, args.to_vec());
if let Some(Commands::Fork(args)) = CliArgs::parse().command {
term::run_command_fn(fork::run, args);
}
}
"help" => {
term::run_command_args::<help::Options, _>(help::HELP, help::run, args.to_vec());