Merge branch 'imag-bookmark-noexit' into master

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
Matthias Beyer 2019-10-27 18:44:54 +01:00
commit fa7e8cc6b4
2 changed files with 79 additions and 108 deletions

View file

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

View file

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