From fab9d25b0a0adcb5c3ecd48d8001e90e9ac93a6b Mon Sep 17 00:00:00 2001 From: "Tony Arcieri (iqlusion)" Date: Tue, 24 May 2022 21:45:26 -0600 Subject: [PATCH] cli: migrate from `gumdrop` to `clap` v3 (#379) `gumdrop` was originally chosen for its minimalist set of dependencies, but `clap` v3 has a slimmed down set of dependencies and better UX. --- Cargo.lock | 113 +++++++++++++++++++++++++++++++----- cli/Cargo.toml | 2 +- cli/src/bin/yubikey/main.rs | 4 +- cli/src/commands.rs | 95 +++++------------------------- cli/src/commands/readers.rs | 4 +- cli/src/commands/status.rs | 4 +- 6 files changed, 120 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e0bed0..f01a7f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,45 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "3.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "lazy_static", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "const-oid" version = "0.7.1" @@ -332,24 +371,16 @@ dependencies = [ ] [[package]] -name = "gumdrop" -version = "0.8.1" +name = "hashbrown" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3" -dependencies = [ - "gumdrop_derive", -] +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] -name = "gumdrop_derive" -version = "0.8.1" +name = "heck" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -375,6 +406,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.3" @@ -511,6 +552,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "os_str_bytes" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" + [[package]] name = "p256" version = "0.11.0" @@ -613,6 +660,30 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.39" @@ -824,6 +895,12 @@ dependencies = [ "der 0.6.0", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.4.1" @@ -859,6 +936,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + [[package]] name = "thiserror" version = "1.0.31" @@ -1018,8 +1101,8 @@ dependencies = [ name = "yubikey-cli" version = "0.6.0-pre" dependencies = [ + "clap", "env_logger", - "gumdrop", "lazy_static", "log", "sha2 0.9.9", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index c58a825..644744f 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" rust-version = "1.56" [dependencies] -gumdrop = "0.8" +clap = { version = "3", features = ["derive"] } env_logger = "0.9" lazy_static = "1" log = "0.4" diff --git a/cli/src/bin/yubikey/main.rs b/cli/src/bin/yubikey/main.rs index 5df4617..87e4c00 100644 --- a/cli/src/bin/yubikey/main.rs +++ b/cli/src/bin/yubikey/main.rs @@ -8,9 +8,9 @@ unused_qualifications )] -use gumdrop::Options; +use clap::Parser; use yubikey_cli::commands::YubiKeyCli; fn main() { - YubiKeyCli::parse_args_default_or_exit().run(); + YubiKeyCli::parse().run() } diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 60bd2ab..993ab9c 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -4,62 +4,25 @@ pub mod readers; pub mod status; use self::{readers::ReadersCmd, status::StatusCmd}; -use crate::terminal::{self, STDOUT}; -use gumdrop::Options; -use std::{ - env, - io::{self, Write}, - process::exit, -}; -use termcolor::{ColorChoice, ColorSpec, WriteColor}; +use crate::terminal; +use clap::Parser; +use std::{env, process::exit}; +use termcolor::ColorChoice; use yubikey::{Serial, YubiKey}; /// The `yubikey` CLI utility -#[derive(Debug, Options)] +#[derive(Debug, Parser)] pub struct YubiKeyCli { - /// Obtain help about the current command - #[options(short = "h", help = "print help message")] - pub help: bool, - - /// Specify the serial number of the YubiKey to connect to - #[options( - short = "s", - long = "serial", - help = "serial number of the YubiKey to connect to" - )] + /// Serial number of the YubiKey to connect to + #[clap(short = 's', long = "serial")] pub serial: Option, /// Subcommand to execute. - #[options(command)] - pub command: Option, + #[clap(subcommand)] + pub command: Commands, } impl YubiKeyCli { - /// Print usage information - pub fn print_usage() -> io::Result<()> { - let mut stdout = STDOUT.lock(); - stdout.reset()?; - - let mut bold = ColorSpec::new(); - bold.set_bold(true); - - stdout.set_color(&bold)?; - writeln!( - stdout, - "{} {}", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_VERSION") - )?; - stdout.reset()?; - - writeln!(stdout, "{}", env!("CARGO_PKG_AUTHORS"))?; - writeln!(stdout, "{}", env!("CARGO_PKG_DESCRIPTION").trim())?; - writeln!(stdout)?; - writeln!(stdout, "{}", Commands::usage())?; - - Ok(()) - } - /// Run the underlying command type or print usage info and exit pub fn run(&self) { // TODO(tarcieri): make this more configurable @@ -70,10 +33,7 @@ impl YubiKeyCli { env_logger::builder().format_timestamp(None).init(); } - match &self.command { - Some(cmd) => cmd.run(self.yubikey_init()), - None => Self::print_usage().unwrap(), - } + self.command.run(self.yubikey_init()) } /// Initialize the YubiKey client driver @@ -92,22 +52,18 @@ impl YubiKeyCli { } /// Subcommands of this application -#[derive(Debug, Options)] +#[derive(Debug, Parser)] pub enum Commands { - /// `help` subcommand - #[options(help = "show help for a command")] - Help(HelpOpts), - /// `version` subcommand - #[options(help = "display version information")] + #[clap(about = "display version information")] Version(VersionOpts), /// `readers` subcommand - #[options(help = "list detected readers")] + #[clap(about = "list detected readers")] Readers(ReadersCmd), /// `status` subcommand - #[options(help = "show yubikey status")] + #[clap(about = "show yubikey status")] Status(StatusCmd), } @@ -115,7 +71,6 @@ impl Commands { /// Run the given command pub fn run(&self, yubikey: YubiKey) { match self { - Commands::Help(help) => help.run(), Commands::Version(version) => version.run(), Commands::Readers(list) => list.run(), Commands::Status(status) => status.run(yubikey), @@ -123,28 +78,8 @@ impl Commands { } } -/// Help options -#[derive(Debug, Options)] -pub struct HelpOpts { - #[options(free, help = "subcommand to get help for")] - free: Vec, -} - -impl HelpOpts { - fn run(&self) { - if let Some(command) = self.free.first() { - if let Some(usage) = Commands::command_usage(command) { - println!("{}", usage); - exit(1); - } - } - - println!("{}", Commands::usage()); - } -} - /// Version options -#[derive(Debug, Options)] +#[derive(Debug, Parser)] pub struct VersionOpts {} impl VersionOpts { diff --git a/cli/src/commands/readers.rs b/cli/src/commands/readers.rs index a3f2f61..2f48ad9 100644 --- a/cli/src/commands/readers.rs +++ b/cli/src/commands/readers.rs @@ -1,7 +1,7 @@ //! List detected readers use crate::terminal::STDOUT; -use gumdrop::Options; +use clap::Parser; use std::{ io::{self, Write}, process::exit, @@ -10,7 +10,7 @@ use termcolor::{ColorSpec, StandardStreamLock, WriteColor}; use yubikey::{Context, Serial}; /// The `readers` subcommand -#[derive(Debug, Options)] +#[derive(Debug, Parser)] pub struct ReadersCmd {} impl ReadersCmd { diff --git a/cli/src/commands/status.rs b/cli/src/commands/status.rs index 5ad5115..09a81c6 100644 --- a/cli/src/commands/status.rs +++ b/cli/src/commands/status.rs @@ -1,7 +1,7 @@ //! Print device status use crate::terminal::{print_cert_info, STDOUT}; -use gumdrop::Options; +use clap::Parser; use std::io::{self, Write}; use termcolor::{ColorSpec, StandardStreamLock, WriteColor}; use yubikey::{piv::*, YubiKey}; @@ -10,7 +10,7 @@ use yubikey::{piv::*, YubiKey}; const NONE_STR: &str = ""; /// The `status` subcommand -#[derive(Debug, Options)] +#[derive(Debug, Parser)] pub struct StatusCmd {} impl StatusCmd {