From ca71373ce37e6377d199ac285df999230049ab8e Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Tue, 15 Jan 2019 18:07:08 -0800 Subject: Auto-generate help text for Option-based arguments The previous change to properly format the help text for optional arguments left one thing out: parameters that are based on an Option as opposed to an enum. The problem with those is that we cannot simply ask the value (i.e., the Option) for all the variants of the inner type. Instead, we have to reference the actual type of the inner enum in order to retrieve all its possible variants. --- nitrocli/src/arg_util.rs | 6 ++++-- nitrocli/src/args.rs | 32 ++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/nitrocli/src/arg_util.rs b/nitrocli/src/arg_util.rs index b1ced25..9fa254b 100644 --- a/nitrocli/src/arg_util.rs +++ b/nitrocli/src/arg_util.rs @@ -109,8 +109,10 @@ macro_rules! Enum { /// replaced with a generated version of the enum's variants. macro_rules! fmt_enum { ( $enm:ident ) => {{ - $enm - .all() + fmt_enum!($enm.all()) + }}; + ( $all:expr ) => {{ + $all .iter() .map(::std::convert::AsRef::as_ref) .collect::<::std::vec::Vec<_>>() diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index e6267e7..bf252c3 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -420,7 +420,7 @@ fn otp_get(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { pub fn otp_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { let mut slot: u8 = 0; let mut algorithm = OtpAlgorithm::Totp; - let help = format!( + let algo_help = format!( "The OTP algorithm to use ({}, default: {})", fmt_enum!(algorithm), algorithm @@ -432,6 +432,10 @@ pub fn otp_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { let mut time_window: u16 = 30; let mut ascii = false; let mut secret_format: Option = None; + let fmt_help = format!( + "The format of the secret ({})", + fmt_enum!(OtpSecretFormat::all_variants()) + ); let mut parser = argparse::ArgumentParser::new(); parser.set_description("Configures a one-time password slot"); let _ = @@ -439,9 +443,10 @@ pub fn otp_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { .refer(&mut slot) .required() .add_argument("slot", argparse::Store, "The OTP slot to use"); - let _ = parser - .refer(&mut algorithm) - .add_option(&["-a", "--algorithm"], argparse::Store, &help); + let _ = + parser + .refer(&mut algorithm) + .add_option(&["-a", "--algorithm"], argparse::Store, &algo_help); let _ = parser.refer(&mut name).required().add_argument( "name", argparse::Store, @@ -475,7 +480,7 @@ pub fn otp_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { let _ = parser.refer(&mut secret_format).add_option( &["-f", "--format"], argparse::StoreOption, - "The format of the secret (ascii|base32|hex)", + &fmt_help, ); parse(ctx, &parser, args)?; drop(parser); @@ -744,9 +749,13 @@ fn parse_arguments<'io, 'ctx: 'io>( args: Vec, ) -> Result<(Command, ExecCtx<'io>, Vec)> { let mut model: Option = None; + let model_help = format!( + "Select the device model to connect to ({})", + fmt_enum!(DeviceModel::all_variants()) + ); let mut verbosity = 0; let mut command = Command::Status; - let help = cmd_help!(command); + let cmd_help = cmd_help!(command); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); let _ = parser.refer(&mut verbosity).add_option( @@ -754,16 +763,15 @@ fn parse_arguments<'io, 'ctx: 'io>( argparse::IncrBy::(1), "Increase the log level (can be supplied multiple times)", ); - let _ = parser.refer(&mut model).add_option( - &["-m", "--model"], - argparse::StoreOption, - "Select the device model to connect to (pro|storage)", - ); + let _ = + parser + .refer(&mut model) + .add_option(&["-m", "--model"], argparse::StoreOption, &model_help); parser.set_description("Provides access to a Nitrokey device"); let _ = parser .refer(&mut command) .required() - .add_argument("command", argparse::Store, &help); + .add_argument("command", argparse::Store, &cmd_help); let _ = parser.refer(&mut subargs).add_argument( "arguments", argparse::List, -- cgit v1.2.1