diff --git a/.imag-documentation/Cargo.toml b/.imag-documentation/Cargo.toml index 0d45f87b..5057179a 100644 --- a/.imag-documentation/Cargo.toml +++ b/.imag-documentation/Cargo.toml @@ -26,9 +26,6 @@ path = "../libimagentrylist" [dependencies.libimagentrymarkdown] path = "../libimagentrymarkdown" -[dependencies.libimagentryselect] -path = "../libimagentryselect" - [dependencies.libimagentrytag] path = "../libimagentrytag" diff --git a/.travis.yml b/.travis.yml index 8b2752fa..633b0edb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,43 +20,21 @@ before_script: export PATH=$HOME/.local/bin:$PATH script: - | - travis_cargo_run_in() { - echo ":: Trying to run cargo in $1" - [[ -d "$1" ]] && - cd "$1" && - { - { - if [[ $(echo "$1" | grep lib) ]]; then - travis-cargo -q test - else - travis-cargo -q build - fi - } && - cd - - } || exit 1 - } + if [[ "$TEST_SUITE" == "binaries" ]]; then + make $(find . -maxdepth 1 -name "imag-*" -type d -printf "%f ") && \ + for d in $(find -name "Cargo.toml" | grep -vE "^./Cargo.toml$"); do + dir=$(dirname $d) + echo "--- Running test scripts ---" + for testsh in $(find $dir -iname "*test.sh"); do + echo "--- Running test script: '$testsh'" + bash $testsh || { echo "--- Test failed. Exiting"; exit 1; } + echo "--- Test script $testsh executed successfully" + done + done + else # $TEST_SUITE == "libraries" + make $(find . -maxdepth 1 -name "libimag*" -printf "test-%f ") + fi - run_sh_test() { - echo "--- Running test script: '$1'" - bash $1 || { echo "--- Test failed. Exiting"; exit 1; } - echo "--- Test script $1 executed successfully" - } - - echo "<< Changes in ./doc are not build by CI >>" - - for d in $(find -name "Cargo.toml" | grep -vE "^./Cargo.toml$"); do - echo ":: Working on $d" - dir=$(dirname $d) - { \ - echo -e "\n--- Running in $d ---\n" && \ - travis_cargo_run_in $dir && \ - echo "--- Running test scripts ---" && \ - for testsh in $(find $dir -iname "*test.sh"); do - run_sh_test $testsh - done && \ - echo -e "--- Done with test scripts ---\n\n" - } || true - done addons: apt: packages: @@ -65,6 +43,7 @@ addons: - libdw-dev - libelf-dev - libzzip-dev + - make - tree sources: - kalakris-cmake @@ -83,6 +62,9 @@ notifications: template: - "%{repository_name} (%{branch} @ %{commit} by %{author}): %{result}" env: + matrix: + - TEST_SUITE=binaries + - TEST_SUITE=libraries global: - TRAVIS_CARGO_NIGHTLY_FEATURE=dev - secure: D+3exBnbvzFvk7fvLOxkF7UotCc4gBbvvOW4xGr9u6dDjEjV5y6CdDy/OQAkhfKhvSou+lIC22g5MuCBQXFEf/ua7A1XzwBAFeVLK4cWZSa7+ql6LdHKqOg3oF6pQlh095WeWr8S2PYJFFJFg8RGUPnbjqdu1J4KSXqe/7GoZ3lYS69mx7D5Hb93KEN084/KGfBuvyJtMjO1fK3spltL2zV8oqegFpv0gLG5GY4LsJ/7ij4Mc6wepXSyyQbaiA1eKMMwQZDvoi4V1mCulo/jeC3pucGxvgnMV5DZs8aa8R7votltGvSpHCgU78LW19dg8oZqwShQQ+XUYw27H+QK5V1lz1l1MaJLbwS3ySyZBPGH8qUuOzQ3bLp9xhAIRgCui3kX/UDhmeME7nJI6k3UZydh+/ydNB1BZHTKn76XS/yFj0Gcibxg7f5fcAYA6Ge5Sg+YPozuwbcKnKe6IpN2M7qNgWa+6MCSXJ1v4BgPb7kN74EynJUM8+yWEFN7MZtWEUQ4ZsHdCs8Pub4C/zHpYGV8qGenZwQzosAFq56YwoGCvJezz35yg4BDd3IMKenOzNnXLBrdxxqX8ySgwt5B3zBqwve/64Lx6OXjae2m8wZKlsmeqad/s6K7nx0zG15/qqRIzyvgcLXq3jwBaHkteq49FRFWvHQFpBQcsPZ2uH4= diff --git a/Makefile b/Makefile index 60826e52..1199a133 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ imag-bin-update: imag-bin-install: @$(ECHO) "\t[IMAG ][INSTALL]" - @$(CARGO) install --path ./bin/Cargo.toml + @$(CARGO) install --force --path ./bin imag-bin-clean: @$(ECHO) "\t[IMAG ][CLEAN ]" diff --git a/bin/Cargo.toml b/bin/Cargo.toml index d9aa7856..4befe8dc 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -7,4 +7,12 @@ authors = ["Matthias Beyer "] version = "2.0" walkdir = "0.1.5" crossbeam = "0.2.9" +clap = "2.*" +log = "0.3" + +[dependencies.libimagrt] +path = "../libimagrt" + +[dependencies.libimagerror] +path = "../libimagerror" diff --git a/bin/src/main.rs b/bin/src/main.rs index 9dc48b5b..71d56820 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -1,7 +1,12 @@ extern crate crossbeam; +extern crate clap; #[macro_use] extern crate version; +#[macro_use] extern crate log; extern crate walkdir; +extern crate libimagrt; +extern crate libimagerror; + use std::env; use std::process::exit; use std::process::Command; @@ -10,11 +15,15 @@ use std::io::ErrorKind; use walkdir::WalkDir; use crossbeam::*; +use clap::{Arg, AppSettings, SubCommand}; -const DBG_FLAG: &'static str = "--debug"; +use libimagrt::runtime::Runtime; +use libimagerror::trace::trace_error; -fn help(cmds: Vec) { - println!(r#" +/// Returns the helptext, putting the Strings in cmds as possible +/// subcommands into it +fn help_text(cmds: Vec) -> String { + let text = format!(r#" _ (_)_ __ ___ __ _ __ _ @@ -33,13 +42,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. @@ -49,9 +53,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 } +/// Returns the list of imag-* executables found in $PATH fn get_commands() -> Vec { let path = env::var("PATH"); if path.is_err() { @@ -80,7 +91,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() }) @@ -97,78 +108,94 @@ 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(); + // 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.clone()); + let app = Runtime::get_default_cli_builder(appname, version, about) + .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp]) + .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")) + .subcommand(SubCommand::with_name("help").help("Show help")) + .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(); - match &first_arg[..] { - "--help" | "-h" => { - help(commands); - exit(0); - }, + debug!("matches: {:?}", matches); - "--version" => println!("imag {}", &version!()[..]), + // Begin checking for arguments - "--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), - }, + 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() { + result.push(crossbeam::scope(|scope| { + scope.spawn(|| { + let v = Command::new(format!("imag-{}",command)).arg("--version").output(); + match v { + Ok(v) => match String::from_utf8(v.stdout) { + Ok(s) => format!("{:10} -> {}", 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); - } - }, + for versionstring in result.into_iter().map(|handle| handle.join()) { + // The amount of newlines may differ depending on the subprocess + println!("{}", versionstring.trim()); + } + } - 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)); + // Matches any subcommand given + match matches.subcommand() { + (subcommand, Some(scmd)) => { + // 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() + }; + + // Typos happen, so check if the given subcommand is one found in $PATH + if !commands.contains(&String::from(subcommand)) { + println!("No such command: 'imag-{}'", subcommand); + println!("See 'imag --help' for available subcommands"); + exit(2); } - match Command::new(format!("imag-{}", s)) + + 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()) .stderr(Stdio::inherit()) @@ -178,29 +205,37 @@ fn main() { { Ok(exit_status) => { if !exit_status.success() { - println!("{} exited with non-zero exit code", s); - exit(exit_status.code().unwrap_or(42)); + debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status); + println!("{} exited with non-zero exit code", subcommand); + exit(exit_status.code().unwrap_or(1)); } + debug!("Successful exit!"); }, Err(e) => { + debug!("Error calling the subcommand"); match e.kind() { ErrorKind::NotFound => { - println!("No such command: 'imag-{}'", s); + // 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); }, ErrorKind::PermissionDenied => { - println!("No permission to execute: 'imag-{}'", s); + println!("No permission to execute: 'imag-{}'", subcommand); exit(1); }, _ => { println!("Error spawning: {:?}", e); - exit(1337); + exit(1); } } } } - }, + // Calling for example 'imag --versions' will lead here, as this option does not exit. + // There's nothing to do in such a case + _ => {}, } } diff --git a/imag-counter/src/interactive.rs b/imag-counter/src/interactive.rs index 4dbb810d..d37a0c05 100644 --- a/imag-counter/src/interactive.rs +++ b/imag-counter/src/interactive.rs @@ -10,6 +10,7 @@ use libimagcounter::counter::Counter; use libimagcounter::error::CounterError; use libimagrt::runtime::Runtime; use libimagutil::key_value_split::IntoKeyValue; +use libimagutil::warn_exit::warn_exit; use libimagerror::trace::{trace_error, trace_error_exit}; type Result = RResult; @@ -17,8 +18,7 @@ type Result = RResult; pub fn interactive(rt: &Runtime) { let scmd = rt.cli().subcommand_matches("interactive"); if scmd.is_none() { - debug!("No subcommand"); - exit(1); + warn_exit("No subcommand", 1); } let scmd = scmd.unwrap(); debug!("Found 'interactive' command"); @@ -130,8 +130,7 @@ impl<'a> Display for Binding<'a> { fn compute_pair<'a>(rt: &'a Runtime, spec: &str) -> Result<(char, Binding<'a>)> { let kv = String::from(spec).into_kv(); if kv.is_none() { - debug!("Key-Value parsing failed!"); - exit(1); + warn_exit("Key-Value parsing failed!", 1); } let kv = kv.unwrap(); diff --git a/imag-counter/src/list.rs b/imag-counter/src/list.rs index 0c16c019..d18ae9b1 100644 --- a/imag-counter/src/list.rs +++ b/imag-counter/src/list.rs @@ -1,5 +1,5 @@ use libimagrt::runtime::Runtime; -use libimagerror::trace::trace_error; +use libimagerror::trace::{MapErrTrace, trace_error}; use libimagcounter::counter::Counter; pub fn list(rt: &Runtime) { @@ -25,11 +25,11 @@ pub fn list(rt: &Runtime) { println!("{} - {} {}", name.unwrap(), value.unwrap(), unit.unwrap()); } }) - .map_err(|e| trace_error(&e)) + .map_err_trace() .ok(); } }) - .map_err(|e| trace_error(&e)) + .map_err_trace() }); } diff --git a/imag-counter/src/main.rs b/imag-counter/src/main.rs index 304bbb5e..c83bba0a 100644 --- a/imag-counter/src/main.rs +++ b/imag-counter/src/main.rs @@ -27,8 +27,9 @@ use std::str::FromStr; use libimagrt::setup::generate_runtime_setup; use libimagcounter::counter::Counter; -use libimagerror::trace::{trace_error, trace_error_exit}; +use libimagerror::trace::MapErrTrace; use libimagutil::key_value_split::IntoKeyValue; +use libimagutil::info_result::*; mod create; mod delete; @@ -73,30 +74,15 @@ fn main() { match action { Action::Inc => { Counter::load(String::from(name), rt.store()) - .map(|mut counter| { - match counter.inc() { - Err(e) => trace_error_exit(&e, 1), - Ok(_) => info!("Ok"), - } - }) + .map(|mut c| c.inc().map_err_trace_exit(1).map_info_str("Ok")) }, Action::Dec => { Counter::load(String::from(name), rt.store()) - .map(|mut counter| { - match counter.dec() { - Err(e) => trace_error_exit(&e, 1), - Ok(_) => info!("Ok"), - } - }) + .map(|mut c| c.dec().map_err_trace_exit(1).map_info_str("Ok")) }, Action::Reset => { Counter::load(String::from(name), rt.store()) - .map(|mut counter| { - match counter.reset() { - Err(e) => trace_error_exit(&e, 1), - Ok(_) => info!("Ok"), - } - }) + .map(|mut c| c.reset().map_err_trace_exit(1).map_info_str("Ok")) }, Action::Set => { let kv = String::from(name).into_kv(); @@ -112,15 +98,10 @@ fn main() { } let value : i64 = value.unwrap(); Counter::load(String::from(key), rt.store()) - .map(|mut counter| { - match counter.set(value) { - Err(e) => trace_error_exit(&e, 1), - Ok(_) => info!("Ok"), - } - }) + .map(|mut c| c.set(value).map_err_trace_exit(1).map_info_str("Ok")) }, } - .map_err(|e| trace_error(&e)) + .map_err_trace() .ok(); }, |name| { diff --git a/imag-diary/src/create.rs b/imag-diary/src/create.rs index 66818527..c715cfaf 100644 --- a/imag-diary/src/create.rs +++ b/imag-diary/src/create.rs @@ -9,15 +9,13 @@ use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error; use libimagdiary::entry::Entry; use libimagdiary::result::Result; +use libimagutil::warn_exit::warn_exit; use util::get_diary_name; pub fn create(rt: &Runtime) { let diaryname = get_diary_name(rt) - .unwrap_or_else(|| { - warn!("No diary selected. Use either the configuration file or the commandline option"); - exit(1) - }); + .unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); let prevent_edit = rt.cli().subcommand_matches("create").unwrap().is_present("no-edit"); @@ -78,10 +76,7 @@ pub fn create(rt: &Runtime) { exit(1); }, - None => { - warn!("Unexpected error, cannot continue"); - exit(1); - }, + None => warn_exit("Unexpected error, cannot continue", 1) }; diary.new_entry_by_id(id) diff --git a/imag-diary/src/delete.rs b/imag-diary/src/delete.rs index d5fd75e7..aec5a8eb 100644 --- a/imag-diary/src/delete.rs +++ b/imag-diary/src/delete.rs @@ -1,4 +1,3 @@ -use std::process::exit; use chrono::naive::datetime::NaiveDateTime; use libimagdiary::diary::Diary; @@ -7,16 +6,15 @@ use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error_exit; use libimagtimeui::datetime::DateTime; use libimagtimeui::parse::Parse; +use libimagutil::warn_exit::warn_exit; use util::get_diary_name; pub fn delete(rt: &Runtime) { use libimaginteraction::ask::ask_bool; - let diaryname = get_diary_name(rt).unwrap_or_else(|| { - warn!("No diary selected. Use either the configuration file or the commandline option"); - exit(1); - }); + let diaryname = get_diary_name(rt) + .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); let diary = Diary::open(rt.store(), &diaryname[..]); debug!("Diary opened: {:?}", diary); @@ -39,10 +37,7 @@ pub fn delete(rt: &Runtime) { Some(Ok(e)) => e, Some(Err(e)) => trace_error_exit(&e, 1), - None => { - warn!("No entry"); - exit(1); - }, + None => warn_exit("No entry", 1) }; if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) { diff --git a/imag-diary/src/edit.rs b/imag-diary/src/edit.rs index 7b79aa26..6c87d130 100644 --- a/imag-diary/src/edit.rs +++ b/imag-diary/src/edit.rs @@ -1,4 +1,3 @@ -use std::process::exit; use chrono::naive::datetime::NaiveDateTime; use libimagdiary::diary::Diary; @@ -7,19 +6,16 @@ use libimagdiary::error::DiaryErrorKind as DEK; use libimagdiary::error::MapErrInto; use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; -use libimagerror::trace::trace_error; +use libimagerror::trace::MapErrTrace; use libimagerror::into::IntoError; use libimagtimeui::datetime::DateTime; use libimagtimeui::parse::Parse; +use libimagutil::warn_exit::warn_exit; use util::get_diary_name; pub fn edit(rt: &Runtime) { - let diaryname = get_diary_name(rt).unwrap_or_else(|| { - warn!("No diary name"); - exit(1); - }); - + let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); let diary = Diary::open(rt.store(), &diaryname[..]); let datetime : Option = rt @@ -41,7 +37,7 @@ pub fn edit(rt: &Runtime) { Some(Err(e)) => Err(e), None => Err(DEK::EntryNotInDiary.into_error()), } - .map_err(|e| trace_error(&e)).ok(); + .map_err_trace().ok(); } diff --git a/imag-diary/src/list.rs b/imag-diary/src/list.rs index 757cf3a1..bae95ce4 100644 --- a/imag-diary/src/list.rs +++ b/imag-diary/src/list.rs @@ -1,5 +1,3 @@ -use std::process::exit; - use libimagdiary::diary::Diary; use libimagdiary::error::DiaryErrorKind as DEK; use libimagdiary::error::MapErrInto; @@ -7,21 +5,21 @@ use libimagentrylist::listers::core::CoreLister; use libimagentrylist::lister::Lister; use libimagrt::runtime::Runtime; use libimagstore::store::Entry; -use libimagerror::trace::trace_error; +use libimagutil::warn_exit::warn_exit; +use libimagerror::trace::MapErrTrace; +use libimagutil::debug_result::*; use util::get_diary_name; pub fn list(rt: &Runtime) { - let diaryname = get_diary_name(rt).unwrap_or_else(|| { - warn!("No diary selected. Use either the configuration file or the commandline option"); - exit(1); - }); + let diaryname = get_diary_name(rt) + .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); fn entry_to_location_listing_string(e: &Entry) -> String { e.get_location().clone() .without_base() .to_str() - .map_err(|e| trace_error(&e)) + .map_err_trace() .unwrap_or(String::from("<>")) } @@ -31,17 +29,16 @@ pub fn list(rt: &Runtime) { .and_then(|es| { debug!("Iterator for listing: {:?}", es); - let es = es.filter_map(|a| { - debug!("Filtering: {:?}", a); - a.ok() - }).map(|e| e.into()); + let es = es + .filter_map(|a| a.map_dbg(|e| format!("Filtering: {:?}", e)).ok()) + .map(|e| e.into()); CoreLister::new(&entry_to_location_listing_string) .list(es) // TODO: Do not ignore non-ok()s .map_err_into(DEK::IOError) }) - .map(|_| debug!("Ok")) - .map_err(|e| trace_error(&e)) + .map_dbg_str("Ok") + .map_err_trace() .ok(); } diff --git a/imag-diary/src/view.rs b/imag-diary/src/view.rs index c214eafe..742bc262 100644 --- a/imag-diary/src/view.rs +++ b/imag-diary/src/view.rs @@ -1,19 +1,14 @@ -use std::process::exit; - use libimagdiary::diary::Diary; use libimagentryview::viewer::Viewer; use libimagentryview::builtin::plain::PlainViewer; use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error; +use libimagutil::warn_exit::warn_exit; use util::get_diary_name; pub fn view(rt: &Runtime) { - let diaryname = get_diary_name(rt).unwrap_or_else(|| { - warn!("No diary name"); - exit(1); - }); - + let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); let diary = Diary::open(rt.store(), &diaryname[..]); let show_header = rt.cli().subcommand_matches("view").unwrap().is_present("show-header"); diff --git a/imag-link/src/main.rs b/imag-link/src/main.rs index fd8d9d5d..a30758e5 100644 --- a/imag-link/src/main.rs +++ b/imag-link/src/main.rs @@ -26,7 +26,6 @@ extern crate libimagstore; extern crate libimagerror; extern crate libimagutil; -use std::process::exit; use std::ops::Deref; use libimagrt::runtime::Runtime; @@ -35,9 +34,11 @@ use libimagstore::error::StoreError; use libimagstore::store::Entry; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; -use libimagerror::trace::{trace_error, trace_error_exit}; +use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit}; use libimagentrylink::external::ExternalLinker; use libimagutil::warn_result::*; +use libimagutil::warn_exit::warn_exit; +use libimagutil::info_result::*; use clap::ArgMatches; use url::Url; @@ -57,10 +58,7 @@ fn main() { match name { "internal" => handle_internal_linking(&rt), "external" => handle_external_linking(&rt), - _ => { - warn!("No commandline call"); - exit(1); - }, + _ => warn_exit("No commandline call", 1) } }); } @@ -92,7 +90,7 @@ fn handle_internal_linking(rt: &Runtime) { println!("{: <3}: {}", i, link); } }) - .map_err(|e| trace_error(&e)) + .map_err_trace() .ok(); }, @@ -112,8 +110,7 @@ fn handle_internal_linking(rt: &Runtime) { let mut from = { let from = get_from_entry(&rt); if from.is_none() { - warn!("No 'from' entry"); - exit(1); + warn_exit("No 'from' entry", 1); } from.unwrap() }; @@ -122,8 +119,7 @@ fn handle_internal_linking(rt: &Runtime) { let to = { let to = get_to_entries(&rt); if to.is_none() { - warn!("No 'to' entry"); - exit(1); + warn_exit("No 'to' entry", 1); } to.unwrap() }; @@ -241,38 +237,17 @@ fn handle_external_linking(rt: &Runtime) { } fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) { - let link = matches.value_of("add").unwrap(); - - let link = Url::parse(link); - if link.is_err() { - debug!("URL parsing error..."); - trace_error_exit(&link.unwrap_err(), 1); - } - let link = link.unwrap(); - - if let Err(e) = entry.add_external_link(store, link) { - debug!("Error while adding external link..."); - trace_error(&e); - } else { - debug!("Everything worked well"); - info!("Ok"); - } + Url::parse(matches.value_of("add").unwrap()) + .map_err_trace_exit(1) + .map(|link| entry.add_external_link(store, link).map_err_trace().map_info_str("Ok")) + .ok(); } fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) { - let link = matches.value_of("remove").unwrap(); - - let link = Url::parse(link); - if link.is_err() { - trace_error_exit(&link.unwrap_err(), 1); - } - let link = link.unwrap(); - - if let Err(e) = entry.remove_external_link(store, link) { - trace_error(&e); - } else { - info!("Ok"); - } + Url::parse(matches.value_of("remove").unwrap()) + .map_err_trace_exit(1) + .map(|link| entry.remove_external_link(store, link).map_err_trace().map_info_str("Ok")) + .ok(); } fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) { @@ -294,29 +269,22 @@ fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLock .filter_map(|x| x) .collect(); - if let Err(e) = entry.set_external_links(store, links) { - trace_error(&e); - } else { - info!("Ok"); - } + entry.set_external_links(store, links) + .map_err_trace() + .map_info_str("Ok") + .ok(); } fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) { - let res = entry.get_external_links(store) + entry.get_external_links(store) .and_then(|links| { for (i, link) in links.iter().enumerate() { println!("{: <3}: {}", i, link); } Ok(()) - }); - - match res { - Err(e) => { - trace_error(&e); - }, - Ok(_) => { - info!("Ok"); - }, - } + }) + .map_err_trace() + .map_info_str("Ok") + .ok(); } diff --git a/imag-notes/Cargo.toml b/imag-notes/Cargo.toml index 9eff3718..e79b2460 100644 --- a/imag-notes/Cargo.toml +++ b/imag-notes/Cargo.toml @@ -8,6 +8,7 @@ semver = "0.2.1" clap = "2.*" log = "0.3" version = "2.0.1" +itertools = "0.4" [dependencies.libimagrt] path = "../libimagrt" @@ -24,3 +25,6 @@ path = "../libimagentrytag" [dependencies.libimagerror] path = "../libimagerror" +[dependencies.libimagutil] +path = "../libimagutil" + diff --git a/imag-notes/src/main.rs b/imag-notes/src/main.rs index 3e478ca4..475847c0 100644 --- a/imag-notes/src/main.rs +++ b/imag-notes/src/main.rs @@ -2,20 +2,26 @@ extern crate clap; #[macro_use] extern crate log; extern crate semver; #[macro_use] extern crate version; +extern crate itertools; extern crate libimagnotes; extern crate libimagrt; extern crate libimagentryedit; extern crate libimagentrytag; extern crate libimagerror; +extern crate libimagutil; use std::process::exit; +use itertools::Itertools; + use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagnotes::note::Note; -use libimagerror::trace::{trace_error, trace_error_exit}; +use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagutil::info_result::*; +use libimagutil::warn_result::WarnResult; mod ui; use ui::build_ui; @@ -48,9 +54,7 @@ fn name_from_cli(rt: &Runtime, subcmd: &str) -> String { fn create(rt: &Runtime) { let name = name_from_cli(rt, "create"); - Note::new(rt.store(), name.clone(), String::new()) - .map_err(|e| trace_error(&e)) - .ok(); + Note::new(rt.store(), name.clone(), String::new()).map_err_trace().ok(); if rt.cli().subcommand_matches("create").unwrap().is_present("edit") && !edit_entry(rt, name) { @@ -60,8 +64,8 @@ fn create(rt: &Runtime) { fn delete(rt: &Runtime) { Note::delete(rt.store(), String::from(name_from_cli(rt, "delete"))) - .map_err(|e| trace_error(&e)) - .map(|_| println!("Ok")) + .map_err_trace() + .map_info_str("Ok") .ok(); } @@ -83,47 +87,31 @@ fn edit_entry(rt: &Runtime, name: String) -> bool { }, }; - if let Err(e) = note.edit_content(rt) { - trace_error(&e); - warn!("Editing failed"); - return false - } - true + note.edit_content(rt).map_err_trace().map_warn_err_str("Editing failed").is_ok() } fn list(rt: &Runtime) { use std::cmp::Ordering; - let iter = Note::all_notes(rt.store()); - if iter.is_err() { - trace_error_exit(&iter.unwrap_err(), 1); - } + Note::all_notes(rt.store()) + .map_err_trace_exit(1) + .map(|iter| { + let notes = iter.filter_map(|note| note.map_err_trace().ok()) + .sort_by(|note_a, note_b| { + if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) { + return a.cmp(&b) + } else { + return Ordering::Greater; + } + }); - let mut iter = iter.unwrap() - .filter_map(|note| { - match note { - Err(e) => { - trace_error(&e); - None - }, - Ok(e) => Some(e) + for note in notes.iter() { + note.get_name() + .map(|name| println!("{}", name)) + .map_err_trace() + .ok(); } }) - .collect::>(); - - iter.sort_by(|note_a, note_b| { - if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) { - return a.cmp(&b) - } else { - return Ordering::Greater; - } - }); - - for note in iter { - note.get_name() - .map(|name| println!("{}", name)) - .map_err(|e| trace_error(&e)) - .ok(); - } + .ok(); } diff --git a/imag-store/src/delete.rs b/imag-store/src/delete.rs index 537b638d..885a089c 100644 --- a/imag-store/src/delete.rs +++ b/imag-store/src/delete.rs @@ -1,12 +1,12 @@ use std::path::PathBuf; use libimagrt::runtime::Runtime; -use libimagerror::trace::trace_error_exit; +use libimagerror::trace::MapErrTrace; use libimagstore::storeid::StoreId; +use libimagutil::warn_exit::warn_exit; +use libimagutil::warn_result::*; pub fn delete(rt: &Runtime) { - use std::process::exit; - rt.cli() .subcommand_matches("delete") .map(|sub| { @@ -14,24 +14,16 @@ pub fn delete(rt: &Runtime) { .map(|id| { let path = PathBuf::from(id); let path = try!(StoreId::new(Some(rt.store().path().clone()), path) - .map_err(|e| trace_error_exit(&e, 1))); + .map_err_trace_exit(1)); debug!("Deleting file at {:?}", id); rt.store() .delete(path) - .map_err(|e| { - warn!("Error: {:?}", e); - exit(1); - }) - }) - .or_else(|| { - warn!("No ID passed. Will exit now"); - exit(1); + .map_warn_err(|e| format!("Error: {:?}", e)) + .map_err_trace_exit(1) }) + .or_else(|| warn_exit("No ID passed. Will exit now", 1)) }) - .or_else(|| { - warn!("No subcommand 'delete'. Will exit now"); - exit(1); - }); + .or_else(|| warn_exit("No subcommand 'delete'. Will exit now", 1)); } diff --git a/imag-store/src/retrieve.rs b/imag-store/src/retrieve.rs index 39b66741..41f8e936 100644 --- a/imag-store/src/retrieve.rs +++ b/imag-store/src/retrieve.rs @@ -6,7 +6,8 @@ use toml::Value; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; use libimagrt::runtime::Runtime; -use libimagerror::trace::{trace_error, trace_error_exit}; +use libimagerror::trace::MapErrTrace; +use libimagutil::debug_result::*; pub fn retrieve(rt: &Runtime) { rt.cli() @@ -16,18 +17,16 @@ pub fn retrieve(rt: &Runtime) { .map(|id| { let path = PathBuf::from(id); let path = try!(StoreId::new(Some(rt.store().path().clone()), path) - .map_err(|e| trace_error_exit(&e, 1))); + .map_err_trace_exit(1)); debug!("path = {:?}", path); rt.store() // "id" must be present, enforced via clap spec .retrieve(path) .map(|e| print_entry(rt, scmd, e)) - .map_err(|e| { - debug!("No entry."); - debug!("{}:", e); - trace_error(&e); - }) + .map_dbg_str("No entry") + .map_dbg(|e| format!("{:?}", e)) + .map_err_trace() }) }); } diff --git a/imag-store/src/verify.rs b/imag-store/src/verify.rs index ca836e3f..b22d5909 100644 --- a/imag-store/src/verify.rs +++ b/imag-store/src/verify.rs @@ -1,13 +1,11 @@ -use std::process::exit; - use libimagrt::runtime::Runtime; +use libimagutil::warn_exit::warn_exit; pub fn verify(rt: &Runtime) { if rt.store().verify() { info!("Store seems to be fine"); } else { - warn!("Store seems to be broken somehow"); - exit(1); + warn_exit("Store seems to be broken somehow", 1); } } diff --git a/imag-tag/Cargo.toml b/imag-tag/Cargo.toml index 4028ec62..33a36544 100644 --- a/imag-tag/Cargo.toml +++ b/imag-tag/Cargo.toml @@ -22,3 +22,6 @@ path = "../libimagerror" [dependencies.libimagentrytag] path = "../libimagentrytag" +[dependencies.libimagutil] +path = "../libimagutil" + diff --git a/imag-tag/src/main.rs b/imag-tag/src/main.rs index f7c91dd0..92d3b7f3 100644 --- a/imag-tag/src/main.rs +++ b/imag-tag/src/main.rs @@ -8,6 +8,7 @@ extern crate libimagstore; extern crate libimagrt; extern crate libimagentrytag; extern crate libimagerror; +extern crate libimagutil; use std::process::exit; use std::path::PathBuf; @@ -19,6 +20,7 @@ use libimagentrytag::tag::Tag; use libimagerror::trace::{trace_error, trace_error_exit}; use libimagentrytag::ui::{get_add_tags, get_remove_tags}; use libimagstore::storeid::StoreId; +use libimagutil::warn_exit::warn_exit; mod ui; @@ -103,10 +105,7 @@ fn list(id: PathBuf, rt: &Runtime) { let entry = match rt.store().get(path.clone()) { Ok(Some(e)) => e, - Ok(None) => { - info!("No entry found."); - exit(1); - }, + Ok(None) => warn_exit("No entry found.", 1), Err(e) => { warn!("Could not get entry '{:?}'", path); diff --git a/imag-todo/src/main.rs b/imag-todo/src/main.rs index 1163fe3c..a5ca650e 100644 --- a/imag-todo/src/main.rs +++ b/imag-todo/src/main.rs @@ -13,7 +13,6 @@ extern crate libimagstore; extern crate libimagerror; extern crate libimagtodo; -use std::process::exit; use std::process::{Command, Stdio}; use std::io::stdin; @@ -22,7 +21,7 @@ use toml::Value; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagtodo::task::Task; -use libimagerror::trace::trace_error; +use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit}; mod ui; @@ -51,18 +50,13 @@ fn tw_hook(rt: &Runtime) { match Task::import(rt.store(), stdin) { Ok((_, line, uuid)) => println!("{}\nTask {} stored in imag", line, uuid), - Err(e) => { - trace_error(&e); - exit(1); - } + Err(e) => trace_error_exit(&e, 1), } } else if subcmd.is_present("delete") { // The used hook is "on-modify". This hook gives two json-objects // per usage und wants one (the second one) back. let stdin = stdin(); - Task::delete_by_imports(rt.store(), stdin.lock()) - .map_err(|e| trace_error(&e)) - .ok(); + Task::delete_by_imports(rt.store(), stdin.lock()).map_err_trace().ok(); } else { // Should not be possible, as one argument is required via // ArgGroup @@ -120,8 +114,6 @@ fn list(rt: &Runtime) { println!("{}", outstring); }); - if let Err(e) = res { - trace_error(&e); - } + res.map_err_trace().ok(); } diff --git a/libimagentryselect/Cargo.toml b/libimagentryselect/Cargo.toml deleted file mode 100644 index 19424a2c..00000000 --- a/libimagentryselect/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "libimagentryselect" -version = "0.2.0" -authors = ["Matthias Beyer "] - -[dependencies] -clap = "2.*" -log = "0.3" -interactor = "0.1" - -[dependencies.libimagstore] -path = "../libimagstore" - -[dependencies.libimagerror] -path = "../libimagerror" - diff --git a/libimagentryselect/README.md b/libimagentryselect/README.md deleted file mode 100644 index de6c4825..00000000 --- a/libimagentryselect/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# libimagentryselect - -Small library crate for asking the user to _select_ one or more entries out of -a list of entries. - -Not much functionality, yet. - diff --git a/libimagentryselect/src/error.rs b/libimagentryselect/src/error.rs deleted file mode 100644 index 767779e6..00000000 --- a/libimagentryselect/src/error.rs +++ /dev/null @@ -1,13 +0,0 @@ -generate_error_module!( - generate_error_types!(EntrySelectError, EntrySelectErrorKind, - CLIError => "Error on commandline", - IdMissingError => "Commandline: ID missing", - StoreIdParsingError => "Error while parsing StoreId", - IdSelectingError => "Error while selecting id" - ); -); - -pub use self::error::EntrySelectError; -pub use self::error::EntrySelectErrorKind; -pub use self::error::MapErrInto; - diff --git a/libimagentryselect/src/lib.rs b/libimagentryselect/src/lib.rs deleted file mode 100644 index 8f5bcbd3..00000000 --- a/libimagentryselect/src/lib.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![deny( - non_camel_case_types, - non_snake_case, - path_statements, - trivial_numeric_casts, - unstable_features, - unused_allocation, - unused_import_braces, - unused_imports, - unused_mut, - unused_qualifications, - while_true, -)] - -extern crate clap; -extern crate log; -extern crate interactor; - -extern crate libimagstore; -#[macro_use] -extern crate libimagerror; - -pub mod error; -pub mod result; -pub mod ui; - diff --git a/libimagentryselect/src/result.rs b/libimagentryselect/src/result.rs deleted file mode 100644 index db949cf6..00000000 --- a/libimagentryselect/src/result.rs +++ /dev/null @@ -1,6 +0,0 @@ -use std::result::Result as RResult; - -use error::EntrySelectError; - -pub type Result = RResult; - diff --git a/libimaginteraction/Cargo.toml b/libimaginteraction/Cargo.toml index 7a78df33..d13b2823 100644 --- a/libimaginteraction/Cargo.toml +++ b/libimaginteraction/Cargo.toml @@ -4,12 +4,13 @@ version = "0.2.0" authors = ["Matthias Beyer "] [dependencies] -spinner = "0.4" -interactor = "0.1" -log = "0.3" ansi_term = "0.7.2" -regex = "0.1" +clap = "2.*" +interactor = "0.1" lazy_static = "0.1.15" +log = "0.3" +regex = "0.1" +spinner = "0.4" [dependencies.libimagstore] path = "../libimagstore" diff --git a/libimaginteraction/src/error.rs b/libimaginteraction/src/error.rs index 9285f0fd..ff347f1c 100644 --- a/libimaginteraction/src/error.rs +++ b/libimaginteraction/src/error.rs @@ -1,9 +1,14 @@ generate_error_module!( generate_error_types!(InteractionError, InteractionErrorKind, - Unknown => "Unknown Error" + Unknown => "Unknown Error", + CLIError => "Error on commandline", + IdMissingError => "Commandline: ID missing", + StoreIdParsingError => "Error while parsing StoreId", + IdSelectingError => "Error while selecting id" ); ); pub use self::error::InteractionError; pub use self::error::InteractionErrorKind; +pub use self::error::MapErrInto; diff --git a/libimaginteraction/src/lib.rs b/libimaginteraction/src/lib.rs index a608898f..b994ee21 100644 --- a/libimaginteraction/src/lib.rs +++ b/libimaginteraction/src/lib.rs @@ -18,6 +18,7 @@ extern crate interactor; extern crate ansi_term; #[macro_use] extern crate lazy_static; extern crate regex; +extern crate clap; extern crate libimagentryfilter; extern crate libimagstore; @@ -28,4 +29,5 @@ pub mod ask; pub mod error; pub mod filter; pub mod result; +pub mod ui; diff --git a/libimagentryselect/src/ui.rs b/libimaginteraction/src/ui.rs similarity index 81% rename from libimagentryselect/src/ui.rs rename to libimaginteraction/src/ui.rs index e3e41b8a..850a537e 100644 --- a/libimagentryselect/src/ui.rs +++ b/libimaginteraction/src/ui.rs @@ -7,7 +7,7 @@ use libimagerror::into::IntoError; use result::Result; use error::MapErrInto; -use error::EntrySelectErrorKind as ESEK; +use error::InteractionErrorKind as IEK; pub fn id_argument<'a, 'b>() -> Arg<'a, 'b> { Arg::with_name(id_argument_name()) @@ -33,14 +33,14 @@ pub fn id_argument_long() -> &'static str { pub fn get_id(matches: &ArgMatches) -> Result> { matches .values_of(id_argument_name()) - .ok_or(ESEK::IdMissingError.into_error()) - .map_err_into(ESEK::CLIError) + .ok_or(IEK::IdMissingError.into_error()) + .map_err_into(IEK::CLIError) .and_then(|vals| { vals.into_iter() .fold(Ok(vec![]), |acc, elem| { acc.and_then(|mut v| { let elem = StoreId::new_baseless(PathBuf::from(String::from(elem))); - let elem = try!(elem.map_err_into(ESEK::StoreIdParsingError)); + let elem = try!(elem.map_err_into(IEK::StoreIdParsingError)); v.push(elem); Ok(v) }) @@ -51,12 +51,12 @@ pub fn get_id(matches: &ArgMatches) -> Result> { pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result> { use interactor::{pick_file, default_menu_cmd}; - match get_id(matches).map_err_into(ESEK::IdSelectingError) { + match get_id(matches).map_err_into(IEK::IdSelectingError) { Ok(v) => Ok(v), Err(_) => { let path = store_path.clone(); - let p = try!(pick_file(default_menu_cmd, path).map_err_into(ESEK::IdSelectingError)); - let id = try!(StoreId::new_baseless(p).map_err_into(ESEK::StoreIdParsingError)); + let p = try!(pick_file(default_menu_cmd, path).map_err_into(IEK::IdSelectingError)); + let id = try!(StoreId::new_baseless(p).map_err_into(IEK::StoreIdParsingError)); Ok(vec![id]) }, } diff --git a/libimagstore/src/storeid.rs b/libimagstore/src/storeid.rs index eaa1ea05..b2cfc121 100644 --- a/libimagstore/src/storeid.rs +++ b/libimagstore/src/storeid.rs @@ -75,14 +75,6 @@ impl StoreId { self.clone().into_pathbuf().map(|pb| pb.exists()).unwrap_or(false) } - pub fn is_file(&self) -> bool { - true - } - - pub fn is_dir(&self) -> bool { - false - } - pub fn to_str(&self) -> Result { if self.base.is_some() { let mut base = self.base.as_ref().cloned().unwrap(); diff --git a/libimagstorestdhook/src/linkverify.rs b/libimagstorestdhook/src/linkverify.rs index 85551999..cf877526 100644 --- a/libimagstorestdhook/src/linkverify.rs +++ b/libimagstorestdhook/src/linkverify.rs @@ -55,8 +55,6 @@ impl NonMutableHookDataAccessor for LinkedEntriesExistHook { for link in links { if !link.exists() { warn!("File link does not exist: {:?} -> {:?}", fle.get_location(), link); - } else if !link.is_file() { - warn!("File link is not a file: {:?} -> {:?}", fle.get_location(), link); } } })