From 47b070418aaaa746f2c7b5e31c4974757f65fa2a Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 6 Oct 2023 10:27:05 -0600 Subject: [PATCH] ectool: Use clap derive syntax Co-authored-by: Tim Crawford --- tool/Cargo.lock | 92 ++++++++++++++++++ tool/Cargo.toml | 2 +- tool/src/main.rs | 246 ++++++++++++++++++++--------------------------- 3 files changed, 198 insertions(+), 142 deletions(-) diff --git a/tool/Cargo.lock b/tool/Cargo.lock index 6910fd1..204c1ea 100644 --- a/tool/Cargo.lock +++ b/tool/Cargo.lock @@ -42,13 +42,28 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags", + "clap_derive", "clap_lex", "indexmap", + "once_cell", "strsim", "termcolor", "textwrap", ] +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "clap_lex" version = "0.2.4" @@ -70,6 +85,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -107,6 +128,12 @@ version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + [[package]] name = "os_str_bytes" version = "6.5.1" @@ -119,6 +146,48 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[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.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + [[package]] name = "redox_hwio" version = "0.1.6" @@ -131,6 +200,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "system76_ectool" version = "0.3.8" @@ -157,6 +237,18 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "winapi" version = "0.3.9" diff --git a/tool/Cargo.toml b/tool/Cargo.toml index 7807790..022bb47 100644 --- a/tool/Cargo.toml +++ b/tool/Cargo.toml @@ -16,7 +16,7 @@ name = "system76_ectool" required-features = ["std", "hidapi", "clap"] [dependencies] -clap = { version = "3.2", optional = true } +clap = { version = "3.2", features = ["derive"], optional = true } libc = { version = "0.2", optional = true } # NOTE: Upgrading to 2.x blocked on Ubuntu shipping newer hidapi hidapi = { version = "1.5", default-features = false, features = ["linux-shared-hidraw"], optional = true } diff --git a/tool/src/main.rs b/tool/src/main.rs index 8bb3f42..cc93627 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -2,7 +2,7 @@ #![allow(clippy::uninlined_format_args)] -use clap::{Arg, App, AppSettings, SubCommand}; +use clap::{AppSettings, Parser}; use ectool::{ Access, AccessHid, @@ -303,115 +303,96 @@ fn parse_color(s: &str) -> Result<(u8, u8, u8), String> { } } + +#[derive(Parser)] +#[clap(rename_all = "snake_case")] +enum SubCommand { + Console, + Fan { + index: u8, + duty: Option, + }, + Flash { + path: String, + }, + FlashBackup { + path: String, + }, + Info, + Keymap { + layer: u8, + output: u8, + input: u8, + value: Option, + }, + LedColor { + index: u8, + #[clap(validator = |x| parse_color(x).and(Ok(())))] + value: Option, + }, + LedValue { + index: u8, + value: Option, + }, + LedMode { + layer: u8, + #[clap(requires = "speed")] + mode: Option, + speed: Option, + }, + LedSave, + Reset, + Matrix, + Print { + #[clap(required = true)] + message: Vec, + }, + SetNoInput { + #[clap(parse(try_from_str))] + value: bool, + }, + Security { + state: Option, + }, +} + +#[derive(clap::ArgEnum, Clone)] +enum AccessMode { + LpcLinux, + LpcSim, + Hid, +} + +#[derive(Parser)] +#[clap(name = "system76_ectool", setting = AppSettings::SubcommandRequired)] +struct Args { + #[clap( + long = "access", + arg_enum, + default_value = "lpc-linux", + )] + access: AccessMode, + #[clap(subcommand)] + subcommand: SubCommand, +} + fn main() { - let matches = App::new("system76_ectool") - .setting(AppSettings::SubcommandRequired) - .arg(Arg::with_name("access") - .long("access") - .possible_values(["lpc-linux", "lpc-sim", "hid"]) - .default_value("lpc-linux") - ) - .subcommand(SubCommand::with_name("console")) - .subcommand(SubCommand::with_name("fan") - .arg(Arg::with_name("index") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("duty") - .value_parser(clap::value_parser!(u8)) - ) - ) - .subcommand(SubCommand::with_name("flash") - .arg(Arg::with_name("path") - .required(true) - ) - ) - .subcommand(SubCommand::with_name("flash_backup") - .arg(Arg::with_name("path") - .required(true) - ) - ) - .subcommand(SubCommand::with_name("info")) - .subcommand(SubCommand::with_name("keymap") - .arg(Arg::with_name("layer") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("output") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("input") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("value")) - ) - .subcommand(SubCommand::with_name("led_color") - .arg(Arg::with_name("index") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("value") - .value_parser(parse_color) - ) - ) - .subcommand(SubCommand::with_name("led_value") - .arg(Arg::with_name("index") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("value") - .value_parser(clap::value_parser!(u8)) - ) - ) - .subcommand(SubCommand::with_name("led_mode") - .arg(Arg::with_name("layer") - .value_parser(clap::value_parser!(u8)) - .required(true) - ) - .arg(Arg::with_name("mode") - .value_parser(clap::value_parser!(u8)) - .requires("speed") - ) - .arg(Arg::with_name("speed") - .value_parser(clap::value_parser!(u8)) - ) - ) - .subcommand(SubCommand::with_name("led_save")) - .subcommand(SubCommand::with_name("reset")) - .subcommand(SubCommand::with_name("matrix")) - .subcommand(SubCommand::with_name("print") - .arg(Arg::with_name("message") - .required(true) - .multiple(true) - ) - ) - .subcommand(SubCommand::with_name("set_no_input") - .arg(Arg::with_name("value") - .possible_values(["true", "false"]) - .required(true) - ) - ) - .subcommand(SubCommand::with_name("security") - .arg(Arg::with_name("state") - .possible_values(["lock", "unlock"]) - ) - ) - .get_matches(); + //.subcommand(Command::new("security").arg(Arg::new("state").value_parser(["lock", "unlock"]))) + + let args = Args::parse(); let get_ec = || -> Result<_, Error> { unsafe { - match matches.value_of("access").unwrap() { - "lpc-linux" => { + match args.access { + AccessMode::LpcLinux => { let access = AccessLpcLinux::new(Duration::new(1, 0))?; Ok(Ec::new(access)?.into_dyn()) }, - "lpc-sim" => { + AccessMode::LpcSim => { let access = AccessLpcSim::new(Duration::new(1, 0))?; Ok(Ec::new(access)?.into_dyn()) }, - "hid" => { + AccessMode::Hid => { let api = HidApi::new()?; for info in api.device_list() { #[allow(clippy::single_match)] @@ -433,7 +414,6 @@ fn main() { } Err(hidapi::HidError::HidApiErrorEmpty.into()) } - _ => unreachable!(), } } }; @@ -445,18 +425,16 @@ fn main() { } }; - match matches.subcommand() { - Some(("console", _sub_m)) => match unsafe { console(&mut ec) } { + match args.subcommand { + SubCommand::Console => match unsafe { console(&mut ec) } { Ok(()) => (), Err(err) => { eprintln!("failed to read console: {:X?}", err); process::exit(1); }, }, - Some(("fan", sub_m)) => { - let index = sub_m.value_of("index").unwrap().parse::().unwrap(); - let duty_opt = sub_m.value_of("duty").map(|x| x.parse::().unwrap()); - match duty_opt { + SubCommand::Fan { index, duty } => { + match duty { Some(duty) => match unsafe { fan_set(&mut ec, index, duty) } { Ok(()) => (), Err(err) => { @@ -473,9 +451,8 @@ fn main() { }, } }, - Some(("flash", sub_m)) => { - let path = sub_m.value_of("path").unwrap(); - match unsafe { flash(&mut ec, path, SpiTarget::Main) } { + SubCommand::Flash { path } => { + match unsafe { flash(&mut ec, &path, SpiTarget::Main) } { Ok(()) => (), Err(err) => { eprintln!("failed to flash '{}': {:X?}", path, err); @@ -483,9 +460,8 @@ fn main() { }, } }, - Some(("flash_backup", sub_m)) => { - let path = sub_m.value_of("path").unwrap(); - match unsafe { flash(&mut ec, path, SpiTarget::Backup) } { + SubCommand::FlashBackup { path } => { + match unsafe { flash(&mut ec, &path, SpiTarget::Backup) } { Ok(()) => (), Err(err) => { eprintln!("failed to flash '{}': {:X?}", path, err); @@ -493,18 +469,15 @@ fn main() { }, } }, - Some(("info", _sub_m)) => match unsafe { info(&mut ec) } { + SubCommand::Info => match unsafe { info(&mut ec) } { Ok(()) => (), Err(err) => { eprintln!("failed to read info: {:X?}", err); process::exit(1); }, }, - Some(("keymap", sub_m)) => { - let layer = sub_m.value_of("layer").unwrap().parse::().unwrap(); - let output = sub_m.value_of("output").unwrap().parse::().unwrap(); - let input = sub_m.value_of("input").unwrap().parse::().unwrap(); - match sub_m.value_of("value") { + SubCommand::Keymap { layer, output, input, value } => { + match value { Some(value_str) => match u16::from_str_radix(value_str.trim_start_matches("0x"), 16) { Ok(value) => match unsafe { keymap_set(&mut ec, layer, output, input, value) } { Ok(()) => (), @@ -527,11 +500,9 @@ fn main() { }, } }, - Some(("led_color", sub_m)) => { - let index = sub_m.value_of("index").unwrap().parse::().unwrap(); - let value = sub_m.value_of("value"); + SubCommand::LedColor { index, value } => { if let Some(value) = value { - let (r, g, b) = parse_color(value).unwrap(); + let (r, g, b) = parse_color(&value).unwrap(); match unsafe { ec.led_set_color(index, r, g, b) } { Ok(()) => (), Err(err) => { @@ -549,9 +520,7 @@ fn main() { } } }, - Some(("led_value", sub_m)) => { - let index = sub_m.value_of("index").unwrap().parse::().unwrap(); - let value = sub_m.value_of("value").map(|x| x.parse::().unwrap()); + SubCommand::LedValue { index, value } => { if let Some(value) = value { match unsafe { ec.led_set_value(index, value) } { Ok(()) => (), @@ -573,10 +542,7 @@ fn main() { } } }, - Some(("led_mode", sub_m)) => { - let layer = sub_m.value_of("layer").unwrap().parse::().unwrap(); - let mode = sub_m.value_of("mode").map(|x| x.parse::().unwrap()); - let speed = sub_m.value_of("speed").map(|x| x.parse::().unwrap()); + SubCommand::LedMode { layer, mode, speed } => { if let (Some(mode), Some(speed)) = (mode, speed) { match unsafe { ec.led_set_mode(layer, mode, speed) } { Ok(()) => (), @@ -598,28 +564,28 @@ fn main() { } } }, - Some(("led_save", _sub_m)) => match unsafe { ec.led_save() } { + SubCommand::LedSave => match unsafe { ec.led_save() } { Ok(()) => (), Err(err) => { eprintln!("failed to save LED settings: {:X?}", err); process::exit(1); }, }, - Some(("reset", _sub_m)) => match unsafe { ec.reset() } { + SubCommand::Reset => match unsafe { ec.reset() } { Ok(()) => (), Err(err) => { eprintln!("failed to reset device: {:X?}", err); process::exit(1); }, }, - Some(("matrix", _sub_m)) => match unsafe { matrix(&mut ec) } { + SubCommand::Matrix => match unsafe { matrix(&mut ec) } { Ok(()) => (), Err(err) => { eprintln!("failed to read matrix: {:X?}", err); process::exit(1); }, }, - Some(("print", sub_m)) => for arg in sub_m.values_of("message").unwrap() { + SubCommand::Print { message } => for arg in message { let mut arg = arg.to_owned(); arg.push('\n'); match unsafe { print(&mut ec, arg.as_bytes()) } { @@ -630,9 +596,8 @@ fn main() { }, } }, - Some(("set_no_input", sub_m)) => { - let no_input = sub_m.value_of("value").unwrap().parse::().unwrap(); - match unsafe { ec.set_no_input(no_input) } { + SubCommand::SetNoInput { value } => { + match unsafe { ec.set_no_input(value) } { Ok(()) => (), Err(err) => { eprintln!("failed to set no_input mode: {:X?}", err); @@ -640,10 +605,10 @@ fn main() { } } }, - Some(("security", sub_m)) => { - match sub_m.value_of("state") { + SubCommand::Security { state } => { + match state { Some(value) => { - let state = match value { + let state = match value.as_str() { "lock" => SecurityState::PrepareLock, "unlock" => SecurityState::PrepareUnlock, _ => { @@ -668,6 +633,5 @@ fn main() { }, } }, - _ => unreachable!() } }