argh instead of getopts

This commit is contained in:
veeso 2021-07-10 20:19:29 +02:00
parent e15b79750b
commit 421969c3da
4 changed files with 104 additions and 82 deletions

View file

@ -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 `<TAB>`
- 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`

53
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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 <https://github.com/veeso/termscp>
Please, consider supporting the author <https://www.buymeacoffee.com/veeso>")]
struct Args {
#[argh(switch, short = 'c', description = "open termscp configuration")]
config: bool,
#[argh(option, short = 'P', description = "provide password from CLI")]
password: Option<String>,
#[argh(switch, short = 'q', description = "disable logging")]
quiet: bool,
#[argh(option, short = 't', description = "import specified theme")]
theme: Option<String>,
#[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<String>,
}
struct RunOpts {
address: Option<String>,
port: u16,
@ -93,34 +125,15 @@ impl Default for RunOpts {
}
fn main() {
let args: Vec<String> = 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", "<path>");
opts.optopt("P", "password", "Provide password from CLI", "<password>");
opts.optopt("T", "ticks", "Set UI ticks; default 10ms", "<ms>");
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 <https://github.com/veeso/termscp>");
println!("Please, consider supporting the author <https://www.buymeacoffee.com/veeso>")
}
/// ### 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<String>> {
// 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<RunOpts, String> {
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::<usize>() {
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<String> = 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<St
run_opts.task = Task::Activity(NextActivity::FileTransfer);
}
Err(err) => {
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