From 421969c3da14d5664a9cbd8ae3e9d3cd9138d952 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 10 Jul 2021 20:19:29 +0200 Subject: [PATCH] argh instead of getopts --- CHANGELOG.md | 2 + Cargo.lock | 53 ++++++++++++++++----- Cargo.toml | 2 +- src/main.rs | 129 ++++++++++++++++++++++++--------------------------- 4 files changed, 104 insertions(+), 82 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8d29ed..b43ba55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,9 @@ Released on FIXME: ?? - Fixed broken input cursor when typing UTF8 characters (tui-realm 0.3.2) - Fixed save bookmark dialog: you could switch out from dialog with `` - Dependencies: + - Added `argh 0.1.5` - Added `open 1.7.0` + - Removed `getopts` - Updated `rand` to `0.8.4` - Updated `textwrap` to `0.14.2` - Updated `tui-realm` to `0.4.3` diff --git a/Cargo.lock b/Cargo.lock index ff3a8d5..3dab2b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,6 +51,35 @@ dependencies = [ "winapi", ] +[[package]] +name = "argh" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7317a549bc17c5278d9e72bb6e62c6aa801ac2567048e39ebc1c194249323e" +dependencies = [ + "argh_derive", + "argh_shared", +] + +[[package]] +name = "argh_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60949c42375351e9442e354434b0cba2ac402c1237edf673cac3a4bf983b8d3c" +dependencies = [ + "argh_shared", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "argh_shared" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a61eb019cb8f415d162cb9f12130ee6bbe9168b7d953c17f4ad049e4051ca00" + [[package]] name = "autocfg" version = "1.0.1" @@ -402,15 +431,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - [[package]] name = "getrandom" version = "0.1.16" @@ -433,6 +453,15 @@ dependencies = [ "wasi 0.10.0+wasi-snapshot-preview1", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hkdf" version = "0.10.0" @@ -519,9 +548,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.97" +version = "0.2.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] name = "libssh2-sys" @@ -1327,6 +1356,7 @@ dependencies = [ name = "termscp" version = "0.6.0" dependencies = [ + "argh", "bitflags", "bytesize", "chrono", @@ -1335,7 +1365,6 @@ dependencies = [ "dirs", "edit", "ftp4", - "getopts", "hostname", "keyring", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 619f494..de7ea32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ name = "termscp" path = "src/main.rs" [dependencies] +argh = "0.1.5" bitflags = "1.2.1" bytesize = "1.0.1" chrono = "0.4.19" @@ -35,7 +36,6 @@ crossterm = "0.19.0" dirs = "3.0.1" edit = "0.1.3" ftp4 = { version = "4.0.2", features = [ "secure" ] } -getopts = "0.2.21" hostname = "0.3.1" keyring = { version = "0.10.1", optional = true } lazy_static = "1.4.0" diff --git a/src/main.rs b/src/main.rs index 76b35dd..cb5a095 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ const TERMSCP_VERSION: &str = env!("CARGO_PKG_VERSION"); const TERMSCP_AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); // Crates -extern crate getopts; +extern crate argh; #[macro_use] extern crate bitflags; #[macro_use] @@ -38,7 +38,7 @@ extern crate magic_crypt; extern crate rpassword; // External libs -use getopts::{Matches, Options}; +use argh::FromArgs; use std::env; use std::path::PathBuf; use std::time::Duration; @@ -64,6 +64,38 @@ enum Task { ImportTheme(PathBuf), } +#[derive(FromArgs)] +#[argh(description = " +where positional can be: [protocol://user@address:port:wrkdir] [local-wrkdir] + +Please, report issues to +Please, consider supporting the author ")] +struct Args { + #[argh(switch, short = 'c', description = "open termscp configuration")] + config: bool, + #[argh(option, short = 'P', description = "provide password from CLI")] + password: Option, + #[argh(switch, short = 'q', description = "disable logging")] + quiet: bool, + #[argh(option, short = 't', description = "import specified theme")] + theme: Option, + #[argh( + option, + short = 'T', + default = "10", + description = "set UI ticks; default 10ms" + )] + ticks: u64, + #[argh(switch, short = 'v', description = "print version")] + version: bool, + // -- positional + #[argh( + positional, + description = "protocol://user@address:port:wrkdir local-wrkdir" + )] + positional: Vec, +} + struct RunOpts { address: Option, port: u16, @@ -93,34 +125,15 @@ impl Default for RunOpts { } fn main() { - let args: Vec = env::args().collect(); - //Program CLI options - let mut run_opts: RunOpts = RunOpts::default(); - //Process options - let mut opts = Options::new(); - opts.optflag("c", "config", "Open termscp configuration"); - opts.optflag("q", "quiet", "Disable logging"); - opts.optopt("t", "theme", "Import specified theme", ""); - opts.optopt("P", "password", "Provide password from CLI", ""); - opts.optopt("T", "ticks", "Set UI ticks; default 10ms", ""); - opts.optflag("v", "version", ""); - opts.optflag("h", "help", "Print this menu"); - let matches: Matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - println!("{}", f.to_string()); + let args: Args = argh::from_env(); + // Parse args + let mut run_opts: RunOpts = match parse_args(args) { + Ok(opts) => opts, + Err(err) => { + eprintln!("{}", err); std::process::exit(255); } }; - // Parse args - if let Err(err) = parse_run_opts(&mut run_opts, matches) { - if let Some(err) = err { - eprintln!("{}", err); - } else { - print_usage(opts); - } - std::process::exit(255); - } // Setup logging if run_opts.log_enabled { if let Err(err) = logging::init() { @@ -141,65 +154,43 @@ fn main() { std::process::exit(rc); } -/// ### print_usage +/// ### parse_args /// -/// Print usage -fn print_usage(opts: Options) { - let brief = String::from( - "Usage: termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]", - ); - print!("{}", opts.usage(&brief)); - println!("\nPlease, report issues to "); - println!("Please, consider supporting the author ") -} - -/// ### parse_run_opts -/// -/// Parse run options; in case something is wrong returns the error message -fn parse_run_opts(run_opts: &mut RunOpts, opts: Matches) -> Result<(), Option> { - // Help - if opts.opt_present("h") { - return Err(None); - } +/// Parse arguments +/// In case of success returns `RunOpts` +/// in case something is wrong returns the error message +fn parse_args(args: Args) -> Result { + let mut run_opts: RunOpts = RunOpts::default(); // Version - if opts.opt_present("v") { - return Err(Some(format!( + if args.version { + return Err(format!( "termscp - {} - Developed by {}", TERMSCP_VERSION, TERMSCP_AUTHORS, - ))); + )); } // Setup activity? - if opts.opt_present("c") { + if args.config { run_opts.task = Task::Activity(NextActivity::SetupActivity); } // Logging - if opts.opt_present("q") { + if args.quiet { run_opts.log_enabled = false; } // Match password - if let Some(passwd) = opts.opt_str("P") { + if let Some(passwd) = args.password { run_opts.password = Some(passwd); } // Match ticks - if let Some(val) = opts.opt_str("T") { - match val.parse::() { - Ok(val) => run_opts.ticks = Duration::from_millis(val as u64), - Err(_) => { - return Err(Some(format!("Ticks is not a number: '{}'", val))); - } - } - } + run_opts.ticks = Duration::from_millis(args.ticks); // @! extra modes - if let Some(theme) = opts.opt_str("t") { + if let Some(theme) = args.theme { run_opts.task = Task::ImportTheme(PathBuf::from(theme)); } // @! Ordinary mode - // Check free args - let extra_args: Vec = opts.free; // Remote argument - if let Some(remote) = extra_args.get(0) { + if let Some(remote) = args.positional.get(0) { // Parse address - match utils::parser::parse_remote_opt(remote) { + match utils::parser::parse_remote_opt(remote.as_str()) { Ok(host_opts) => { // Set params run_opts.address = Some(host_opts.hostname); @@ -211,19 +202,19 @@ fn parse_run_opts(run_opts: &mut RunOpts, opts: Matches) -> Result<(), Option { - return Err(Some(format!("Bad address option: {}", err))); + return Err(format!("Bad address option: {}", err)); } } } // Local directory - if let Some(localdir) = extra_args.get(1) { + if let Some(localdir) = args.positional.get(1) { // Change working directory if local dir is set let localdir: PathBuf = PathBuf::from(localdir); if let Err(err) = env::set_current_dir(localdir.as_path()) { - return Err(Some(format!("Bad working directory argument: {}", err))); + return Err(format!("Bad working directory argument: {}", err)); } } - Ok(()) + Ok(run_opts) } /// ### read_password