diff --git a/Cargo.lock b/Cargo.lock index caba0c3791..b8eadef512 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -306,6 +306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -320,6 +321,18 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "clap_lex" version = "0.7.4" diff --git a/Cargo.toml b/Cargo.toml index 1a8153d40c..ee94952ff3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,7 @@ features = ["clock", "std"] [dependencies.clap] version = "4.5.0" optional = true +features = ["derive"] [dependencies.crc] version = "3.0.0" diff --git a/src/bin/tools/cmds.rs b/src/bin/tools/cmds.rs index 2daba35b31..9264796bff 100644 --- a/src/bin/tools/cmds.rs +++ b/src/bin/tools/cmds.rs @@ -4,11 +4,12 @@ use std::path::PathBuf; -use clap::{Arg, ArgAction, ArgGroup, Command}; +use clap::{Arg, ArgAction, ArgGroup, Command, Parser}; -use crate::tools::{check_metadata, dump_metadata, legacy_pool}; - -use stratisd::stratis::VERSION; +use crate::{ + tools::{check_metadata, dump_metadata, legacy_pool}, + VERSION, +}; pub trait ToolCommand<'a> { fn name(&self) -> &'a str; @@ -16,57 +17,40 @@ pub trait ToolCommand<'a> { fn show_in_after_help(&self) -> bool; } -struct StratisDumpMetadata; - -impl StratisDumpMetadata { - fn cmd() -> Command { - Command::new("stratis-dumpmetadata") - .version(VERSION) - .about("Reads Stratis metadata from a Stratis device and displays it") - .next_line_help(true) - .arg( - Arg::new("dev") - .value_parser(clap::value_parser!(PathBuf)) - .required(true) - .help("Print metadata of given device"), - ) - .arg( - Arg::new("print_bytes") - .long("print-bytes") - .action(ArgAction::SetTrue) - .num_args(0) - .short('b') - .help("Print byte buffer of signature block"), - ) - .arg( - Arg::new("only") - .long("only") - .action(ArgAction::Set) - .value_name("PORTION") - .value_parser(["pool"]) - .help("Only print specified portion of the metadata"), - ) - } +#[derive(Parser)] +#[command( + version, + name = "stratis-dumpmetadata", + about = "Reads Stratis metadata from a Stratis device and displays it", + next_line_help = true +)] +struct StratisDumpMetadataCli { + /// Print metadata of given device + #[arg(required = true)] + dev: PathBuf, + + /// Print byte buffer of signature block + #[arg(action = ArgAction::SetTrue, long="print-bytes", num_args=0, short='b')] + print_bytes: bool, + + /// Only print specified portion of the metadata + #[arg(action = ArgAction::Set, long="only", value_name = "PORTION", value_parser=["pool"])] + only: Option, } +struct StratisDumpMetadata; + impl<'a> ToolCommand<'a> for StratisDumpMetadata { fn name(&self) -> &'a str { "stratis-dumpmetadata" } fn run(&self, command_line_args: Vec) -> Result<(), String> { - let matches = StratisDumpMetadata::cmd().get_matches_from(command_line_args); - let devpath = matches - .get_one::("dev") - .expect("'dev' is a mandatory argument"); - + let matches = StratisDumpMetadataCli::parse_from(command_line_args); dump_metadata::run( - devpath, - matches.get_flag("print_bytes"), - matches - .get_one::("only") - .map(|v| v == "pool") - .unwrap_or(false), + &matches.dev, + matches.print_bytes, + matches.only.map(|v| v == "pool").unwrap_or(false), ) } @@ -75,35 +59,29 @@ impl<'a> ToolCommand<'a> for StratisDumpMetadata { } } -struct StratisCheckMetadata; - -impl StratisCheckMetadata { - fn cmd() -> Command { - Command::new("stratis-checkmetadata") - .version(VERSION) - .about("Check validity of Stratis metadata") - .next_line_help(true) - .arg( - Arg::new("file") - .value_parser(clap::value_parser!(PathBuf)) - .required(true) - .help("File containing pool-level metadata as JSON"), - ) - } +#[derive(Parser)] +#[command( + version, + name = "stratis-checkmetadata", + about = "Check validity of Stratis metadata", + next_line_help = true +)] +struct StratisCheckMetadataCli { + /// File containing pool-level metadata as JSON + #[arg(required = true)] + file: PathBuf, } +struct StratisCheckMetadata; + impl<'a> ToolCommand<'a> for StratisCheckMetadata { fn name(&self) -> &'a str { "stratis-checkmetadata" } fn run(&self, command_line_args: Vec) -> Result<(), String> { - let matches = StratisCheckMetadata::cmd().get_matches_from(command_line_args); - let infile = matches - .get_one::("file") - .expect("'file' is a mandatory argument"); - - check_metadata::run(infile, false) + let matches = StratisCheckMetadataCli::parse_from(command_line_args); + check_metadata::run(&matches.file, false) } fn show_in_after_help(&self) -> bool { @@ -111,35 +89,29 @@ impl<'a> ToolCommand<'a> for StratisCheckMetadata { } } -struct StratisPrintMetadata; - -impl StratisPrintMetadata { - fn cmd() -> Command { - Command::new("stratis-printmetadata") - .version(VERSION) - .about("Print a human-suitable representation of Stratis metadata") - .next_line_help(true) - .arg( - Arg::new("file") - .value_parser(clap::value_parser!(PathBuf)) - .required(true) - .help("File containing pool-level metadata as JSON"), - ) - } +#[derive(Parser)] +#[command( + version, + name = "stratis-printmetadata", + about = "Print a human-suitable representation of Stratis metadata", + next_line_help = true +)] +struct StratisPrintMetadataCli { + /// File containing pool-level metadata as JSON + #[arg(required = true)] + file: PathBuf, } +struct StratisPrintMetadata; + impl<'a> ToolCommand<'a> for StratisPrintMetadata { fn name(&self) -> &'a str { "stratis-printmetadata" } fn run(&self, command_line_args: Vec) -> Result<(), String> { - let matches = StratisPrintMetadata::cmd().get_matches_from(command_line_args); - let infile = matches - .get_one::("file") - .expect("'file' is a mandatory argument"); - - check_metadata::run(infile, true) + let matches = StratisPrintMetadataCli::parse_from(command_line_args); + check_metadata::run(&matches.file, true) } fn show_in_after_help(&self) -> bool { @@ -220,12 +192,14 @@ pub fn cmds<'a>() -> Vec>> { #[cfg(test)] mod tests { - use super::{StratisCheckMetadata, StratisDumpMetadata, StratisPrintMetadata}; + use clap::CommandFactory; + + use super::{StratisCheckMetadataCli, StratisDumpMetadataCli, StratisPrintMetadataCli}; #[test] fn test_dumpmetadata_parse_args() { - StratisCheckMetadata::cmd().debug_assert(); - StratisDumpMetadata::cmd().debug_assert(); - StratisPrintMetadata::cmd().debug_assert(); + StratisCheckMetadataCli::command().debug_assert(); + StratisDumpMetadataCli::command().debug_assert(); + StratisPrintMetadataCli::command().debug_assert(); } }