From 73f9f2d36fae06981f0b91c194da70de3a75adda Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 6 Aug 2016 17:43:28 +0200 Subject: [PATCH 01/24] Add dependency: clap --- bin/Cargo.toml | 1 + bin/src/main.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/bin/Cargo.toml b/bin/Cargo.toml index d9aa7856..4514928c 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -7,4 +7,5 @@ authors = ["Matthias Beyer "] version = "2.0" walkdir = "0.1.5" crossbeam = "0.2.9" +clap = "2.*" diff --git a/bin/src/main.rs b/bin/src/main.rs index 9dc48b5b..dff9ca8d 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -1,4 +1,5 @@ extern crate crossbeam; +extern crate clap; #[macro_use] extern crate version; extern crate walkdir; From 6909410a43fa52a404e81d9173f339171136ad54 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 6 Aug 2016 17:44:28 +0200 Subject: [PATCH 02/24] Add dependency: libimagrt --- bin/Cargo.toml | 3 +++ bin/src/main.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 4514928c..9daddb9e 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -9,3 +9,6 @@ walkdir = "0.1.5" crossbeam = "0.2.9" clap = "2.*" +[dependencies.libimagrt] +path = "../libimagrt" + diff --git a/bin/src/main.rs b/bin/src/main.rs index dff9ca8d..90423c37 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -3,6 +3,8 @@ extern crate clap; #[macro_use] extern crate version; extern crate walkdir; +extern crate libimagrt; + use std::env; use std::process::exit; use std::process::Command; From ecbbc3dfc166f5486cb17c9def17caf964e8fd60 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 6 Aug 2016 17:55:52 +0200 Subject: [PATCH 03/24] Rewrite imag binary --- bin/src/main.rs | 141 ++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 90423c37..fb6dba6a 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -13,8 +13,9 @@ use std::io::ErrorKind; use walkdir::WalkDir; use crossbeam::*; +use clap::{Arg, SubCommand}; -const DBG_FLAG: &'static str = "--debug"; +use libimagrt::runtime::Runtime; fn help(cmds: Vec) { println!(r#" @@ -100,88 +101,86 @@ fn get_commands() -> Vec { execs } -fn find_command() -> Option { - env::args().skip(1).filter(|x| !x.starts_with("-")).next() -} - -fn find_flag() -> Option { - env::args().skip(1).filter(|x| x.starts_with("-")).next() -} - -fn is_debug_flag>(ref s: &T) -> bool { - s.as_ref() == DBG_FLAG -} - -fn find_args(command: &str) -> Vec { - env::args() - .skip(1) - .position(|e| e == command) - .map(|pos| env::args().skip(pos + 2).collect::>()) - .unwrap_or(vec![]) -} - fn main() { - let commands = get_commands(); - let mut args = env::args(); - let _ = args.next(); - let first_arg = match find_command() { - Some(s) => s, - None => match find_flag() { - Some(s) => s, - None => { - help(commands); - exit(0); - }, - }, - }; - let is_debug = env::args().skip(1).find(is_debug_flag).is_some(); + let appname = "imag"; + let version = &version!(); + let about = "imag - the PIM suite for the commandline"; + let mut app = Runtime::get_default_cli_builder(appname, version, about); - match &first_arg[..] { - "--help" | "-h" => { - help(commands); - exit(0); - }, + let commands = get_commands(); - "--version" => println!("imag {}", &version!()[..]), + for command in commands.iter() { + let s = SubCommand::with_name(&command[..]); + app = app.subcommand(s) + } - "--versions" => { - let mut result = vec![]; - for command in commands.iter() { - result.push(crossbeam::scope(|scope| { - scope.spawn(|| { - let v = Command::new(command).arg("--version").output(); - match v { - Ok(v) => match String::from_utf8(v.stdout) { - Ok(s) => format!("{} -> {}", command, s), - Err(e) => format!("Failed calling {} -> {:?}", command, e), - }, + let app = app.arg(Arg::with_name("version") + .long("version") + .takes_value(false) + .required(false) + .multiple(false) + .help("Get the version of imag")) + .arg(Arg::with_name("versions") + .long("versions") + .takes_value(false) + .required(false) + .multiple(false) + .help("Get the versions of the imag commands")); + + let matches = app.get_matches(); + + if matches.is_present("version") { + println!("imag {}", &version!()[..]); + exit(0); + } + + if matches.is_present("versions") { + let mut result = vec![]; + for command in commands.iter() { + result.push(crossbeam::scope(|scope| { + scope.spawn(|| { + let v = Command::new(command).arg("--version").output(); + match v { + Ok(v) => match String::from_utf8(v.stdout) { + Ok(s) => format!("{} -> {}", command, s), Err(e) => format!("Failed calling {} -> {:?}", command, e), - } - }) - })) + }, + Err(e) => format!("Failed calling {} -> {:?}", command, e), + } + }) + })) + } + + for versionstring in result.into_iter().map(|handle| handle.join()) { + println!("{}", versionstring); + } + } + + matches.subcommand_name() + .map(|subcommand| { + + let mut subcommand_args = vec![]; + + for arg in Runtime::arg_names() { + matches.value_of(arg) + .map(|value| { + subcommand_args.push(arg); + subcommand_args.push(value); + }); } - for versionstring in result.into_iter().map(|handle| handle.join()) { - println!("{}", versionstring); - } - }, - - s => { - let mut subcommand_args = find_args(s); - if is_debug && subcommand_args.iter().find(is_debug_flag).is_none() { - subcommand_args.insert(0, String::from(DBG_FLAG)); - } - match Command::new(format!("imag-{}", s)) + match Command::new(format!("imag-{}", subcommand)) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) + .arg(subcommand) .args(&subcommand_args[..]) .spawn() .and_then(|mut handle| handle.wait()) { Ok(exit_status) => { if !exit_status.success() { - println!("{} exited with non-zero exit code", s); + println!("{} exited with non-zero exit code", subcommand); exit(exit_status.code().unwrap_or(42)); } }, @@ -189,11 +188,11 @@ fn main() { Err(e) => { match e.kind() { ErrorKind::NotFound => { - println!("No such command: 'imag-{}'", s); + println!("No such command: 'imag-{}'", subcommand); exit(2); }, ErrorKind::PermissionDenied => { - println!("No permission to execute: 'imag-{}'", s); + println!("No permission to execute: 'imag-{}'", subcommand); exit(1); }, _ => { @@ -203,7 +202,5 @@ fn main() { } } } - - }, - } + }); } From cd70c68a01b171ca6098550c9c034c01e826fd16 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 7 Aug 2016 14:31:34 +0200 Subject: [PATCH 04/24] Add support for --help and -h --- bin/src/main.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index fb6dba6a..03cedd72 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -125,10 +125,23 @@ fn main() { .takes_value(false) .required(false) .multiple(false) - .help("Get the versions of the imag commands")); + .help("Get the versions of the imag commands")) + .arg(Arg::with_name("help") + .long("help") + .short("h") + .takes_value(false) + .required(false) + .multiple(false) + .help("Show help")); + let matches = app.get_matches(); + if matches.is_present("help") { + help(get_commands()); + exit(0); + } + if matches.is_present("version") { println!("imag {}", &version!()[..]); exit(0); From fa379a2fa730c495e30d564a95d6a3223b00c5fc Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 7 Aug 2016 15:11:48 +0200 Subject: [PATCH 05/24] Only return subcommand name --- bin/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 03cedd72..d40a022b 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -84,7 +84,7 @@ fn get_commands() -> Vec { .filter_map(|path| { path.file_name() .to_str() - .and_then(|s| s.splitn(2, "-").nth(1).map(|s| format!("imag {}", s))) + .and_then(|s| s.splitn(2, "-").nth(1).map(String::from)) }) .collect() }) From 58fd2dbfe44f6213b3b9f13dd78063b1cbd0f78e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 7 Aug 2016 15:19:20 +0200 Subject: [PATCH 06/24] Shrink App setup code --- bin/src/main.rs | 60 ++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index d40a022b..7a2f3d0e 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -102,40 +102,34 @@ fn get_commands() -> Vec { } fn main() { - let appname = "imag"; - let version = &version!(); - let about = "imag - the PIM suite for the commandline"; - let mut app = Runtime::get_default_cli_builder(appname, version, about); - + let appname = "imag"; + let version = &version!(); + let about = "imag - the PIM suite for the commandline"; let commands = get_commands(); - - for command in commands.iter() { - let s = SubCommand::with_name(&command[..]); - app = app.subcommand(s) - } - - let app = app.arg(Arg::with_name("version") - .long("version") - .takes_value(false) - .required(false) - .multiple(false) - .help("Get the version of imag")) - .arg(Arg::with_name("versions") - .long("versions") - .takes_value(false) - .required(false) - .multiple(false) - .help("Get the versions of the imag commands")) - .arg(Arg::with_name("help") - .long("help") - .short("h") - .takes_value(false) - .required(false) - .multiple(false) - .help("Show help")); - - - let matches = app.get_matches(); + let r = Runtime::get_default_cli_builder(appname, version, about); + let matches = commands + .iter() + .fold(r, |app, cmd| app.subcommand(SubCommand::with_name(cmd))) + .arg(Arg::with_name("version") + .long("version") + .takes_value(false) + .required(false) + .multiple(false) + .help("Get the version of imag")) + .arg(Arg::with_name("versions") + .long("versions") + .takes_value(false) + .required(false) + .multiple(false) + .help("Get the versions of the imag commands")) + .arg(Arg::with_name("help") + .long("help") + .short("h") + .takes_value(false) + .required(false) + .multiple(false) + .help("Show help")) + .get_matches(); if matches.is_present("help") { help(get_commands()); From 58b2597bcb0596a7e8531908c71c127eab2ce482 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 26 Aug 2016 16:35:15 +0200 Subject: [PATCH 07/24] Enable forwarding of args and subcommands --- bin/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 7a2f3d0e..a17c0801 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -13,7 +13,7 @@ use std::io::ErrorKind; use walkdir::WalkDir; use crossbeam::*; -use clap::{Arg, SubCommand}; +use clap::{Arg, AppSettings, SubCommand}; use libimagrt::runtime::Runtime; @@ -129,6 +129,8 @@ fn main() { .required(false) .multiple(false) .help("Show help")) + .subcommand(SubCommand::with_name("help").help("Show help")) + .settings(&[AppSettings::AllowExternalSubcommands]) .get_matches(); if matches.is_present("help") { From c4c726a9834790257c6a6d51cfc92ead66e1bcea Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 1 Sep 2016 11:24:31 +0200 Subject: [PATCH 08/24] Add dep: log = 0.3 --- bin/Cargo.toml | 1 + bin/src/main.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 9daddb9e..e07df830 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -8,6 +8,7 @@ version = "2.0" walkdir = "0.1.5" crossbeam = "0.2.9" clap = "2.*" +log = "0.3" [dependencies.libimagrt] path = "../libimagrt" diff --git a/bin/src/main.rs b/bin/src/main.rs index a17c0801..9ac30fb5 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -1,6 +1,7 @@ extern crate crossbeam; extern crate clap; #[macro_use] extern crate version; +#[macro_use] extern crate log; extern crate walkdir; extern crate libimagrt; From ac7fb1904053eca82bcc55c44bb0e6d7907dda36 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 1 Sep 2016 11:24:53 +0200 Subject: [PATCH 09/24] Use libimagrt::setup::generate_runtime_setup() helper to build Runtime object --- bin/src/main.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 9ac30fb5..19c8c319 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -14,9 +14,10 @@ use std::io::ErrorKind; use walkdir::WalkDir; use crossbeam::*; -use clap::{Arg, AppSettings, SubCommand}; +use clap::{Arg, App, AppSettings, SubCommand}; use libimagrt::runtime::Runtime; +use libimagrt::setup::generate_runtime_setup; fn help(cmds: Vec) { println!(r#" @@ -102,15 +103,10 @@ fn get_commands() -> Vec { execs } -fn main() { - let appname = "imag"; - let version = &version!(); - let about = "imag - the PIM suite for the commandline"; - let commands = get_commands(); - let r = Runtime::get_default_cli_builder(appname, version, about); - let matches = commands +pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { + get_commands() .iter() - .fold(r, |app, cmd| app.subcommand(SubCommand::with_name(cmd))) + .fold(app, |app, cmd| app.subcommand(SubCommand::with_name(cmd))) .arg(Arg::with_name("version") .long("version") .takes_value(false) @@ -132,21 +128,32 @@ fn main() { .help("Show help")) .subcommand(SubCommand::with_name("help").help("Show help")) .settings(&[AppSettings::AllowExternalSubcommands]) - .get_matches(); +} +fn main() { + let appname = "imag"; + let version = &version!(); + let about = "imag - the PIM suite for the commandline"; + let rt = generate_runtime_setup(appname, version, about, build_ui); + let matches = rt.cli(); + + debug!("matches: {:?}", matches); if matches.is_present("help") { + debug!("Calling help()"); help(get_commands()); exit(0); } if matches.is_present("version") { + debug!("Showing version"); println!("imag {}", &version!()[..]); exit(0); } if matches.is_present("versions") { + debug!("Showing versions"); let mut result = vec![]; - for command in commands.iter() { + for command in get_commands().iter() { result.push(crossbeam::scope(|scope| { scope.spawn(|| { let v = Command::new(command).arg("--version").output(); From 389c5b9033f74b11f6b365d1d7ed78a6db60c14a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 2 Sep 2016 09:39:34 +0200 Subject: [PATCH 10/24] We do not need to pass the subcommand as arg here --- bin/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 19c8c319..75c0934f 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -190,7 +190,6 @@ fn main() { .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) - .arg(subcommand) .args(&subcommand_args[..]) .spawn() .and_then(|mut handle| handle.wait()) From 352d7e90838623b9ed335ed520231418a881446d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 2 Sep 2016 09:48:02 +0200 Subject: [PATCH 11/24] Add some debugging output --- bin/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/src/main.rs b/bin/src/main.rs index 75c0934f..7c2b3320 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -186,6 +186,8 @@ fn main() { }); } + debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args); + match Command::new(format!("imag-{}", subcommand)) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) @@ -196,12 +198,15 @@ fn main() { { Ok(exit_status) => { if !exit_status.success() { + debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status); println!("{} exited with non-zero exit code", subcommand); exit(exit_status.code().unwrap_or(42)); } + debug!("Successful exit!"); }, Err(e) => { + debug!("Error calling the subcommand"); match e.kind() { ErrorKind::NotFound => { println!("No such command: 'imag-{}'", subcommand); From a740dcd7ba40a50dccc86be1653e220514da317f Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Fri, 2 Sep 2016 16:43:31 +0200 Subject: [PATCH 12/24] Change build_ui to use subcommands() --- bin/src/main.rs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 7c2b3320..70fd5097 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -104,9 +104,8 @@ fn get_commands() -> Vec { } pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { - get_commands() - .iter() - .fold(app, |app, cmd| app.subcommand(SubCommand::with_name(cmd))) + app + .settings(&[AppSettings::AllowExternalSubcommands]) .arg(Arg::with_name("version") .long("version") .takes_value(false) @@ -127,7 +126,10 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .multiple(false) .help("Show help")) .subcommand(SubCommand::with_name("help").help("Show help")) - .settings(&[AppSettings::AllowExternalSubcommands]) + .subcommands(get_commands() + .iter() + .map(|cmd| SubCommand::with_name(cmd)) + ) } fn main() { @@ -173,19 +175,9 @@ fn main() { } } - matches.subcommand_name() - .map(|subcommand| { - - let mut subcommand_args = vec![]; - - for arg in Runtime::arg_names() { - matches.value_of(arg) - .map(|value| { - subcommand_args.push(arg); - subcommand_args.push(value); - }); - } - + match matches.subcommand() { + (subcommand, Some(scmd)) => { + let subcommand_args : Vec<&str> = scmd.values_of(subcommand).unwrap().collect(); debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args); match Command::new(format!("imag-{}", subcommand)) @@ -223,5 +215,10 @@ fn main() { } } } - }); + }, + // clap ensures we have valid input by exiting if not. + // The above case is a catch-all for subcommands, + // so nothing else needs to be expexted. + _ => unreachable!(), + } } From 1900d6922c0372aebdc5adce85f4de4cc4637b80 Mon Sep 17 00:00:00 2001 From: mario Date: Sat, 3 Sep 2016 12:39:21 +0200 Subject: [PATCH 13/24] Fix clap for external subcommands --- bin/src/main.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 70fd5097..f8e0ccc8 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -126,10 +126,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .multiple(false) .help("Show help")) .subcommand(SubCommand::with_name("help").help("Show help")) - .subcommands(get_commands() - .iter() - .map(|cmd| SubCommand::with_name(cmd)) - ) } fn main() { @@ -177,7 +173,7 @@ fn main() { match matches.subcommand() { (subcommand, Some(scmd)) => { - let subcommand_args : Vec<&str> = scmd.values_of(subcommand).unwrap().collect(); + let subcommand_args : Vec<&str> = scmd.values_of("").unwrap().collect(); debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args); match Command::new(format!("imag-{}", subcommand)) @@ -202,6 +198,7 @@ fn main() { match e.kind() { ErrorKind::NotFound => { println!("No such command: 'imag-{}'", subcommand); + println!("See 'imag --help' for available subcommands"); exit(2); }, ErrorKind::PermissionDenied => { From 882b2ef5a75307f9988e2cb9646449bf5ea8f311 Mon Sep 17 00:00:00 2001 From: mario Date: Sat, 3 Sep 2016 14:58:14 +0200 Subject: [PATCH 14/24] Add help_text() Replaces the help() functions with help_text(), which returns the help_text of imag. Use the .help() function of clap::App to overwrite the help text generated by clap Remove unneeded argument '--help', generated by clap now --- bin/src/main.rs | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index f8e0ccc8..7076a2ea 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -19,8 +19,8 @@ use clap::{Arg, App, AppSettings, SubCommand}; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; -fn help(cmds: Vec) { - println!(r#" +fn help_text(cmds: Vec) -> String { + let text = format!(r#" _ (_)_ __ ___ __ _ __ _ @@ -39,13 +39,8 @@ fn help(cmds: Vec) { modules can be used independently. Available commands: - "#); - for cmd in cmds.iter() { - println!("\t{}", cmd); - } - - println!(r#" + {imagbins} Call a command with 'imag ' Each command can be called with "--help" to get the respective helptext. @@ -55,9 +50,16 @@ fn help(cmds: Vec) { imag is free software. It is released under the terms of LGPLv2.1 - (c) 2016 Matthias Beyer and contributors"#); + (c) 2016 Matthias Beyer and contributors"#, imagbins = cmds.into_iter() + .map(|cmd| format!("\t{}\n", cmd)) + .fold(String::new(), |s, c| { + let s = s + c.as_str(); + s + })); + text } + fn get_commands() -> Vec { let path = env::var("PATH"); if path.is_err() { @@ -118,14 +120,8 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .required(false) .multiple(false) .help("Get the versions of the imag commands")) - .arg(Arg::with_name("help") - .long("help") - .short("h") - .takes_value(false) - .required(false) - .multiple(false) - .help("Show help")) .subcommand(SubCommand::with_name("help").help("Show help")) + .help(help_text(get_commands())) } fn main() { @@ -136,11 +132,6 @@ fn main() { let matches = rt.cli(); debug!("matches: {:?}", matches); - if matches.is_present("help") { - debug!("Calling help()"); - help(get_commands()); - exit(0); - } if matches.is_present("version") { debug!("Showing version"); From d19243e7a8942646e1b3529c61c246862fe31daa Mon Sep 17 00:00:00 2001 From: mario Date: Sat, 3 Sep 2016 17:58:14 +0200 Subject: [PATCH 15/24] Fall back to get_default_cli_builder insert custom help text cleanup not anymore used code --- bin/Cargo.toml | 3 +++ bin/src/main.rs | 32 +++++++++++++++++++------------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/bin/Cargo.toml b/bin/Cargo.toml index e07df830..4befe8dc 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -13,3 +13,6 @@ log = "0.3" [dependencies.libimagrt] path = "../libimagrt" +[dependencies.libimagerror] +path = "../libimagerror" + diff --git a/bin/src/main.rs b/bin/src/main.rs index 7076a2ea..25d47ce3 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -5,6 +5,7 @@ extern crate clap; extern crate walkdir; extern crate libimagrt; +extern crate libimagerror; use std::env; use std::process::exit; @@ -14,10 +15,10 @@ use std::io::ErrorKind; use walkdir::WalkDir; use crossbeam::*; -use clap::{Arg, App, AppSettings, SubCommand}; +use clap::{Arg, AppSettings, SubCommand}; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagerror::trace::trace_error; fn help_text(cmds: Vec) -> String { let text = format!(r#" @@ -105,8 +106,14 @@ fn get_commands() -> Vec { execs } -pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { - app + +fn main() { + let appname = "imag"; + let version = &version!(); + let about = "imag - the PIM suite for the commandline"; + let commands = get_commands(); + let helptext = help_text(commands); + let app = Runtime::get_default_cli_builder(appname, version, about) .settings(&[AppSettings::AllowExternalSubcommands]) .arg(Arg::with_name("version") .long("version") @@ -121,15 +128,14 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .multiple(false) .help("Get the versions of the imag commands")) .subcommand(SubCommand::with_name("help").help("Show help")) - .help(help_text(get_commands())) -} - -fn main() { - let appname = "imag"; - let version = &version!(); - let about = "imag - the PIM suite for the commandline"; - let rt = generate_runtime_setup(appname, version, about, build_ui); - let matches = rt.cli(); + .help(helptext.as_str()); + let rt = Runtime::new(app) + .unwrap_or_else(|e| { + println!("Runtime couldn't be setup. Exiting"); + trace_error(&e); + exit(1); + }); + let matches = rt.cli(); debug!("matches: {:?}", matches); From 5ea5f588a964e46fefcac1efabb7f241c719f7ac Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 10:12:55 +0200 Subject: [PATCH 16/24] Fix panics due to unwrap on Option::None --- bin/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 25d47ce3..12af035e 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -170,7 +170,11 @@ fn main() { match matches.subcommand() { (subcommand, Some(scmd)) => { - let subcommand_args : Vec<&str> = scmd.values_of("").unwrap().collect(); + debug!("Calling with subcommand: {}", subcommand); + let subcommand_args : Vec<&str> = match scmd.values_of("") { + Some(values) => values.collect(), + None => Vec::new() + }; debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args); match Command::new(format!("imag-{}", subcommand)) From e6d48cb31ab6eee22ae5db3e8ace8f882835303f Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 10:16:36 +0200 Subject: [PATCH 17/24] Fix exit codes --- bin/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 12af035e..885f0163 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -189,7 +189,7 @@ fn main() { if !exit_status.success() { debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status); println!("{} exited with non-zero exit code", subcommand); - exit(exit_status.code().unwrap_or(42)); + exit(exit_status.code().unwrap_or(1)); } debug!("Successful exit!"); }, @@ -208,7 +208,7 @@ fn main() { }, _ => { println!("Error spawning: {:?}", e); - exit(1337); + exit(1); } } } From 7023d1f2027b1402ca837efc626029e2cb1d687f Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 10:31:00 +0200 Subject: [PATCH 18/24] Add check if given subcommand is supported --- bin/src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/src/main.rs b/bin/src/main.rs index 885f0163..de383068 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -175,6 +175,13 @@ fn main() { Some(values) => values.collect(), None => Vec::new() }; + + if !get_commands().contains(&String::from(subcommand)) { + println!("No such command: 'imag-{}'", subcommand); + println!("See 'imag --help' for available subcommands"); + exit(2); + } + debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args); match Command::new(format!("imag-{}", subcommand)) @@ -198,6 +205,8 @@ fn main() { debug!("Error calling the subcommand"); match e.kind() { ErrorKind::NotFound => { + // With the check above, this absolutely should not happen. + // Keeping it to be safe println!("No such command: 'imag-{}'", subcommand); println!("See 'imag --help' for available subcommands"); exit(2); From c828bed0e15cb7b545403c49a1c3b56c53f26488 Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 10:37:16 +0200 Subject: [PATCH 19/24] Fix panic! when reaching unreachable!, because imag doesnt do anything without an argument or subcommand --- bin/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index de383068..b708b861 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -114,7 +114,7 @@ fn main() { let commands = get_commands(); let helptext = help_text(commands); let app = Runtime::get_default_cli_builder(appname, version, about) - .settings(&[AppSettings::AllowExternalSubcommands]) + .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp]) .arg(Arg::with_name("version") .long("version") .takes_value(false) From d69b8498e9e82072da70430143b2141f1f85e015 Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 11:07:02 +0200 Subject: [PATCH 20/24] Add some comments --- bin/src/main.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index b708b861..4f6f84d7 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -20,6 +20,8 @@ use clap::{Arg, AppSettings, SubCommand}; use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error; +/// Returns the helptext, putting the Strings in cmds as possible +/// subcommands into it fn help_text(cmds: Vec) -> String { let text = format!(r#" @@ -60,7 +62,7 @@ fn help_text(cmds: Vec) -> String { text } - +/// Returns the list of imag-* executables found in $PATH fn get_commands() -> Vec { let path = env::var("PATH"); if path.is_err() { @@ -108,11 +110,12 @@ fn get_commands() -> Vec { fn main() { + // Initialize the Runtime and build the CLI let appname = "imag"; let version = &version!(); let about = "imag - the PIM suite for the commandline"; let commands = get_commands(); - let helptext = help_text(commands); + let helptext = help_text(commands.clone()); let app = Runtime::get_default_cli_builder(appname, version, about) .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp]) .arg(Arg::with_name("version") @@ -139,6 +142,8 @@ fn main() { debug!("matches: {:?}", matches); + // Begin checking for arguments + if matches.is_present("version") { debug!("Showing version"); println!("imag {}", &version!()[..]); @@ -168,15 +173,19 @@ fn main() { } } + // Matches any subcommand given match matches.subcommand() { (subcommand, Some(scmd)) => { - debug!("Calling with subcommand: {}", subcommand); + // Get all given arguments and further subcommands to pass to + // the imag-<> binary + // Providing no arguments is OK, and is therefore ignored here let subcommand_args : Vec<&str> = match scmd.values_of("") { Some(values) => values.collect(), None => Vec::new() }; - if !get_commands().contains(&String::from(subcommand)) { + // Typos happen, so check if the given subcommand is one found in $PATH + if !commands.clone().contains(&String::from(subcommand)) { println!("No such command: 'imag-{}'", subcommand); println!("See 'imag --help' for available subcommands"); exit(2); @@ -184,6 +193,7 @@ fn main() { debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args); + // Create a Command, and pass it the gathered arguments match Command::new(format!("imag-{}", subcommand)) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) @@ -223,9 +233,8 @@ fn main() { } } }, - // clap ensures we have valid input by exiting if not. - // The above case is a catch-all for subcommands, - // so nothing else needs to be expexted. - _ => unreachable!(), + // Calling for example 'imag --versions' will lead here, as this option does not exit. + // There's nothing to do in such a case + _ => {}, } } From 12f9175700ce9da71de1c37fa3607b9440bc5828 Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 11:14:08 +0200 Subject: [PATCH 21/24] Fix --versions --- bin/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 4f6f84d7..f8259d52 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -156,7 +156,7 @@ fn main() { for command in get_commands().iter() { result.push(crossbeam::scope(|scope| { scope.spawn(|| { - let v = Command::new(command).arg("--version").output(); + let v = Command::new(format!("imag-{}",command)).arg("--version").output(); match v { Ok(v) => match String::from_utf8(v.stdout) { Ok(s) => format!("{} -> {}", command, s), From e813ab9e3a58c67e7322dd4c74d8b49ac162a569 Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 11:24:36 +0200 Subject: [PATCH 22/24] Pretty output of --versions --- bin/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index f8259d52..70aaf5d0 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -159,7 +159,7 @@ fn main() { let v = Command::new(format!("imag-{}",command)).arg("--version").output(); match v { Ok(v) => match String::from_utf8(v.stdout) { - Ok(s) => format!("{} -> {}", command, s), + Ok(s) => format!("{:10} -> {}", command, s), Err(e) => format!("Failed calling {} -> {:?}", command, e), }, Err(e) => format!("Failed calling {} -> {:?}", command, e), @@ -169,7 +169,7 @@ fn main() { } for versionstring in result.into_iter().map(|handle| handle.join()) { - println!("{}", versionstring); + print!("{}", versionstring); } } From e2d3e5597bbfb64b337de207eb0af67922ab62f4 Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 12:53:38 +0200 Subject: [PATCH 23/24] Fix differing amount of newlines from subprocesses influences output --- bin/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 70aaf5d0..afe37cbb 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -169,7 +169,8 @@ fn main() { } for versionstring in result.into_iter().map(|handle| handle.join()) { - print!("{}", versionstring); + // The amount of newlines may differ depending on the subprocess + println!("{}", versionstring.trim()); } } From 6fe440880070e53bc7c1a68d2941cbc108909691 Mon Sep 17 00:00:00 2001 From: Mario Krehl Date: Wed, 7 Sep 2016 12:57:34 +0200 Subject: [PATCH 24/24] Reduce clone()-ing of commands to necessary places --- bin/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index afe37cbb..71d56820 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -153,7 +153,7 @@ fn main() { if matches.is_present("versions") { debug!("Showing versions"); let mut result = vec![]; - for command in get_commands().iter() { + for command in commands.iter() { result.push(crossbeam::scope(|scope| { scope.spawn(|| { let v = Command::new(format!("imag-{}",command)).arg("--version").output(); @@ -186,7 +186,7 @@ fn main() { }; // Typos happen, so check if the given subcommand is one found in $PATH - if !commands.clone().contains(&String::from(subcommand)) { + if !commands.contains(&String::from(subcommand)) { println!("No such command: 'imag-{}'", subcommand); println!("See 'imag --help' for available subcommands"); exit(2);