Transform imag-bookmark to not call exit() but propagate errors to main()

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
Matthias Beyer 2019-10-27 10:50:30 +01:00
parent b6facfff6b
commit 641c6c7761
2 changed files with 79 additions and 108 deletions

View file

@ -24,6 +24,7 @@ log = "0.4.6"
toml = "0.5.1"
toml-query = "0.9.2"
failure = "0.1.5"
resiter = "0.4.0"
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }

View file

@ -39,6 +39,7 @@ extern crate clap;
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate failure;
extern crate resiter;
extern crate libimagbookmark;
extern crate libimagrt;
@ -47,12 +48,13 @@ extern crate libimagutil;
extern crate libimagentrylink;
use std::io::Write;
use std::process::exit;
use std::ops::DerefMut;
use toml_query::read::TomlValueReadTypeExt;
use failure::Error;
use failure::err_msg;
use failure::Fallible as Result;
use resiter::AndThen;
use clap::App;
use libimagrt::runtime::Runtime;
@ -60,10 +62,6 @@ use libimagrt::application::ImagApplication;
use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::collection::BookmarkCollectionStore;
use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{MapErrTrace, trace_error};
use libimagerror::io::ToExitCode;
use libimagerror::exit::ExitUnwrap;
use libimagutil::debug_result::DebugResult;
use libimagentrylink::linkable::Linkable;
mod ui;
@ -75,24 +73,20 @@ mod ui;
pub enum ImagBookmark {}
impl ImagApplication for ImagBookmark {
fn run(rt: Runtime) -> Result<()> {
if let Some(name) = rt.cli().subcommand_name() {
debug!("Call {}", name);
match name {
"add" => add(&rt),
"collection" => collection(&rt),
"list" => list(&rt),
"remove" => remove(&rt),
other => {
debug!("Unknown command");
let _ = rt.handle_unknown_subcommand("imag-bookmark", 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"))? {
"add" => add(&rt),
"collection" => collection(&rt),
"list" => list(&rt),
"remove" => remove(&rt),
other => {
debug!("Unknown command");
if rt.handle_unknown_subcommand("imag-bookmark", 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> {
@ -112,131 +106,107 @@ impl ImagApplication for ImagBookmark {
}
}
fn add(rt: &Runtime) {
fn add(rt: &Runtime) -> Result<()> {
let scmd = rt.cli().subcommand_matches("add").unwrap();
let coll = get_collection_name(rt, "add", "collection");
let coll = get_collection_name(rt, "add", "collection")?;
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
.map_err_trace_exit_unwrap()
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
.map_err_trace_exit_unwrap();
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)?
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))?;
rt.report_touched(collection.get_location()).unwrap_or_exit();
rt.report_touched(collection.get_location())?;
for url in scmd.values_of("urls").unwrap() { // unwrap saved by clap
let new_ids = BookmarkCollection::add_link(collection.deref_mut(), rt.store(), BookmarkLink::from(url))
.map_err_trace_exit_unwrap();
rt.report_all_touched(new_ids.into_iter()).unwrap_or_exit();
}
info!("Ready");
scmd.values_of("urls")
.unwrap()
.into_iter()
.map(|url| {
let new_ids = BookmarkCollection::add_link(collection.deref_mut(), rt.store(), BookmarkLink::from(url))?;
rt.report_all_touched(new_ids.into_iter()).map_err(Error::from)
})
.collect()
}
fn collection(rt: &Runtime) {
fn collection(rt: &Runtime) -> Result<()> {
let scmd = rt.cli().subcommand_matches("collection").unwrap();
if scmd.is_present("add") { // adding a new collection
let name = scmd.value_of("add").unwrap();
if let Ok(id) = BookmarkCollectionStore::new(rt.store(), &name) {
rt.report_touched(id.get_location()).unwrap_or_exit();
info!("Created: {}", name);
} else {
warn!("Creating collection {} failed", name);
exit(1);
}
let id = BookmarkCollectionStore::new(rt.store(), &name)?;
rt.report_touched(id.get_location())?;
info!("Created: {}", name);
}
if scmd.is_present("remove") { // remove a collection
let name = scmd.value_of("remove").unwrap();
{ // remove all links
BookmarkCollectionStore::get(rt.store(), &name)
.map_err_trace_exit_unwrap()
.ok_or_else(|| format_err!("Collection does not exist: {}", name))
.map_err_trace_exit_unwrap()
.unlink(rt.store())
.map_err_trace_exit_unwrap();
BookmarkCollectionStore::get(rt.store(), &name)?
.ok_or_else(|| format_err!("Collection does not exist: {}", name))?
.unlink(rt.store())?;
}
if BookmarkCollectionStore::delete(rt.store(), &name).is_ok() {
info!("Deleted: {}", name);
} else {
warn!("Deleting collection {} failed", name);
exit(1);
}
BookmarkCollectionStore::delete(rt.store(), &name)?;
info!("Deleted: {}", name);
}
Ok(())
}
fn list(rt: &Runtime) {
let coll = get_collection_name(rt, "list", "collection");
fn list(rt: &Runtime) -> Result<()> {
let coll = get_collection_name(rt, "list", "collection")?;
let collection = BookmarkCollectionStore::get(rt.store(), &coll)
.map_err_trace_exit_unwrap()
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
.map_err_trace_exit_unwrap();
let collection = BookmarkCollectionStore::get(rt.store(), &coll)?
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))?;
rt.report_touched(collection.get_location()).unwrap_or_exit();
rt.report_touched(collection.get_location())?;
let mut i = 0; // poor mans enumerate()
collection
.get_links(rt.store())
.map_dbg_str("Listing...")
.map_err_trace_exit_unwrap()
.enumerate()
.for_each(|(i, link)| match link {
Ok(link) => writeln!(rt.stdout(), "{: >3}: {}", i, link).to_exit_code().unwrap_or_exit(),
Err(e) => trace_error(&e)
});
debug!("... ready with listing");
.get_links(rt.store())?
.and_then_ok(|link| {
let r = writeln!(rt.stdout(), "{: >3}: {}", i, link).map_err(Error::from);
i += 1;
r
})
.collect()
}
fn remove(rt: &Runtime) {
fn remove(rt: &Runtime) -> Result<()> {
let scmd = rt.cli().subcommand_matches("remove").unwrap();
let coll = get_collection_name(rt, "list", "collection");
let coll = get_collection_name(rt, "list", "collection")?;
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
.map_err_trace_exit_unwrap()
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
.map_err_trace_exit_unwrap();
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)?
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))?;
rt.report_touched(collection.get_location()).unwrap_or_exit();
rt.report_touched(collection.get_location())?;
for url in scmd.values_of("urls").unwrap() { // enforced by clap
let removed_links = BookmarkCollection::remove_link(collection.deref_mut(), rt.store(), BookmarkLink::from(url))
.map_err_trace_exit_unwrap();
rt.report_all_touched(removed_links.into_iter()).unwrap_or_exit();
}
info!("Ready");
scmd.values_of("urls")
.unwrap()
.into_iter()
.map(|url| {
let removed_links = BookmarkCollection::remove_link(collection.deref_mut(), rt.store(), BookmarkLink::from(url))?;
rt.report_all_touched(removed_links.into_iter()).map_err(Error::from)
})
.collect()
}
fn get_collection_name(rt: &Runtime,
subcommand_name: &str,
collection_argument_name: &str)
-> String
-> Result<String>
{
rt.cli()
if let Some(cn) = rt.cli()
.subcommand_matches(subcommand_name)
.and_then(|scmd| scmd.value_of(collection_argument_name).map(String::from))
.unwrap_or_else(|| {
rt.config()
.map(|cfg| {
cfg.read_string("bookmark.default_collection")
.map_err(Error::from)
.map_err_trace_exit_unwrap()
.ok_or_else(|| {
error!("Missing config: 'bookmark.default_collection'. Set or use commandline to specify.");
exit(1)
})
.unwrap()
.clone()
})
.unwrap_or_else(|| {
error!("Failed to read configuration");
exit(1)
})
})
{
return Ok(cn)
} else {
rt.config().ok_or_else(|| err_msg("No configuration availablew"))
.and_then(|cfg| {
cfg.read_string("bookmark.default_collection")?
.ok_or_else(|| err_msg("Missing config: 'bookmark.default_collection'."))
})
}
}