summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-12-20 22:59:01 +0100
committerMatthias Beyer <mail@beyermatthias.de>2019-12-20 22:59:01 +0100
commit7542b8c8fe19ede0f06eb23d3fae8887fcb106cb (patch)
tree2f76fbb15cba3dd5a6b322e8a5b298651f6a81a6
parent733979609fb07d5ed301035828ae612dc332f09f (diff)
Rewrite imag-log to propagate errors to main() instead of exit()ing
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--bin/domain/imag-log/Cargo.toml1
-rw-r--r--bin/domain/imag-log/src/lib.rs169
2 files changed, 78 insertions, 92 deletions
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 == &current_log)
+ .map_ok(|value| value.as_str().unwrap())
+ .map_ok(String::from)
+ .collect::<Result<Vec<_>>>()?
+ .iter()
+ .find(|log| *log == &current_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)
}