diff options
-rw-r--r-- | bin/domain/imag-diary/Cargo.toml | 1 | ||||
-rw-r--r-- | bin/domain/imag-diary/src/create.rs | 117 | ||||
-rw-r--r-- | bin/domain/imag-diary/src/delete.rs | 38 | ||||
-rw-r--r-- | bin/domain/imag-diary/src/lib.rs | 50 | ||||
-rw-r--r-- | bin/domain/imag-diary/src/list.rs | 37 | ||||
-rw-r--r-- | bin/domain/imag-diary/src/util.rs | 4 | ||||
-rw-r--r-- | bin/domain/imag-diary/src/view.rs | 51 | ||||
-rw-r--r-- | bin/domain/imag-log/Cargo.toml | 1 | ||||
-rw-r--r-- | bin/domain/imag-log/src/lib.rs | 169 |
9 files changed, 200 insertions, 268 deletions
diff --git a/bin/domain/imag-diary/Cargo.toml b/bin/domain/imag-diary/Cargo.toml index e46a36f3..26432644 100644 --- a/bin/domain/imag-diary/Cargo.toml +++ b/bin/domain/imag-diary/Cargo.toml @@ -26,6 +26,7 @@ toml = "0.5.1" toml-query = "0.9.2" itertools = "0.8.0" failure = "0.1.5" +resiter = "0.4.0" libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } diff --git a/bin/domain/imag-diary/src/create.rs b/bin/domain/imag-diary/src/create.rs index 8a3f80a3..c6c4687f 100644 --- a/bin/domain/imag-diary/src/create.rs +++ b/bin/domain/imag-diary/src/create.rs @@ -24,14 +24,11 @@ use chrono::Timelike; use failure::Error; use failure::ResultExt; use failure::err_msg; +use failure::Fallible as Result; use libimagdiary::diary::Diary; use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; -use libimagerror::trace::MapErrTrace; -use libimagerror::exit::ExitUnwrap; -use libimagutil::warn_exit::warn_exit; -use libimagutil::debug_result::DebugResult; use libimagutil::debug_option::DebugOption; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; @@ -40,60 +37,46 @@ use crate::util::get_diary_name; use crate::util::get_diary_timed_config; use crate::util::Timed; -pub fn create(rt: &Runtime) { +pub fn create(rt: &Runtime) -> Result<()> { let diaryname = get_diary_name(rt) - .unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); + .ok_or_else(|| err_msg("No diary selected. Use either the configuration file or the commandline option"))?; - let mut entry = create_entry(rt.store(), &diaryname, rt); + let mut entry = create_entry(rt.store(), &diaryname, rt)?; + rt.report_touched(entry.get_location())?; - rt.report_touched(entry.get_location()).unwrap_or_exit(); - - let res = if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") { + if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") { debug!("Not editing new diary entry"); + info!("Ok!"); Ok(()) } else { debug!("Editing new diary entry"); entry.edit_content(rt).context(err_msg("Diary edit error")).map_err(Error::from) - }; - - res.map_err_trace_exit_unwrap(); - info!("Ok!"); + } } -fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> { +fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> Result<FileLockEntry<'a>> { use crate::util::parse_timed_string; let create = rt.cli().subcommand_matches("create").unwrap(); - create.value_of("timed") - .map(|t| parse_timed_string(t, diaryname).map_err_trace_exit_unwrap()) - .map(Some) - .unwrap_or_else(|| { - match get_diary_timed_config(rt, diaryname).map_err_trace_exit_unwrap() { - Some(t) => Some(t), - None => { - warn!("Missing config: 'diary.diaries.{}.timed'", diaryname); - warn!("Assuming 'false'"); - None - } - } - }) - .map(|timed| { - let time = create_id_from_clispec(&create, timed); - diary.new_entry_at(&diaryname, &time) - .context(err_msg("Store write error")) - .map_err(Error::from) - }) - .unwrap_or_else(|| { - debug!("Creating non-timed entry"); - diary.new_entry_today(diaryname) - }) - .map_dbg(|e| format!("Created: {}", e.get_location())) - .map_err_trace_exit_unwrap() + let timed = match create.value_of("timed").map(|t| parse_timed_string(t, diaryname)) { + Some(t) => t.map(Some), + None => get_diary_timed_config(rt, diaryname) + }?; + + if let Some(timed) = timed { + let time = create_id_from_clispec(&create, timed)?; + diary.new_entry_at(&diaryname, &time) + .context(err_msg("Store write error")) + .map_err(Error::from) + } else { + debug!("Creating non-timed entry"); + diary.new_entry_today(diaryname) + } } -fn create_id_from_clispec(create: &ArgMatches, timed_type: Timed) -> NaiveDateTime { +fn create_id_from_clispec(create: &ArgMatches, timed_type: Timed) -> Result<NaiveDateTime> { use std::str::FromStr; let dt = Local::now(); @@ -102,71 +85,73 @@ fn create_id_from_clispec(create: &ArgMatches, timed_type: Timed) -> NaiveDateTi match timed_type { Timed::Daily => { debug!("Creating daily-timed entry"); - ndt.with_hour(0) + Ok(ndt.with_hour(0) .unwrap() // safe because hour = 0 is safe .with_minute(0) .unwrap() // safe because minute = 0 is safe .with_second(0) - .unwrap() // safe because second = 0 is safe + .unwrap()) // safe because second = 0 is safe }, Timed::Hourly => { debug!("Creating hourly-timed entry"); - ndt.with_minute(0) + Ok(ndt.with_minute(0) .unwrap() // safe because minute = 0 is safe .with_second(0) - .unwrap() // safe because second = 0 is safe + .unwrap()) // safe because second = 0 is safe }, Timed::Minutely => { let min = create .value_of("minute") .map_dbg(|m| format!("minute = {:?}", m)) - .and_then(|s| { + .map(|s| { FromStr::from_str(s) - .map_err(|_| warn!("Could not parse minute: '{}'", s)) - .ok() + .map_err(Error::from) + .context(format_err!("Could not parse minute: '{}'", s)) + .map_err(Error::from) }) + .transpose()? .unwrap_or_else(|| ndt.minute()); ndt.with_minute(min) - .unwrap_or_else(|| { - error!("Cannot set {} as minute, would yield invalid time!", min); - ::std::process::exit(1) + .ok_or_else(|| { + format_err!("Cannot set {} as minute, would yield invalid time!", min) }) - .with_second(0) - .unwrap() // safe because second = 0 is safe + .map(|ndt| ndt.with_second(0).unwrap()) // safe because second = 0 is safe }, Timed::Secondly => { let min = create .value_of("minute") .map_dbg(|m| format!("minute = {:?}", m)) - .and_then(|s| { + .map(|s| { FromStr::from_str(s) - .map_err(|_| warn!("Could not parse minute: '{}'", s)) - .ok() + .map_err(Error::from) + .context(format_err!("Could not parse minute: '{}'", s)) + .map_err(Error::from) }) + .transpose()? .unwrap_or_else(|| ndt.minute()); let sec = create .value_of("second") .map_dbg(|s| format!("second = {:?}", s)) - .and_then(|s| { + .map(|s| { FromStr::from_str(s) - .map_err(|_| warn!("Could not parse second: '{}'", s)) - .ok() + .map_err(Error::from) + .context(format_err!("Could not parse second: '{}'", s)) + .map_err(Error::from) }) + .transpose()? .unwrap_or_else(|| ndt.second()); ndt.with_minute(min) - .unwrap_or_else(|| { - error!("Cannot set {} as minute, would yield invalid time!", min); - ::std::process::exit(1) - }) + .ok_or_else(|| { + format_err!("Cannot set {} as minute, would yield invalid time!", min) + })? .with_second(sec) - .unwrap_or_else(|| { - error!("Cannot set {} as second, would yield invalid time!", sec); - ::std::process::exit(1) + .ok_or_else(|| { + format_err!("Cannot set {} as second, would yield invalid time!", sec) }) }, } diff --git a/bin/domain/imag-diary/src/delete.rs b/bin/domain/imag-diary/src/delete.rs index 1b254c18..84a2e586 100644 --- a/bin/domain/imag-diary/src/delete.rs +++ b/bin/domain/imag-diary/src/delete.rs @@ -17,26 +17,23 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -use std::process::exit; - use chrono::naive::NaiveDateTime as NDT; +use failure::Fallible as Result; +use failure::err_msg; use libimagdiary::diaryid::DiaryId; use libimagrt::runtime::Runtime; use libimagtimeui::datetime::DateTime; use libimagtimeui::parse::Parse; -use libimagutil::warn_exit::warn_exit; use libimagstore::storeid::IntoStoreId; -use libimagerror::trace::MapErrTrace; -use libimagerror::exit::ExitUnwrap; use crate::util::get_diary_name; -pub fn delete(rt: &Runtime) { +pub fn delete(rt: &Runtime) -> Result<()> { use libimaginteraction::ask::ask_bool; let diaryname = get_diary_name(rt) - .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); + .ok_or_else(|| err_msg("No diary selected. Use either the configuration file or the commandline option"))?; let to_del_location = rt .cli() @@ -46,34 +43,21 @@ pub fn delete(rt: &Runtime) { .map(|dt| { debug!("DateTime = {:?}", dt); dt }) .and_then(DateTime::parse) .map(Into::into) - .ok_or_else(|| warn_exit("Not deleting entries: missing date/time specification", 1)) + .ok_or_else(|| err_msg("Not deleting entries: missing date/time specification")) .and_then(|dt: NDT| DiaryId::from_datetime(diaryname.clone(), dt).into_storeid()) - .and_then(|id| rt.store().retrieve(id)) - .map_err_trace_exit_unwrap() + .and_then(|id| rt.store().retrieve(id))? .get_location() .clone(); - let mut input = rt.stdin().unwrap_or_else(|| { - error!("No input stream. Cannot ask for permission"); - exit(1); - }); - + let mut input = rt.stdin().ok_or_else(|| err_msg("No input stream. Cannot ask for permission"))?; let mut output = rt.stdout(); - if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true), &mut input, &mut output) - .map_err_trace_exit_unwrap() - { + if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true), &mut input, &mut output)? { info!("Aborting delete action"); - return; + return Ok(()); } - rt.report_touched(&to_del_location).unwrap_or_exit(); - - rt - .store() - .delete(to_del_location) - .map_err_trace_exit_unwrap(); - - info!("Ok!"); + rt.report_touched(&to_del_location)?; + rt.store().delete(to_del_location) } diff --git a/bin/domain/imag-diary/src/lib.rs b/bin/domain/imag-diary/src/lib.rs index 23629dc9..f87cd927 100644 --- a/bin/domain/imag-diary/src/lib.rs +++ b/bin/domain/imag-diary/src/lib.rs @@ -36,6 +36,7 @@ #[macro_use] extern crate log; #[macro_use] extern crate failure; +extern crate resiter; extern crate clap; extern crate chrono; extern crate toml; @@ -56,11 +57,12 @@ use std::io::Write; use libimagrt::runtime::Runtime; use libimagrt::application::ImagApplication; -use libimagerror::trace::MapErrTrace; use itertools::Itertools; use clap::App; use failure::Fallible as Result; +use failure::err_msg; +use failure::Error; mod create; mod delete; @@ -81,25 +83,21 @@ use crate::view::view; pub enum ImagDiary {} impl ImagApplication for ImagDiary { fn run(rt: Runtime) -> Result<()> { - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "diaries" => diaries(&rt), - "create" => create(&rt), - "delete" => delete(&rt), - "list" => list(&rt), - "view" => view(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-diary", 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"))? { + "diaries" => diaries(&rt), + "create" => create(&rt), + "delete" => delete(&rt), + "list" => list(&rt), + "view" => view(&rt), + other => { + debug!("Unknown command"); + if rt.handle_unknown_subcommand("imag-diary", 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> { @@ -119,20 +117,18 @@ impl ImagApplication for ImagDiary { } } -fn diaries(rt: &Runtime) { +fn diaries(rt: &Runtime) -> Result<()> { use libimagdiary::diary::Diary; - use libimagerror::io::ToExitCode; - use libimagerror::exit::ExitUnwrap; - use libimagerror::iter::TraceIterator; let out = rt.stdout(); let mut outlock = out.lock(); rt.store() - .diary_names() - .map_err_trace_exit_unwrap() - .trace_unwrap_exit() + .diary_names()? + .collect::<Result<Vec<String>>>()? + .into_iter() .unique() - .for_each(|n| writeln!(outlock, "{}", n).to_exit_code().unwrap_or_exit()) + .map(|n| writeln!(outlock, "{}", n).map_err(Error::from)) + .collect() } diff --git a/bin/domain/imag-diary/src/list.rs b/bin/domain/imag-diary/src/list.rs index 9c4593ec..634b0ff7 100644 --- a/bin/domain/imag-diary/src/list.rs +++ b/bin/domain/imag-diary/src/list.rs @@ -19,33 +19,28 @@ use std::io::Write; +use failure::Fallible as Result; +use failure::err_msg; +use failure::Error; +use resiter::AndThen; + use libimagdiary::diary::Diary; use libimagrt::runtime::Runtime; -use libimagutil::warn_exit::warn_exit; -use libimagerror::trace::MapErrTrace; -use libimagerror::iter::TraceIterator; -use libimagerror::io::ToExitCode; -use libimagerror::exit::ExitUnwrap; use libimagutil::debug_result::*; use libimagdiary::diaryid::DiaryId; use libimagdiary::diaryid::FromStoreId; use libimagstore::storeid::IntoStoreId; -use failure::Fallible as Result; - use crate::util::get_diary_name; -pub fn list(rt: &Runtime) { +pub fn list(rt: &Runtime) -> Result<()> { let diaryname = get_diary_name(rt) - .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); + .ok_or_else(|| err_msg("No diary selected. Use either the configuration file or the commandline option"))?; let mut ids = Diary::entries(rt.store(), &diaryname) - .map_dbg_str("Ok") - .map_err_trace_exit_unwrap() - .trace_unwrap_exit() - .map(|id| DiaryId::from_storeid(&id)) - .collect::<Result<Vec<_>>>() - .map_err_trace_exit_unwrap(); + .map_dbg_str("Ok")? + .and_then_ok(|id| DiaryId::from_storeid(&id)) + .collect::<Result<Vec<_>>>()?; ids.sort_by_key(|id| { [id.year() as u32, id.month(), id.day(), id.hour(), id.minute(), id.second()] @@ -53,13 +48,15 @@ pub fn list(rt: &Runtime) { ids.into_iter() .map(IntoStoreId::into_storeid) - .trace_unwrap_exit() - .for_each(|id| { - rt.report_touched(&id).unwrap_or_exit(); + .and_then_ok(|id| { + rt.report_touched(&id)?; if !rt.output_is_pipe() { - writeln!(rt.stdout(), "{}", id).to_exit_code().unwrap_or_exit() + writeln!(rt.stdout(), "{}", id).map_err(Error::from) + } else { + Ok(()) } - }); + }) + .collect() } diff --git a/bin/domain/imag-diary/src/util.rs b/bin/domain/imag-diary/src/util.rs index 3059b6db..2ae01172 100644 --- a/bin/domain/imag-diary/src/util.rs +++ b/bin/domain/imag-diary/src/util.rs @@ -89,8 +89,6 @@ pub fn parse_timed_string(s: &str, diary_name: &str) -> Result<Timed> { } else if s == "s" || s == "secondly" { Ok(Timed::Secondly) } else { - let s = format!("Cannot parse config: 'diary.diaries.{}.timed = {}'", - diary_name, s); - Err(format_err!("{}", s)) + Err(format_err!("Cannot parse config: 'diary.diaries.{}.timed = {}'", diary_name, s)) } } diff --git a/bin/domain/imag-diary/src/view.rs b/bin/domain/imag-diary/src/view.rs index 9c77691f..c52d274f 100644 --- a/bin/domain/imag-diary/src/view.rs +++ b/bin/domain/imag-diary/src/view.rs @@ -17,47 +17,32 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use failure::Fallible as Result; +use failure::err_msg; +use failure::Error; +use resiter::AndThen; +use resiter::IterInnerOkOrElse; + use libimagdiary::diary::Diary; -use libimagdiary::viewer::DiaryViewer as DV; +use libimagdiary::viewer::DiaryViewer; use libimagrt::runtime::Runtime; -use libimagerror::trace::MapErrTrace; -use libimagerror::iter::TraceIterator; -use libimagerror::exit::ExitUnwrap; -use libimagerror::io::ToExitCode; -use libimagutil::warn_exit::warn_exit; use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagentryview::viewer::Viewer; -use libimagentryview::error::Error; use crate::util::get_diary_name; -pub fn view(rt: &Runtime) { - let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); - let hdr = rt.cli().subcommand_matches("view").unwrap().is_present("show-header"); - - let entries = Diary::entries(rt.store(), &diaryname) - .map_err_trace_exit_unwrap() - .into_get_iter(rt.store()) - .trace_unwrap_exit() - .map(|e| e.unwrap_or_else(|| { - error!("Failed to fetch entry"); - ::std::process::exit(1) - })); - - let entries = entries.map(|e| { - rt.report_touched(e.get_location()).unwrap_or_exit(); - - e - }); - - let out = rt.stdout(); +pub fn view(rt: &Runtime) -> Result<()> { + let diaryname = get_diary_name(rt).ok_or_else(|| err_msg("No diary name"))?; + let hdr = rt.cli().subcommand_matches("view").unwrap().is_present("show-header"); + let out = rt.stdout(); let mut outlock = out.lock(); + let viewer = DiaryViewer::new(hdr); - if let Err(e) = DV::new(hdr).view_entries(entries, &mut outlock) { - match e { - Error::Io(e) => Err(e).to_exit_code().unwrap_or_exit(), - Error::Other(e) => Err(e).map_err_trace_exit_unwrap() - } - } + Diary::entries(rt.store(), &diaryname)? + .into_get_iter(rt.store()) + .map_inner_ok_or_else(|| err_msg("Did not find one entry")) + .and_then_ok(|e| viewer.view_entry(&e, &mut outlock).map_err(Error::from).map(|_| e)) + .and_then_ok(|e| rt.report_touched(e.get_location()).map_err(Error::from)) + .collect() } diff --git a/bin/domain/imag-log/Cargo.toml b/bin/domain/imag-log/Cargo.toml index 5466caab..6bb3eeb2 100644 --- a/bin/domain/imag-log/Cargo.toml +++ b/bin/domain/imag-log/Cargo.toml @@ -27,6 +27,7 @@ is-match = "0.1.0" itertools = "0.8.0" failure = "0.1.5" textwrap = "0.11.0" +resiter = "0.4.0" libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" } diff --git a/bin/domain/imag-log/src/lib.rs b/bin/domain/imag-log/src/lib.rs index 338a482d..a6d21427 100644 --- a/bin/domain/imag-log/src/lib.rs +++ b/bin/domain/imag-log/src/lib.rs @@ -42,6 +42,7 @@ extern crate toml_query; extern crate itertools; extern crate failure; extern crate textwrap; +extern crate resiter; extern crate libimaglog; extern crate libimagrt; @@ -51,20 +52,18 @@ extern crate libimagdiary; use std::io::Write; use std::io::Cursor; -use std::result::Result as RResult; use std::str::FromStr; use failure::Error; use failure::err_msg; use failure::Fallible as Result; +use resiter::Map; +use resiter::AndThen; +use resiter::IterInnerOkOrElse; +use resiter::Filter; use libimagrt::application::ImagApplication; use libimagrt::runtime::Runtime; -use libimagerror::trace::MapErrTrace; -use libimagerror::io::ToExitCode; -use libimagerror::exit::ExitUnwrap; -use libimagerror::iter::TraceIterator; -use libimagerror::exit::ExitCode; use libimagdiary::diary::Diary; use libimagdiary::diaryid::DiaryId; use libimaglog::log::Log; @@ -88,37 +87,33 @@ impl ImagApplication for ImagLog { if let Some(scmd) = rt.cli().subcommand_name() { match scmd { "show" => show(&rt), - other => { + other => { debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-log", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); + if rt.handle_unknown_subcommand("imag-bookmark", other, rt.cli())?.success() { + Ok(()) + } else { + Err(err_msg("Failed to handle unknown subcommand")) + } }, } } else { let text = get_log_text(&rt); - let diary_name = rt.cli() - .value_of("diaryname") - .map(String::from) - .unwrap_or_else(|| get_diary_name(&rt)); + let diary_name = match rt.cli().value_of("diaryname").map(String::from) { + Some(s) => s, + None => get_diary_name(&rt)?, + }; debug!("Writing to '{}': {}", diary_name, text); - rt - .store() + rt.store() .new_entry_now(&diary_name) - .map(|mut fle| { - fle.make_log_entry().map_err_trace_exit_unwrap(); + .and_then(|mut fle| { + fle.make_log_entry()?; *fle.get_content_mut() = text; - fle + Ok(fle) }) - .map(|fle| rt.report_touched(fle.get_location()).unwrap_or_exit()) - .map_err_trace_exit_unwrap(); - + .and_then(|fle| rt.report_touched(fle.get_location()).map_err(Error::from)) } - - Ok(()) } fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> { @@ -138,7 +133,7 @@ impl ImagApplication for ImagLog { } } -fn show(rt: &Runtime) { +fn show(rt: &Runtime) -> Result<()> { use std::borrow::Cow; use libimagdiary::iter::DiaryEntryIterator; @@ -147,29 +142,33 @@ fn show(rt: &Runtime) { let scmd = rt.cli().subcommand_matches("show").unwrap(); // safed by main() let iters : Vec<DiaryEntryIterator> = match scmd.values_of("show-name") { Some(values) => values - .map(|diary_name| Diary::entries(rt.store(), diary_name).map_err_trace_exit_unwrap()) - .collect(), + .map(|diary_name| Diary::entries(rt.store(), diary_name)) + .collect::<Result<Vec<DiaryEntryIterator>>>(), None => if scmd.is_present("show-all") { debug!("Showing for all diaries"); - rt.store() - .diary_names() - .map_err_trace_exit_unwrap() + let iter = rt.store() + .diary_names()? .map(|diary_name| { - let diary_name = diary_name.map_err_trace_exit_unwrap(); + let diary_name = diary_name?; debug!("Getting entries for Diary: {}", diary_name); - let entries = Diary::entries(rt.store(), &diary_name).map_err_trace_exit_unwrap(); + let entries = Diary::entries(rt.store(), &diary_name)?; let diary_name = Cow::from(diary_name); - (entries, diary_name) + Ok((entries, diary_name)) }) + .collect::<Result<Vec<(DiaryEntryIterator, Cow<str>)>>>()?; + + let iter = iter.into_iter() .unique_by(|tpl| tpl.1.clone()) .map(|tpl| tpl.0) - .collect() + .collect::<Vec<DiaryEntryIterator>>(); + + Ok(iter) } else { // showing default logs - vec![Diary::entries(rt.store(), &get_diary_name(rt)).map_err_trace_exit_unwrap()] + get_diary_name(rt).and_then(|dname| Diary::entries(rt.store(), &dname)).map(|e| vec![e]) } - }; + }?; let mut do_wrap = if scmd.is_present("show-wrap") { Some(80) @@ -179,26 +178,25 @@ fn show(rt: &Runtime) { let do_remove_newlines = scmd.is_present("show-skipnewlines"); if let Some(wrap_value) = scmd.value_of("show-wrap") { - do_wrap = Some(usize::from_str(wrap_value).map_err(Error::from).map_err_trace_exit_unwrap()); + do_wrap = Some(usize::from_str(wrap_value).map_err(Error::from)?); } let mut output = rt.stdout(); - iters.into_iter() + let v = iters.into_iter() .flatten() .into_get_iter(rt.store()) - .trace_unwrap_exit() - .filter_map(|opt| { - if opt.is_none() { - warn!("Failed to retrieve an entry from an existing store id"); - } - - opt - }) - .filter(|e| e.is_log().map_err_trace_exit_unwrap()) - .map(|entry| (entry.diary_id().map_err_trace_exit_unwrap(), entry)) - .sorted_by_key(|tpl| tpl.0.get_date_representation()) - .map(|tpl| { debug!("Found entry: {:?}", tpl.1); tpl }) + .map_inner_ok_or_else(|| err_msg("Did not find one entry")) + .and_then_ok(|e| e.is_log().map(|b| (b, e))) + .filter_ok(|tpl| tpl.0) + .map_ok(|tpl| tpl.1) + .and_then_ok(|entry| entry.diary_id().map(|did| (did.get_date_representation(), did, entry))) + .collect::<Result<Vec<_>>>()?; + + v.into_iter() + .sorted_by_key(|tpl| tpl.0) + .map(|tpl| (tpl.1, tpl.2)) + .inspect(|tpl| debug!("Found entry: {:?}", tpl.1)) .map(|(id, entry)| { if let Some(wrap_limit) = do_wrap { // assume a capacity here: @@ -206,70 +204,57 @@ fn show(rt: &Runtime) { // 10 + 4 + 2 + 2 + 2 + 2 + 6 + 4 = 32 // plus text, which we assume to be 120 characters... lets allocate 256 bytes. let mut buffer = Cursor::new(Vec::with_capacity(256)); - do_write_to(&mut buffer, id, &entry, do_remove_newlines).unwrap_or_exit(); - let buffer = String::from_utf8(buffer.into_inner()) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); + do_write_to(&mut buffer, id, &entry, do_remove_newlines)?; + let buffer = String::from_utf8(buffer.into_inner())?; // now lets wrap - for line in ::textwrap::wrap(&buffer, wrap_limit).iter() { - writeln!(&mut output, "{}", line).to_exit_code()?; - } + ::textwrap::wrap(&buffer, wrap_limit) + .iter() + .map(|line| writeln!(&mut output, "{}", line).map_err(Error::from)) + .collect::<Result<Vec<_>>>()?; } else { - do_write_to(&mut output, id, &entry, do_remove_newlines).unwrap_or_exit(); + do_write_to(&mut output, id, &entry, do_remove_newlines)?; } - rt - .report_touched(entry.get_location()) - .unwrap_or_exit(); - Ok(()) + rt.report_touched(entry.get_location()).map_err(Error::from) }) - .collect::<RResult<Vec<()>, ExitCode>>() - .unwrap_or_exit(); + .collect::<Result<Vec<_>>>() + .map(|_| ()) } -fn get_diary_name(rt: &Runtime) -> String { +fn get_diary_name(rt: &Runtime) -> Result<String> { use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadTypeExt; let cfg = rt .config() - .ok_or_else(|| err_msg("Configuration not present, cannot continue")) - .map_err_trace_exit_unwrap(); + .ok_or_else(|| err_msg("Configuration not present, cannot continue"))?; let current_log = cfg - .read_string("log.default") - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .ok_or_else(|| err_msg("Configuration missing: 'log.default'")) - .map_err_trace_exit_unwrap(); + .read_string("log.default")? + .ok_or_else(|| err_msg("Configuration missing: 'log.default'"))?; if cfg - .read("log.logs") - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .ok_or_else(|| err_msg("Configuration missing: 'log.logs'")) - .map_err_trace_exit_unwrap() + .read("log.logs")? + .ok_or_else(|| err_msg("Configuration missing: 'log.logs'"))? .as_array() - .ok_or_else(|| err_msg("Configuration 'log.logs' is not an Array")) - .map_err_trace_exit_unwrap() + .ok_or_else(|| err_msg("Configuration 'log.logs' is not an Array"))? .iter() .map(|e| if !is_match!(e, &Value::String(_)) { - error!("Configuration 'log.logs' is not an Array<String>!"); - ::std::process::exit(1) + Err(err_msg("Configuration 'log.logs' is not an Array<String>!")) } else { - e + Ok(e) }) - .map(Value::as_str) - .map(Option::unwrap) // safe by map from above - .map(String::from) - .find(|log| log == ¤t_log) + .map_ok(|value| value.as_str().unwrap()) + .map_ok(String::from) + .collect::<Result<Vec<_>>>()? + .iter() + .find(|log| *log == ¤t_log) .is_none() { - error!("'log.logs' does not contain 'log.default'"); - ::std::process::exit(1) + Err(err_msg("'log.logs' does not contain 'log.default'")) } else { - current_log + Ok(current_log) } } @@ -287,7 +272,7 @@ fn get_log_text(rt: &Runtime) -> String { }) } -fn do_write_to<'a>(sink: &mut dyn Write, id: DiaryId, entry: &FileLockEntry<'a>, do_remove_newlines: bool) -> RResult<(), ExitCode> { +fn do_write_to<'a>(sink: &mut dyn Write, id: DiaryId, entry: &FileLockEntry<'a>, do_remove_newlines: bool) -> Result<()> { let text = if do_remove_newlines { entry.get_content().trim_end().replace("\n", "") } else { @@ -303,6 +288,6 @@ fn do_write_to<'a>(sink: &mut dyn Write, id: DiaryId, entry: &FileLockEntry<'a>, H = id.hour(), M = id.minute(), text = text) - .to_exit_code() + .map_err(Error::from) } |