tool: Use clap for argument parsing

This commit is contained in:
Ian Douglas Scott 2021-02-18 15:50:41 -08:00 committed by Jeremy Soller
parent 504284bf72
commit 7c5ba4e62c
3 changed files with 244 additions and 140 deletions

100
tool/Cargo.lock generated
View File

@ -1,10 +1,55 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.66" version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "hidapi" name = "hidapi"
version = "1.2.5" version = "1.2.5"
@ -30,18 +75,73 @@ name = "redox_hwio"
version = "0.1.3" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "system76_ectool" name = "system76_ectool"
version = "0.2.3" version = "0.2.3"
dependencies = [ dependencies = [
"clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
"hidapi 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "hidapi 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [metadata]
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" "checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
"checksum hermit-abi 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
"checksum hidapi 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76c352a18370f7e7e47bcbfcbdc5432b8c80c705b5d751a25232c659fcf5c775" "checksum hidapi 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76c352a18370f7e7e47bcbfcbdc5432b8c80c705b5d751a25232c659fcf5c775"
"checksum libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)" = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" "checksum libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)" = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
"checksum pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" "checksum pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
"checksum redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41aa2c4c67329a04106644cad336238aa5adecfd73d06fb10339d472ce6d8070" "checksum redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41aa2c4c67329a04106644cad336238aa5adecfd73d06fb10339d472ce6d8070"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -16,6 +16,7 @@ name = "system76_ectool"
required-features = ["std"] required-features = ["std"]
[dependencies] [dependencies]
clap = "2"
libc = { version = "0.2", optional = true } libc = { version = "0.2", optional = true }
hidapi = { version = "1.2", default-features = false, features = ["linux-static-hidraw"], optional = true } hidapi = { version = "1.2", default-features = false, features = ["linux-static-hidraw"], optional = true }
redox_hwio = { version = "0.1.3", optional = true } redox_hwio = { version = "0.1.3", optional = true }

View File

@ -1,3 +1,4 @@
use clap::{Arg, App, AppSettings, SubCommand};
use ectool::{ use ectool::{
Access, Access,
AccessLpcLinux, AccessLpcLinux,
@ -10,7 +11,7 @@ use ectool::{
SpiTarget, SpiTarget,
}; };
use std::{ use std::{
env, fmt::Display,
fs, fs,
process, process,
str::{self, FromStr}, str::{self, FromStr},
@ -262,53 +263,71 @@ unsafe fn keymap_set(layer: u8, output: u8, input: u8, value: u16) -> Result<(),
ec.keymap_set(layer, output, input, value) ec.keymap_set(layer, output, input, value)
} }
fn usage() { fn validate_from_str<T: FromStr>(s: String) -> Result<(), String>
eprintln!(" console"); where T::Err: Display {
eprintln!(" flash [file]"); s.parse::<T>()
eprintln!(" flash_backup [file]"); .and(Ok(()))
eprintln!(" fan [index] <duty>"); .map_err(|err| format!("{}", err))
eprintln!(" info");
eprintln!(" keymap [layer] [output] [input] <value>");
eprintln!(" print [message]");
}
fn parse_arg_opt<I: Iterator<Item=String>, F: FromStr>(args: &mut I, name: &str) -> Option<F> {
match args.next() {
Some(arg) => match arg.parse::<F>() {
Ok(ok) => Some(ok),
Err(_err) => {
eprintln!("failed to parse {}: '{}'", name, arg);
process::exit(1);
},
},
None => None,
}
}
fn parse_arg<I: Iterator<Item=String>, F: FromStr>(args: &mut I, name: &str) -> F {
match parse_arg_opt(args, name) {
Some(some) => some,
None => {
eprintln!("no {} provided", name);
process::exit(1);
}
}
} }
fn main() { fn main() {
let mut args = env::args().skip(1); let matches = App::new("system76_ectool")
match args.next() { .setting(AppSettings::SubcommandRequired)
Some(arg) => match arg.as_str() { .subcommand(SubCommand::with_name("console"))
"console" => match unsafe { console() } { .subcommand(SubCommand::with_name("fan")
.arg(Arg::with_name("index")
.validator(validate_from_str::<u8>)
.required(true)
)
.arg(Arg::with_name("duty")
.validator(validate_from_str::<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")
.validator(validate_from_str::<u8>)
.required(true)
)
.arg(Arg::with_name("output")
.validator(validate_from_str::<u8>)
.required(true)
)
.arg(Arg::with_name("input")
.validator(validate_from_str::<u8>)
.required(true)
)
.arg(Arg::with_name("value"))
)
.subcommand(SubCommand::with_name("print")
.arg(Arg::with_name("message")
.required(true)
.multiple(true)
)
)
.get_matches();
match matches.subcommand() {
("console", Some(_sub_m)) => match unsafe { console() } {
Ok(()) => (), Ok(()) => (),
Err(err) => { Err(err) => {
eprintln!("failed to read console: {:X?}", err); eprintln!("failed to read console: {:X?}", err);
process::exit(1); process::exit(1);
}, },
}, },
"fan" => { ("fan", Some(sub_m)) => {
let index = parse_arg(&mut args, "index"); let index = sub_m.value_of("index").unwrap().parse::<u8>().unwrap();
let duty_opt = parse_arg_opt(&mut args, "duty"); let duty_opt = sub_m.value_of("duty").map(|x| x.parse::<u8>().unwrap());
match duty_opt { match duty_opt {
Some(duty) => match unsafe { fan_set(index, duty) } { Some(duty) => match unsafe { fan_set(index, duty) } {
Ok(()) => (), Ok(()) => (),
@ -326,44 +345,38 @@ fn main() {
}, },
} }
}, },
"flash" => match args.next() { ("flash", Some(sub_m)) => {
Some(path) => match unsafe { flash(&path, SpiTarget::Main) } { let path = sub_m.value_of("path").unwrap();
match unsafe { flash(&path, SpiTarget::Main) } {
Ok(()) => (), Ok(()) => (),
Err(err) => { Err(err) => {
eprintln!("failed to flash '{}': {:X?}", path, err); eprintln!("failed to flash '{}': {:X?}", path, err);
process::exit(1); process::exit(1);
}, },
},
None => {
eprintln!("no file provided");
process::exit(1);
} }
}, },
"flash_backup" => match args.next() { ("flash_backup", Some(sub_m)) => {
Some(path) => match unsafe { flash(&path, SpiTarget::Backup) } { let path = sub_m.value_of("path").unwrap();
match unsafe { flash(&path, SpiTarget::Backup) } {
Ok(()) => (), Ok(()) => (),
Err(err) => { Err(err) => {
eprintln!("failed to flash '{}': {:X?}", path, err); eprintln!("failed to flash '{}': {:X?}", path, err);
process::exit(1); process::exit(1);
}, },
},
None => {
eprintln!("no file provided");
process::exit(1);
} }
}, },
"info" => match unsafe { info() } { ("info", Some(_sub_m)) => match unsafe { info() } {
Ok(()) => (), Ok(()) => (),
Err(err) => { Err(err) => {
eprintln!("failed to read info: {:X?}", err); eprintln!("failed to read info: {:X?}", err);
process::exit(1); process::exit(1);
}, },
}, },
"keymap" => { ("keymap", Some(sub_m)) => {
let layer = parse_arg(&mut args, "layer"); let layer = sub_m.value_of("layer").unwrap().parse::<u8>().unwrap();
let output = parse_arg(&mut args, "output"); let output = sub_m.value_of("output").unwrap().parse::<u8>().unwrap();
let input = parse_arg(&mut args, "input"); let input = sub_m.value_of("input").unwrap().parse::<u8>().unwrap();
match args.next() { match sub_m.value_of("value") {
Some(value_str) => match u16::from_str_radix(value_str.trim_start_matches("0x"), 16) { Some(value_str) => match u16::from_str_radix(value_str.trim_start_matches("0x"), 16) {
Ok(value) => match unsafe { keymap_set(layer, output, input, value) } { Ok(value) => match unsafe { keymap_set(layer, output, input, value) } {
Ok(()) => (), Ok(()) => (),
@ -373,7 +386,7 @@ fn main() {
}, },
}, },
Err(err) => { Err(err) => {
eprintln!("failed to parse value: '{}': {}", arg, err); eprintln!("failed to parse value: '{}': {}", value_str, err);
process::exit(1); process::exit(1);
} }
}, },
@ -386,7 +399,8 @@ fn main() {
}, },
} }
}, },
"print" => for mut arg in args { ("print", Some(sub_m)) => for arg in sub_m.values_of("message").unwrap() {
let mut arg = arg.to_owned();
arg.push('\n'); arg.push('\n');
match unsafe { print(&arg.as_bytes()) } { match unsafe { print(&arg.as_bytes()) } {
Ok(()) => (), Ok(()) => (),
@ -396,17 +410,6 @@ fn main() {
}, },
} }
}, },
_ => { _ => unreachable!()
eprintln!("unknown subcommand '{}'", arg);
usage();
process::exit(1);
},
},
None => {
eprintln!("no subcommand provided");
usage();
process::exit(1);
},
} }
} }