diff options
Diffstat (limited to 'bin/domain/imag-contact/src/lib.rs')
-rw-r--r-- | bin/domain/imag-contact/src/lib.rs | 320 |
1 files changed, 150 insertions, 170 deletions
diff --git a/bin/domain/imag-contact/src/lib.rs b/bin/domain/imag-contact/src/lib.rs index 0285f128..873c822a 100644 --- a/bin/domain/imag-contact/src/lib.rs +++ b/bin/domain/imag-contact/src/lib.rs @@ -44,6 +44,7 @@ extern crate walkdir; extern crate uuid; extern crate serde_json; #[macro_use] extern crate failure; +extern crate resiter; extern crate libimagcontact; extern crate libimagstore; @@ -54,7 +55,6 @@ extern crate libimaginteraction; extern crate libimagentryedit; extern crate libimagentryref; -use std::process::exit; use std::path::PathBuf; use std::io::Write; @@ -67,13 +67,13 @@ use walkdir::WalkDir; use failure::Error; use failure::err_msg; use failure::Fallible as Result; +use resiter::AndThen; +use resiter::IterInnerOkOrElse; +use resiter::Map; +use resiter::Filter; use libimagrt::runtime::Runtime; use libimagrt::application::ImagApplication; -use libimagerror::trace::MapErrTrace; -use libimagerror::io::ToExitCode; -use libimagerror::exit::ExitUnwrap; -use libimagerror::iter::TraceIterator; use libimagcontact::store::ContactStore; use libimagcontact::contact::Contact; use libimagcontact::deser::DeserVcard; @@ -94,26 +94,22 @@ use crate::edit::edit; pub enum ImagContact {} impl ImagApplication for ImagContact { fn run(rt: Runtime) -> Result<()> { - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "list" => list(&rt), - "import" => import(&rt), - "show" => show(&rt), - "edit" => edit(&rt), - "find" => find(&rt), - "create" => create(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-contact", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, - } + match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? { + "list" => list(&rt), + "import" => import(&rt), + "show" => show(&rt), + "edit" => edit(&rt), + "find" => find(&rt), + "create" => create(&rt), + other => { + debug!("Unknown command"); + if rt.handle_unknown_subcommand("imag-contact", other, rt.cli())?.success() { + Ok(()) + } else { + Err(err_msg("Failed to handle unknown subcommand")) + } + }, } - - Ok(()) } fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> { @@ -133,128 +129,117 @@ impl ImagApplication for ImagContact { } } -fn list(rt: &Runtime) { +fn list(rt: &Runtime) -> Result<()> { let scmd = rt.cli().subcommand_matches("list").unwrap(); - let list_format = get_contact_print_format("contact.list_format", rt, &scmd); + let list_format = get_contact_print_format("contact.list_format", rt, &scmd)?; debug!("List format: {:?}", list_format); let iterator = rt .store() - .all_contacts() - .map_err_trace_exit_unwrap() + .all_contacts()? .into_get_iter() - .trace_unwrap_exit() - .map(|fle| fle.ok_or_else(|| err_msg("StoreId not found".to_owned()))) - .trace_unwrap_exit() - .map(|fle| { - rt.report_touched(fle.get_location()).unwrap_or_exit(); - fle + .map_inner_ok_or_else(|| err_msg("Did not find one entry")) + .and_then_ok(|fle| { + rt.report_touched(fle.get_location())?; + Ok(fle) }) - .map(|e| e.deser()) - .trace_unwrap_exit() - .enumerate(); + .and_then_ok(|e| e.deser()); if scmd.is_present("json") { debug!("Listing as JSON"); - let v : Vec<DeserVcard> = iterator.map(|tpl| tpl.1).collect(); - - match ::serde_json::to_string(&v) { - Ok(s) => writeln!(rt.stdout(), "{}", s).to_exit_code().unwrap_or_exit(), - Err(e) => { - error!("Error generating JSON: {:?}", e); - ::std::process::exit(1) - } - } + let v = iterator.collect::<Result<Vec<DeserVcard>>>()?; + let s = ::serde_json::to_string(&v)?; + writeln!(rt.stdout(), "{}", s).map_err(Error::from) } else { debug!("Not listing as JSON"); let output = rt.stdout(); let mut output = output.lock(); + let mut i = 0; iterator - .map(|(i, dvcard)| build_data_object_for_handlebars(i, &dvcard)) - .map(|data| list_format.render("format", &data).map_err(Error::from)) - .trace_unwrap_exit() - .for_each(|s| { - writeln!(output, "{}", s).to_exit_code().unwrap_or_exit() - }); + .map_ok(|dvcard| { + i += 1; + build_data_object_for_handlebars(i, &dvcard) + }) + .and_then_ok(|data| list_format.render("format", &data).map_err(Error::from)) + .and_then_ok(|s| writeln!(output, "{}", s).map_err(Error::from)) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } } -fn import(rt: &Runtime) { +fn import(rt: &Runtime) -> Result<()> { let scmd = rt.cli().subcommand_matches("import").unwrap(); // secured by main let force_override = scmd.is_present("force-override"); let path = scmd.value_of("path").map(PathBuf::from).unwrap(); // secured by clap let collection_name = rt.cli().value_of("contact-ref-collection-name").unwrap(); // default by clap let ref_config = rt.config() - .ok_or_else(|| format_err!("No configuration, cannot continue!")) - .map_err_trace_exit_unwrap() - .read_partial::<libimagentryref::reference::Config>() - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .ok_or_else(|| format_err!("Configuration missing: {}", libimagentryref::reference::Config::LOCATION)) - .map_err_trace_exit_unwrap(); - // TODO: Refactor the above to libimagutil or libimagrt? + .ok_or_else(|| format_err!("No configuration, cannot continue!"))? + .read_partial::<libimagentryref::reference::Config>()? + .ok_or_else(|| format_err!("Configuration missing: {}", libimagentryref::reference::Config::LOCATION))?; + // TODO: Refactor the above to libimagutil or libimagrt? if !path.exists() { - error!("Path does not exist"); - exit(1) + return Err(format_err!("Path does not exist: {}", path.display())) } if path.is_file() { let entry = rt .store() - .retrieve_from_path(&path, &ref_config, &collection_name, force_override) - .map_err_trace_exit_unwrap(); + .retrieve_from_path(&path, &ref_config, &collection_name, force_override)?; - rt.report_touched(entry.get_location()).unwrap_or_exit(); + rt.report_touched(entry.get_location()).map_err(Error::from) } else if path.is_dir() { - for entry in WalkDir::new(path).min_depth(1).into_iter() { - let entry = entry - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - - if entry.file_type().is_file() { - let pb = PathBuf::from(entry.path()); - let fle = rt - .store() - .retrieve_from_path(&pb, &ref_config, &collection_name, force_override) - .map_err_trace_exit_unwrap(); - - rt.report_touched(fle.get_location()).unwrap_or_exit(); - info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>")); - } else { - warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>")); - } - } + WalkDir::new(path) + .min_depth(1) + .into_iter() + .map(|r| r.map_err(Error::from)) + .and_then_ok(|entry| { + if entry.file_type().is_file() { + let pb = PathBuf::from(entry.path()); + let fle = rt + .store() + .retrieve_from_path(&pb, &ref_config, &collection_name, force_override)?; + + rt.report_touched(fle.get_location())?; + info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>")); + Ok(()) + } else { + warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>")); + Ok(()) + } + }) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } else { - error!("Path is neither directory nor file"); - exit(1) + Err(err_msg("Path is neither directory nor file")) } } -fn show(rt: &Runtime) { +fn show(rt: &Runtime) -> Result<()> { let scmd = rt.cli().subcommand_matches("show").unwrap(); let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap - let show_format = get_contact_print_format("contact.show_format", rt, &scmd); + let show_format = get_contact_print_format("contact.show_format", rt, &scmd)?; let out = rt.stdout(); let mut outlock = out.lock(); - util::find_contact_by_hash(rt, hash) + util::find_contact_by_hash(rt, hash)? + .filter_ok(|tpl| tpl.0) + .map_ok(|tpl| tpl.1) .enumerate() - .for_each(|(i, elem)| { - let elem = elem.deser().map_err_trace_exit_unwrap(); + .map(|(i, elem)| { + let elem = elem?.deser()?; let data = build_data_object_for_handlebars(i, &elem); - let s = show_format - .render("format", &data) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit(); - }); + let s = show_format.render("format", &data)?; + writeln!(outlock, "{}", s).map_err(Error::from) + }) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } -fn find(rt: &Runtime) { +fn find(rt: &Runtime) -> Result<()> { let scmd = rt.cli().subcommand_matches("find").unwrap(); let grepstring = scmd .values_of("string") @@ -263,24 +248,16 @@ fn find(rt: &Runtime) { .collect::<Vec<String>>(); // We don't know yet which we need, but we pay that price for simplicity of the codebase - let show_format = get_contact_print_format("contact.show_format", rt, &scmd); - let list_format = get_contact_print_format("contact.list_format", rt, &scmd); + let show_format = get_contact_print_format("contact.show_format", rt, &scmd)?; + let list_format = get_contact_print_format("contact.list_format", rt, &scmd)?; let iterator = rt .store() - .all_contacts() - .map_err_trace_exit_unwrap() + .all_contacts()? .into_get_iter() - .map(|el| { - el.map_err_trace_exit_unwrap() - .ok_or_else(|| { - error!("Could not get StoreId from Store::all_contacts(). This is a BUG!"); - ::std::process::exit(1) - }) - .unwrap() // safed above - }) - .filter_map(|entry| { - let card = entry.deser().map_err_trace_exit_unwrap(); + .map_inner_ok_or_else(|| err_msg("Did not find one entry")) + .and_then_ok(|entry| { + let card = entry.deser()?; let str_contains_any = |s: &String, v: &Vec<String>| { v.iter().any(|i| s.contains(i)) @@ -291,91 +268,94 @@ fn find(rt: &Runtime) { || card.fullname().iter().any(|a| str_contains_any(a, &grepstring)); if take { - rt.report_touched(entry.get_location()).unwrap_or_exit(); + rt.report_touched(entry.get_location())?; // optimization so we don't have to parse again in the next step - Some((entry, card)) + Ok((true, entry, card)) } else { - None + Ok((false, entry, card)) } - }) - .enumerate(); + }); + + let mut i = 0; if !rt.output_is_pipe() || rt.ignore_ids() { if scmd.is_present("json") { - let v : Vec<DeserVcard> = iterator.map(|(_, tlp)| tlp.1).collect(); - - match ::serde_json::to_string(&v) { - Ok(s) => writeln!(rt.stdout(), "{}", s).to_exit_code().unwrap_or_exit(), - Err(e) => { - error!("Error generating JSON: {:?}", e); - ::std::process::exit(1) - } - } + iterator + .filter_ok(|tpl| tpl.0) + .map_ok(|tpl| tpl.2) + .and_then_ok(|v| { + let s = ::serde_json::to_string(&v)?; + writeln!(rt.stdout(), "{}", s).map_err(Error::from) + }) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } else if scmd.is_present("find-id") { iterator - .for_each(|(_i, (entry, _))| { - writeln!(rt.stdout(), "{}", entry.get_location()) - .to_exit_code() - .unwrap_or_exit(); + .and_then_ok(|(take, entry, _)| { + if take { + writeln!(rt.stdout(), "{}", entry.get_location()).map_err(Error::from) + } else { + Ok(()) + } }) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } else if scmd.is_present("find-full-id") { let storepath = rt.store().path().display(); iterator - .for_each(|(_i, (entry, _))| { - writeln!(rt.stdout(), "{}/{}", storepath, entry.get_location()) - .to_exit_code() - .unwrap_or_exit(); + .and_then_ok(|(take, entry, _)| { + if take { + writeln!(rt.stdout(), "{}/{}", storepath, entry.get_location()).map_err(Error::from) + } else { + Ok(()) + } }) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } else { iterator - .for_each(|(i, (_, card))| { - let fmt = if scmd.is_present("find-show") { - &show_format - } else { // default: find-list - &list_format - }; - - let data = build_data_object_for_handlebars(i, &card); - let s = fmt - .render("format", &data) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - - writeln!(rt.stdout(), "{}", s) - .to_exit_code() - .unwrap_or_exit(); - }); + .and_then_ok(|(take, _, card)| { + if take { + i += 1; + let fmt = if scmd.is_present("find-show") { + &show_format + } else { // default: find-list + &list_format + }; + + let data = build_data_object_for_handlebars(i, &card); + let s = fmt.render("format", &data)?; + + writeln!(rt.stdout(), "{}", s).map_err(Error::from) + } else { + Ok(()) + } + }) + .collect::<Result<Vec<_>>>() + .map(|_| ()) } } else { // if not printing, we still have to consume the iterator to report the touched IDs let _ = iterator.collect::<Vec<_>>(); + Ok(()) } } -fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Handlebars { - let fmt = scmd - .value_of("format") - .map(String::from) - .unwrap_or_else(|| { - rt.config() - .ok_or_else(|| err_msg("No configuration file")) - .map_err_trace_exit_unwrap() - .read_string(config_value_path) - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .ok_or_else(|| err_msg("Configuration 'contact.list_format' does not exist")) - .map_err_trace_exit_unwrap() - }); +fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Result<Handlebars> { + let fmt = match scmd.value_of("format").map(String::from) { + Some(s) => Ok(s), + None => rt.config() + .ok_or_else(|| err_msg("No configuration file"))? + .read_string(config_value_path)? + .ok_or_else(|| err_msg("Configuration 'contact.list_format' does not exist")), + }?; let mut hb = Handlebars::new(); - hb - .register_template_string("format", fmt) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); + hb.register_template_string("format", fmt)?; hb.register_escape_fn(::handlebars::no_escape); ::libimaginteraction::format::register_all_color_helpers(&mut hb); ::libimaginteraction::format::register_all_format_helpers(&mut hb); - hb + Ok(hb) } |