Merge branch 'failure'

I'm so happy to finally be able to merge this patchset. After four days
of work, we finally convert the whole codebase from error_chain error
handling to failure.

Dependencies are now imported from "master" or even "failure" branches,
which will result in dependencies breaking the imag build as soon as the
"failure" branches vanish or the master breaks on the dependencies, but
we do it anyways until we are in release-shape.

Thanks goes to Kai for emotional support during the last weekend while
developing this patchset.

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
Matthias Beyer 2018-10-30 19:23:00 +01:00
commit a749d97a16
231 changed files with 1579 additions and 3404 deletions

View file

@ -26,6 +26,7 @@ log = "0.4.0"
url = "1.2" url = "1.2"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = "0.7"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -35,6 +35,7 @@
extern crate clap; extern crate clap;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate failure;
extern crate libimagentryannotation; extern crate libimagentryannotation;
extern crate libimagentryedit; extern crate libimagentryedit;
@ -46,9 +47,11 @@ extern crate libimagutil;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use failure::Error;
use failure::err_msg;
use libimagentryannotation::annotateable::*; use libimagentryannotation::annotateable::*;
use libimagentryannotation::annotation_fetcher::*; use libimagentryannotation::annotation_fetcher::*;
use libimagentryannotation::error::AnnotationError as AE;
use libimagentryedit::edit::*; use libimagentryedit::edit::*;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::exit::ExitUnwrap; use libimagerror::exit::ExitUnwrap;
@ -97,7 +100,7 @@ fn add(rt: &Runtime) {
let _ = rt.store() let _ = rt.store()
.get(entry_name) .get(entry_name)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(AE::from("Entry does not exist".to_owned())) .ok_or_else(|| Error::from(err_msg("Entry does not exist".to_owned())))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.annotate(rt.store(), annotation_name) .annotate(rt.store(), annotation_name)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
@ -114,7 +117,7 @@ fn remove(rt: &Runtime) {
let mut entry = rt.store() let mut entry = rt.store()
.get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit_unwrap(1)) .get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit_unwrap(1))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(AE::from("Entry does not exist".to_owned())) .ok_or_else(|| Error::from(err_msg("Entry does not exist".to_owned())))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let annotation = entry let annotation = entry
@ -148,7 +151,7 @@ fn list(rt: &Runtime) {
.store() .store()
.get(pb.into_storeid().map_err_trace_exit_unwrap(1)) .get(pb.into_storeid().map_err_trace_exit_unwrap(1))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(AE::from("Entry does not exist".to_owned())) .ok_or_else(|| Error::from(err_msg("Entry does not exist")))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.annotations(rt.store()) .annotations(rt.store())
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)

View file

@ -24,7 +24,7 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -18,8 +18,9 @@ build = "../../../build.rs"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
indicatif = "0.9" indicatif = "0.9"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -36,6 +36,7 @@ extern crate clap;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate indicatif; extern crate indicatif;
extern crate failure;
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
@ -52,12 +53,14 @@ use libimagerror::io::ToExitCode;
use libimagerror::exit::ExitUnwrap; use libimagerror::exit::ExitUnwrap;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::error::StoreError as Error;
use libimagentrylink::internal::*; use libimagentrylink::internal::*;
use toml::Value; use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use failure::Fallible as Result;
use failure::Error;
use failure::err_msg;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -76,7 +79,7 @@ struct Diagnostic {
impl Diagnostic { impl Diagnostic {
fn for_entry<'a>(entry: &FileLockEntry<'a>) -> Result<Diagnostic, ::libimagstore::error::StoreError> { fn for_entry<'a>(entry: &FileLockEntry<'a>) -> Result<Diagnostic> {
Ok(Diagnostic { Ok(Diagnostic {
id: entry.get_location().clone(), id: entry.get_location().clone(),
entry_store_version: entry entry_store_version: entry
@ -142,7 +145,7 @@ fn main() {
.into_get_iter() .into_get_iter()
.map(|e| { .map(|e| {
e.map_err_trace_exit_unwrap(1) e.map_err_trace_exit_unwrap(1)
.ok_or(Error::from("Unable to get entry".to_owned())) .ok_or_else(|| Error::from(err_msg("Unable to get entry".to_owned())))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}) })
.map(|e| { .map(|e| {
@ -163,7 +166,7 @@ fn main() {
diag diag
}) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>>>()
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
spinner.finish(); spinner.finish();
@ -265,6 +268,7 @@ fn main() {
fn get_config(rt: &Runtime, s: &'static str) -> Option<String> { fn get_config(rt: &Runtime, s: &'static str) -> Option<String> {
rt.config().and_then(|cfg| { rt.config().and_then(|cfg| {
cfg.read(s) cfg.read(s)
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.map(|opt| match opt { .map(|opt| match opt {
&Value::String(ref s) => s.to_owned(), &Value::String(ref s) => s.to_owned(),

View file

@ -26,6 +26,7 @@ log = "0.4.0"
url = "1.2" url = "1.2"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = "0.7"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -35,6 +35,7 @@
extern crate clap; extern crate clap;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate failure;
extern crate libimagentrygps; extern crate libimagentrygps;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
@ -47,8 +48,9 @@ use std::process::exit;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use libimagentrygps::error::GPSError as GE; use failure::Error;
use libimagentrygps::error::GPSErrorKind as GEK; use failure::err_msg;
use libimagentrygps::types::*; use libimagentrygps::types::*;
use libimagentrygps::entry::*; use libimagentrygps::entry::*;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
@ -100,7 +102,7 @@ fn add(rt: &Runtime) {
.map(|v| {debug!("Parsing = {}", v); v}) .map(|v| {debug!("Parsing = {}", v); v})
.map(FromStr::from_str) .map(FromStr::from_str)
.map(|elem| { .map(|elem| {
elem.or_else(|_| Err(GE::from(GEK::NumberConversionError))) elem.or_else(|_| Err(Error::from(err_msg("Error while converting number"))))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}) })
.collect::<Vec<i64>>(); .collect::<Vec<i64>>();

View file

@ -26,8 +26,9 @@ filters = "0.3"
nom = "3.2" nom = "3.2"
log = "0.4" log = "0.4"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
is-match = "0.1" is-match = "0.1"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -51,6 +51,7 @@ pub mod header_filter_lang {
use nom::digit; use nom::digit;
use nom::multispace; use nom::multispace;
use failure::Error;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
@ -403,6 +404,7 @@ pub mod header_filter_lang {
entry entry
.get_header() .get_header()
.read(selector_str) .read(selector_str)
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.map(|value| { .map(|value| {
let comp = Comparator(&self.compare_operator, &self.compare_value); let comp = Comparator(&self.compare_operator, &self.compare_value);

View file

@ -39,6 +39,7 @@ extern crate filters;
#[macro_use] extern crate is_match; #[macro_use] extern crate is_match;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate failure;
#[cfg(test)] #[cfg(test)]
extern crate env_logger; extern crate env_logger;
@ -68,7 +69,7 @@ fn main() {
let version = make_imag_version!(); let version = make_imag_version!();
let rt = generate_runtime_setup("imag-ids", let rt = generate_runtime_setup("imag-ids",
&version, &version,
"Print all ids, optionally filtered with a user-defined filter", "print all ids",
build_ui); build_ui);
let print_storepath = rt.cli().is_present("print-storepath"); let print_storepath = rt.cli().is_present("print-storepath");

View file

@ -25,8 +25,9 @@ maintenance = { status = "actively-developed" }
log = "0.4.0" log = "0.4.0"
url = "1.5" url = "1.5"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
prettytable-rs = "0.8" prettytable-rs = "0.8"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -35,6 +35,7 @@
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate clap; extern crate clap;
extern crate url; extern crate url;
extern crate failure;
#[macro_use] extern crate prettytable; #[macro_use] extern crate prettytable;
#[cfg(test)] extern crate toml; #[cfg(test)] extern crate toml;
#[cfg(test)] extern crate toml_query; #[cfg(test)] extern crate toml_query;
@ -55,22 +56,24 @@ extern crate libimagutil;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use failure::Error;
use failure::err_msg;
use libimagentrylink::external::ExternalLinker; use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker; use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::store_check::StoreLinkConsistentExt; use libimagentrylink::internal::store_check::StoreLinkConsistentExt;
use libimagentrylink::error::LinkError as LE;
use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::trace::{MapErrTrace, trace_error};
use libimagerror::exit::ExitUnwrap; use libimagerror::exit::ExitUnwrap;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagutil::warn_exit::warn_exit; use libimagutil::warn_exit::warn_exit;
use libimagutil::warn_result::*; use libimagutil::warn_result::*;
use url::Url; use url::Url;
use failure::Fallible as Result;
mod ui; mod ui;
@ -80,7 +83,7 @@ fn main() {
let version = make_imag_version!(); let version = make_imag_version!();
let rt = generate_runtime_setup("imag-link", let rt = generate_runtime_setup("imag-link",
&version, &version,
"Add/Remove links between entries", "Link entries",
build_ui); build_ui);
if rt.cli().is_present("check-consistency") { if rt.cli().is_present("check-consistency") {
let exit_code = match rt.store().check_link_consistency() { let exit_code = match rt.store().check_link_consistency() {
@ -119,11 +122,11 @@ fn main() {
warn_exit("No commandline call", 1) warn_exit("No commandline call", 1)
} }
}) })
.ok_or(LE::from("No commandline call".to_owned())) .ok_or_else(|| Error::from(err_msg("No commandline call".to_owned())))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
} }
fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> { fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>> {
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
debug!("Getting: {:?}", name); debug!("Getting: {:?}", name);
@ -336,11 +339,12 @@ mod tests {
use toml::value::Value; use toml::value::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use toml_query::error::Result as TomlQueryResult; use failure::Fallible as Result;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::store::{Result as StoreResult, FileLockEntry, Entry}; use libimagstore::store::{FileLockEntry, Entry};
fn setup_logging() { fn setup_logging() {
let _ = ::env_logger::try_init(); let _ = ::env_logger::try_init();
@ -355,7 +359,7 @@ mod tests {
use self::mock::generate_test_runtime; use self::mock::generate_test_runtime;
use self::mock::reset_test_runtime; use self::mock::reset_test_runtime;
fn create_test_default_entry<'a, S: AsRef<OsStr>>(rt: &'a Runtime, name: S) -> StoreResult<StoreId> { fn create_test_default_entry<'a, S: AsRef<OsStr>>(rt: &'a Runtime, name: S) -> Result<StoreId> {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
path.set_file_name(name); path.set_file_name(name);
@ -376,11 +380,10 @@ mod tests {
Ok(id) Ok(id)
} }
fn get_entry_links<'a>(entry: &'a FileLockEntry<'a>) -> TomlQueryResult<&'a Value> { fn get_entry_links<'a>(entry: &'a FileLockEntry<'a>) -> Result<&'a Value> {
match entry.get_header().read(&"links.internal".to_owned()) { match entry.get_header().read(&"links.internal".to_owned()).map_err(Error::from)? {
Err(e) => Err(e), Some(v) => Ok(v),
Ok(Some(v)) => Ok(v), None => panic!("Didn't find 'links' in {:?}", entry),
Ok(None) => panic!("Didn't find 'links' in {:?}", entry),
} }
} }
@ -394,7 +397,7 @@ mod tests {
#[test] #[test]
fn test_link_modificates() { fn test_link_modificates() {
setup_logging(); setup_logging();
let rt = generate_test_runtime(vec!["test1", "test2"]) let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
.unwrap(); .unwrap();
debug!("Runtime created"); debug!("Runtime created");
@ -423,7 +426,7 @@ mod tests {
#[test] #[test]
fn test_linking_links() { fn test_linking_links() {
setup_logging(); setup_logging();
let rt = generate_test_runtime(vec!["test1", "test2"]) let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
.unwrap(); .unwrap();
debug!("Runtime created"); debug!("Runtime created");
@ -452,7 +455,7 @@ mod tests {
#[test] #[test]
fn test_multilinking() { fn test_multilinking() {
setup_logging(); setup_logging();
let rt = generate_test_runtime(vec!["test1", "test2"]) let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
.unwrap(); .unwrap();
debug!("Runtime created"); debug!("Runtime created");
@ -482,7 +485,7 @@ mod tests {
#[test] #[test]
fn test_linking_more_than_two() { fn test_linking_more_than_two() {
setup_logging(); setup_logging();
let rt = generate_test_runtime(vec!["test1", "test2", "test3"]) let rt = generate_test_runtime(vec!["internal", "test1", "test2", "test3"])
.unwrap(); .unwrap();
debug!("Runtime created"); debug!("Runtime created");
@ -519,7 +522,7 @@ mod tests {
#[test] #[test]
fn test_linking_links_unlinking_removes_links() { fn test_linking_links_unlinking_removes_links() {
setup_logging(); setup_logging();
let rt = generate_test_runtime(vec!["test1", "test2"]) let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
.unwrap(); .unwrap();
debug!("Runtime created"); debug!("Runtime created");
@ -555,7 +558,7 @@ mod tests {
#[test] #[test]
fn test_linking_and_unlinking_more_than_two() { fn test_linking_and_unlinking_more_than_two() {
setup_logging(); setup_logging();
let rt = generate_test_runtime(vec!["test1", "test2", "test3"]) let rt = generate_test_runtime(vec!["internal", "test1", "test2", "test3"])
.unwrap(); .unwrap();
debug!("Runtime created"); debug!("Runtime created");

View file

@ -53,7 +53,6 @@ use libimagerror::iter::TraceIterator;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagstore::error::StoreError;
use libimagentrylink::internal::InternalLinker; use libimagentrylink::internal::InternalLinker;
use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagstore::iter::get::StoreIdGetIteratorExtension;
@ -93,7 +92,7 @@ fn main() {
}) })
.get_internal_links() .get_internal_links()
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.map(|link| Ok(link.get_store_id().clone()) as Result<_, StoreError>) .map(|link| Ok(link.get_store_id().clone()) as Result<_, _>)
.into_get_iter(rt.store()) .into_get_iter(rt.store())
.trace_unwrap_exit(1) .trace_unwrap_exit(1)
.map(|e| { .map(|e| {

View file

@ -24,7 +24,7 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
error-chain = "0.12" failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore", features = ["verify"] } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore", features = ["verify"] }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -20,12 +20,13 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::io::stdin; use std::io::stdin;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::result::Result as RResult;
use std::io::Read; use std::io::Read;
use std::ops::DerefMut; use std::ops::DerefMut;
use clap::ArgMatches; use clap::ArgMatches;
use toml::Value; use toml::Value;
use failure::Fallible as Result;
use failure::err_msg;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagstore::store::Entry; use libimagstore::store::Entry;
@ -33,13 +34,8 @@ use libimagstore::storeid::StoreId;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagutil::debug_result::*; use libimagutil::debug_result::*;
use error::StoreError;
use error::StoreErrorKind;
use error::ResultExt;
use util::build_toml_header; use util::build_toml_header;
type Result<T> = RResult<T, StoreError>;
pub fn create(rt: &Runtime) { pub fn create(rt: &Runtime) {
let scmd = rt.cli().subcommand_matches("create").unwrap(); let scmd = rt.cli().subcommand_matches("create").unwrap();
debug!("Found 'create' subcommand..."); debug!("Found 'create' subcommand...");
@ -95,13 +91,9 @@ fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> R
fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> { fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
let content = matches let content = matches
.value_of("from-raw") .value_of("from-raw")
.ok_or(StoreError::from_kind(StoreErrorKind::NoCommandlineCall)) .ok_or_else(|| err_msg("No Commandline call"))
.map(string_from_raw_src); .map(string_from_raw_src)?;
if content.is_err() {
return content.map(|_| ());
}
let content = content.unwrap();
debug!("Content with len = {}", content.len()); debug!("Content with len = {}", content.len());
Entry::from_str(path.clone(), &content[..]) Entry::from_str(path.clone(), &content[..])
@ -118,7 +110,6 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Res
r r
}) })
.map_dbg_err(|e| format!("Error storing entry: {:?}", e)) .map_dbg_err(|e| format!("Error storing entry: {:?}", e))
.chain_err(|| StoreErrorKind::BackendError)
} }
fn create_with_content_and_header(rt: &Runtime, fn create_with_content_and_header(rt: &Runtime,
@ -142,7 +133,6 @@ fn create_with_content_and_header(rt: &Runtime,
debug!("New header set"); debug!("New header set");
} }
}) })
.chain_err(|| StoreErrorKind::BackendError)
} }
fn string_from_raw_src(raw_src: &str) -> String { fn string_from_raw_src(raw_src: &str) -> String {

View file

@ -1,38 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
error_chain! {
types {
StoreError, StoreErrorKind, ResultExt, Result;
}
errors {
BackendError {
description("Backend Error")
display("Backend Error")
}
NoCommandlineCall {
description("No commandline call")
display("No commandline call")
}
}
}

View file

@ -36,7 +36,7 @@ extern crate clap;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate toml; extern crate toml;
#[cfg(test)] extern crate toml_query; #[cfg(test)] extern crate toml_query;
#[macro_use] extern crate error_chain; extern crate failure;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
extern crate libimagstore; extern crate libimagstore;
@ -54,7 +54,6 @@ use libimagerror::trace::MapErrTrace;
mod create; mod create;
mod delete; mod delete;
mod error;
mod get; mod get;
mod retrieve; mod retrieve;
mod ui; mod ui;

View file

@ -37,8 +37,9 @@ default-features = false
features = ["color", "suggestions", "wrap_help"] features = ["color", "suggestions", "wrap_help"]
[dev-dependencies] [dev-dependencies]
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
env_logger = "0.5" env_logger = "0.5"
failure = "0.1"
[dev-dependencies.libimagutil] [dev-dependencies.libimagutil]
version = "0.9.0" version = "0.9.0"

View file

@ -36,6 +36,7 @@ extern crate clap;
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[cfg(test)] extern crate toml; #[cfg(test)] extern crate toml;
#[cfg(test)] extern crate failure;
extern crate libimagstore; extern crate libimagstore;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
@ -80,7 +81,7 @@ fn main() {
let version = make_imag_version!(); let version = make_imag_version!();
let rt = generate_runtime_setup("imag-tag", let rt = generate_runtime_setup("imag-tag",
&version, &version,
"Add and remove tags for entries", "Direct interface to the store. Use with great care!",
build_ui); build_ui);
let ids : Vec<PathBuf> = rt let ids : Vec<PathBuf> = rt
@ -269,11 +270,12 @@ mod tests {
use toml::value::Value; use toml::value::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use toml_query::error::Result as TomlQueryResult; use failure::Fallible as Result;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::store::{Result as StoreResult, FileLockEntry, Entry}; use libimagstore::store::{FileLockEntry, Entry};
use super::*; use super::*;
@ -285,7 +287,7 @@ mod tests {
} }
use self::mock::generate_test_runtime; use self::mock::generate_test_runtime;
fn create_test_default_entry<'a, S: AsRef<OsStr>>(rt: &'a Runtime, name: S) -> StoreResult<StoreId> { fn create_test_default_entry<'a, S: AsRef<OsStr>>(rt: &'a Runtime, name: S) -> Result<StoreId> {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
path.set_file_name(name); path.set_file_name(name);
@ -300,8 +302,8 @@ mod tests {
Ok(id) Ok(id)
} }
fn get_entry_tags<'a>(entry: &'a FileLockEntry<'a>) -> TomlQueryResult<Option<&'a Value>> { fn get_entry_tags<'a>(entry: &'a FileLockEntry<'a>) -> Result<Option<&'a Value>> {
entry.get_header().read(&"tag.values".to_owned()) entry.get_header().read(&"tag.values".to_owned()).map_err(Error::from)
} }
fn tags_toml_value<'a, I: IntoIterator<Item = &'static str>>(tags: I) -> Value { fn tags_toml_value<'a, I: IntoIterator<Item = &'static str>>(tags: I) -> Value {

View file

@ -24,9 +24,10 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
handlebars = "1.0" handlebars = "1.0"
tempfile = "3" tempfile = "3"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -38,6 +38,7 @@ extern crate handlebars;
extern crate tempfile; extern crate tempfile;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate failure;
extern crate libimagentryview; extern crate libimagentryview;
extern crate libimagerror; extern crate libimagerror;
@ -55,10 +56,11 @@ use std::process::exit;
use handlebars::Handlebars; use handlebars::Handlebars;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use failure::Error;
use failure::err_msg;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::str::ErrFromStr;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
@ -66,10 +68,8 @@ use libimagerror::exit::ExitUnwrap;
use libimagentryview::builtin::stdout::StdoutViewer; use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::builtin::md::MarkdownViewer; use libimagentryview::builtin::md::MarkdownViewer;
use libimagentryview::viewer::Viewer; use libimagentryview::viewer::Viewer;
use libimagentryview::error::ViewError as VE;
use libimagstore::storeid::IntoStoreId; use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagstore::error::StoreError;
use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagstore::iter::get::StoreIdGetIteratorExtension;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
@ -92,8 +92,7 @@ fn main() {
.into_get_iter(rt.store()) .into_get_iter(rt.store())
.trace_unwrap_exit(1) .trace_unwrap_exit(1)
.map(|e| { .map(|e| {
e.ok_or_else(|| String::from("Entry not found")) e.ok_or_else(|| err_msg("Entry not found"))
.map_err(StoreError::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}) })
.map(|entry| create_tempfile_for(&entry, view_header, hide_content)) .map(|entry| create_tempfile_for(&entry, view_header, hide_content))
@ -103,18 +102,19 @@ fn main() {
let viewer = rt let viewer = rt
.cli() .cli()
.value_of("in") .value_of("in")
.ok_or_else::<VE, _>(|| "No viewer given".to_owned().into()) .ok_or_else(|| Error::from(err_msg("No viewer given")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let config = rt let config = rt
.config() .config()
.ok_or_else::<VE, _>(|| "No configuration, cannot continue".to_owned().into()) .ok_or_else(|| Error::from(err_msg("No configuration, cannot continue")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let query = format!("view.viewers.{}", viewer); let query = format!("view.viewers.{}", viewer);
let viewer_template = config let viewer_template = config
.read_string(&query) .read_string(&query)
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.unwrap_or_else(|| { .unwrap_or_else(|| {
error!("Cannot find '{}' in config", query); error!("Cannot find '{}' in config", query);
@ -126,8 +126,7 @@ fn main() {
let _ = handlebars let _ = handlebars
.register_template_string("template", viewer_template) .register_template_string("template", viewer_template)
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let mut data = BTreeMap::new(); let mut data = BTreeMap::new();
@ -142,13 +141,12 @@ fn main() {
let call = handlebars let call = handlebars
.render("template", &data) .render("template", &data)
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let mut elems = call.split_whitespace(); let mut elems = call.split_whitespace();
let command_string = elems let command_string = elems
.next() .next()
.ok_or::<VE>("No command".to_owned().into()) .ok_or_else(|| Error::from(err_msg("No command")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let mut cmd = Command::new(command_string); let mut cmd = Command::new(command_string);
@ -163,8 +161,7 @@ fn main() {
if !command if !command
.status() .status()
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.success() .success()
{ {
@ -177,8 +174,7 @@ fn main() {
.into_get_iter(rt.store()) .into_get_iter(rt.store())
.map(|e| { .map(|e| {
e.map_err_trace_exit_unwrap(1) e.map_err_trace_exit_unwrap(1)
.ok_or_else(|| String::from("Entry not found")) .ok_or_else(|| err_msg("Entry not found"))
.map_err(StoreError::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}); });
@ -282,25 +278,21 @@ fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_co
-> (tempfile::NamedTempFile, String) -> (tempfile::NamedTempFile, String)
{ {
let mut tmpfile = tempfile::NamedTempFile::new() let mut tmpfile = tempfile::NamedTempFile::new()
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
if view_header { if view_header {
let hdr = toml::ser::to_string_pretty(entry.get_header()) let hdr = toml::ser::to_string_pretty(entry.get_header())
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes()) let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes())
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
} }
if !hide_content { if !hide_content {
let _ = tmpfile.write(entry.get_content().as_bytes()) let _ = tmpfile.write(entry.get_content().as_bytes())
.err_from_str() .map_err(Error::from)
.map_err(VE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
} }
@ -308,7 +300,7 @@ fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_co
.path() .path()
.to_str() .to_str()
.map(String::from) .map(String::from)
.ok_or::<VE>("Cannot build path".to_owned().into()) .ok_or_else(|| Error::from(err_msg("Cannot build path")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
(tmpfile, file_path) (tmpfile, file_path)

View file

@ -32,7 +32,6 @@ walkdir = "2"
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = "0.7"
is-match = "0.1"
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -37,7 +37,6 @@ extern crate clap;
extern crate walkdir; extern crate walkdir;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
#[macro_use] extern crate is_match;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
extern crate libimagerror; extern crate libimagerror;
@ -56,7 +55,6 @@ use clap::{Arg, ArgMatches, AppSettings, SubCommand};
use toml::Value; use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use libimagrt::error::RuntimeErrorKind;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::spec::CliSpec; use libimagrt::spec::CliSpec;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
@ -91,7 +89,7 @@ fn help_text(cmds: Vec<String>) -> String {
Call a command with 'imag <command> <args>' Call a command with 'imag <command> <args>'
Each command can be called with "--help" to get the respective helptext. Each command can be called with "--help" to get the respective helptext.
Please visit https://git.imag-pim.org/imag to view the source code, Please visit https://github.com/matthiasbeyer/imag to view the source code,
follow the development of imag or maybe even contribute to imag. follow the development of imag or maybe even contribute to imag.
imag is free software. It is released under the terms of LGPLv2.1 imag is free software. It is released under the terms of LGPLv2.1
@ -190,17 +188,11 @@ fn main() {
.value_of(Runtime::arg_config_name()) .value_of(Runtime::arg_config_name())
.map_or_else(|| rtp.clone(), PathBuf::from); .map_or_else(|| rtp.clone(), PathBuf::from);
debug!("Config path = {:?}", configpath); debug!("Config path = {:?}", configpath);
let config = match ::libimagrt::configuration::fetch_config(&configpath) { let config = ::libimagrt::configuration::fetch_config(&configpath)
Ok(c) => Some(c), .unwrap_or_else(|e| {
Err(e) => if !is_match!(e.kind(), &RuntimeErrorKind::ConfigNoConfigFileFound) {
trace_error(&e); trace_error(&e);
::std::process::exit(1) exit(1)
} else { });
println!("No config file found.");
println!("Continuing without configuration file");
None
},
};
debug!("matches: {:?}", matches); debug!("matches: {:?}", matches);

View file

@ -24,7 +24,8 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
failure = "0.1"
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -36,6 +36,7 @@ extern crate clap;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
#[macro_use] extern crate failure;
extern crate libimagbookmark; extern crate libimagbookmark;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
@ -46,12 +47,12 @@ use std::io::Write;
use std::process::exit; use std::process::exit;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagbookmark::collection::BookmarkCollection; use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::collection::BookmarkCollectionStore; use libimagbookmark::collection::BookmarkCollectionStore;
use libimagbookmark::error::BookmarkError as BE;
use libimagbookmark::link::Link as BookmarkLink; use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::trace::{MapErrTrace, trace_error};
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
@ -94,7 +95,7 @@ fn add(rt: &Runtime) {
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll) let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(BE::from(format!("No bookmark collection '{}' found", coll))) .ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
for url in scmd.values_of("urls").unwrap() { // unwrap saved by clap for url in scmd.values_of("urls").unwrap() { // unwrap saved by clap
@ -135,7 +136,7 @@ fn list(rt: &Runtime) {
let collection = BookmarkCollectionStore::get(rt.store(), &coll) let collection = BookmarkCollectionStore::get(rt.store(), &coll)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(BE::from(format!("No bookmark collection '{}' found", coll))) .ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1); let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1);
@ -157,7 +158,7 @@ fn remove(rt: &Runtime) {
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll) let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(BE::from(format!("No bookmark collection '{}' found", coll))) .ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
for url in scmd.values_of("urls").unwrap() { // enforced by clap for url in scmd.values_of("urls").unwrap() { // enforced by clap
@ -182,6 +183,7 @@ fn get_collection_name(rt: &Runtime,
rt.config() rt.config()
.map(|cfg| { .map(|cfg| {
cfg.read_string("bookmark.default_collection") cfg.read_string("bookmark.default_collection")
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or_else(|| { .ok_or_else(|| {
error!("Missing config: 'bookmark.default_collection'. Set or use commandline to specify."); error!("Missing config: 'bookmark.default_collection'. Set or use commandline to specify.");

View file

@ -24,12 +24,13 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "update-errorchain" } vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "master" }
handlebars = "1.0" handlebars = "1.0"
walkdir = "2" walkdir = "2"
uuid = { version = "0.7", features = ["v4"] } uuid = { version = "0.7", features = ["v4"] }
serde_json = "1" serde_json = "1"
failure = "0.1"
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }

View file

@ -44,11 +44,10 @@ use vobject::write_component;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use toml::Value; use toml::Value;
use uuid::Uuid; use uuid::Uuid;
use failure::Error;
use libimagcontact::store::ContactStore; use libimagcontact::store::ContactStore;
use libimagcontact::error::ContactError as CE;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::str::ErrFromStr;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagutil::warn_result::WarnResult; use libimagutil::warn_result::WarnResult;
@ -126,8 +125,7 @@ pub fn create(rt: &Runtime) {
.create_new(true) .create_new(true)
.open(fl.clone()) .open(fl.clone())
.map_warn_err_str("Cannot create/open destination File. Stopping.") .map_warn_err_str("Cannot create/open destination File. Stopping.")
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let uuid_string = uuid let uuid_string = uuid
@ -161,8 +159,7 @@ pub fn create(rt: &Runtime) {
match ::toml::de::from_str(&template) match ::toml::de::from_str(&template)
.map(|toml| parse_toml_into_vcard(toml, uuid.clone())) .map(|toml| parse_toml_into_vcard(toml, uuid.clone()))
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
{ {
Err(e) => { Err(e) => {
error!("Error parsing template"); error!("Error parsing template");
@ -183,7 +180,7 @@ pub fn create(rt: &Runtime) {
let vcard_string = write_component(&vcard); let vcard_string = write_component(&vcard);
let _ = dest let _ = dest
.write_all(&vcard_string.as_bytes()) .write_all(&vcard_string.as_bytes())
.map_err(CE::from) .map_err(Error::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
break; break;
@ -244,7 +241,7 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
{ // parse nicknames { // parse nicknames
debug!("Parsing nicknames"); debug!("Parsing nicknames");
match toml.read("nickname").map_err_trace_exit_unwrap(1) { match toml.read("nickname").map_err(Error::from).map_err_trace_exit_unwrap(1) {
Some(&Value::Array(ref ary)) => { Some(&Value::Array(ref ary)) => {
for (i, element) in ary.iter().enumerate() { for (i, element) in ary.iter().enumerate() {
let nicktype = match read_str_from_toml(element, "type", false) { let nicktype = match read_str_from_toml(element, "type", false) {
@ -306,7 +303,7 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
{ // parse phone { // parse phone
debug!("Parse phone"); debug!("Parse phone");
match toml.read("person.phone").map_err_trace_exit_unwrap(1) { match toml.read("person.phone").map_err(Error::from).map_err_trace_exit_unwrap(1) {
Some(&Value::Array(ref ary)) => { Some(&Value::Array(ref ary)) => {
for (i, element) in ary.iter().enumerate() { for (i, element) in ary.iter().enumerate() {
let phonetype = match read_str_from_toml(element, "type", false) { let phonetype = match read_str_from_toml(element, "type", false) {
@ -344,7 +341,7 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
{ // parse address { // parse address
debug!("Parsing address"); debug!("Parsing address");
match toml.read("addresses").map_err_trace_exit_unwrap(1) { match toml.read("addresses").map_err(Error::from).map_err_trace_exit_unwrap(1) {
Some(&Value::Array(ref ary)) => { Some(&Value::Array(ref ary)) => {
for (i, element) in ary.iter().enumerate() { for (i, element) in ary.iter().enumerate() {
let adrtype = match read_str_from_toml(element, "type", false) { let adrtype = match read_str_from_toml(element, "type", false) {
@ -391,7 +388,7 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
{ // parse email { // parse email
debug!("Parsing email"); debug!("Parsing email");
match toml.read("person.email").map_err_trace_exit_unwrap(1) { match toml.read("person.email").map_err(Error::from).map_err_trace_exit_unwrap(1) {
Some(&Value::Array(ref ary)) => { Some(&Value::Array(ref ary)) => {
for (i, element) in ary.iter().enumerate() { for (i, element) in ary.iter().enumerate() {
let mailtype = match read_str_from_toml(element, "type", false) { let mailtype = match read_str_from_toml(element, "type", false) {
@ -456,7 +453,7 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
} }
fn read_strary_from_toml(toml: &Value, path: &'static str) -> Option<Vec<String>> { fn read_strary_from_toml(toml: &Value, path: &'static str) -> Option<Vec<String>> {
match toml.read(path).map_warn_err_str(&format!("Failed to read value at '{}'", path)) { match toml.read(path).map_err(Error::from).map_warn_err_str(&format!("Failed to read value at '{}'", path)) {
Ok(Some(&Value::Array(ref vec))) => { Ok(Some(&Value::Array(ref vec))) => {
let mut v = Vec::new(); let mut v = Vec::new();
for elem in vec { for elem in vec {
@ -486,6 +483,7 @@ fn read_strary_from_toml(toml: &Value, path: &'static str) -> Option<Vec<String>
fn read_str_from_toml(toml: &Value, path: &'static str, must_be_there: bool) -> Option<String> { fn read_str_from_toml(toml: &Value, path: &'static str, must_be_there: bool) -> Option<String> {
let v = toml.read(path) let v = toml.read(path)
.map_err(Error::from)
.map_warn_err_str(&format!("Failed to read value at '{}'", path)); .map_warn_err_str(&format!("Failed to read value at '{}'", path));
match v { match v {

View file

@ -41,6 +41,7 @@ extern crate handlebars;
extern crate walkdir; extern crate walkdir;
extern crate uuid; extern crate uuid;
extern crate serde_json; extern crate serde_json;
extern crate failure;
extern crate libimagcontact; extern crate libimagcontact;
extern crate libimagstore; extern crate libimagstore;
@ -58,16 +59,16 @@ use handlebars::Handlebars;
use clap::ArgMatches; use clap::ArgMatches;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use walkdir::WalkDir; use walkdir::WalkDir;
use failure::Error;
use failure::err_msg;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagerror::str::ErrFromStr;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
use libimagerror::exit::ExitUnwrap; use libimagerror::exit::ExitUnwrap;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagcontact::store::ContactStore; use libimagcontact::store::ContactStore;
use libimagcontact::error::ContactError as CE;
use libimagcontact::contact::Contact; use libimagcontact::contact::Contact;
use libimagcontact::deser::DeserVcard; use libimagcontact::deser::DeserVcard;
use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagstore::iter::get::StoreIdGetIteratorExtension;
@ -121,7 +122,7 @@ fn list(rt: &Runtime) {
.map(|fle| { .map(|fle| {
let fle = fle let fle = fle
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or_else(|| CE::from("StoreId not found".to_owned())) .ok_or_else(|| Error::from(err_msg("StoreId not found".to_owned())))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
fle.deser().map_err_trace_exit_unwrap(1) fle.deser().map_err_trace_exit_unwrap(1)
@ -144,8 +145,7 @@ fn list(rt: &Runtime) {
let data = build_data_object_for_handlebars(i, &deservcard); let data = build_data_object_for_handlebars(i, &deservcard);
list_format.render("format", &data) list_format.render("format", &data)
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}) })
@ -175,8 +175,7 @@ fn import(rt: &Runtime) {
} else if path.is_dir() { } else if path.is_dir() {
for entry in WalkDir::new(path).min_depth(1).into_iter() { for entry in WalkDir::new(path).min_depth(1).into_iter() {
let entry = entry let entry = entry
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
if entry.file_type().is_file() { if entry.file_type().is_file() {
let pb = PathBuf::from(entry.path()); let pb = PathBuf::from(entry.path());
@ -233,8 +232,7 @@ fn show(rt: &Runtime) {
let s = show_format let s = show_format
.render("format", &data) .render("format", &data)
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let _ = writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit(); let _ = writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit();
}); });
@ -324,8 +322,7 @@ fn find(rt: &Runtime) {
let data = build_data_object_for_handlebars(i, &card); let data = build_data_object_for_handlebars(i, &card);
let s = fmt let s = fmt
.render("format", &data) .render("format", &data)
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let _ = writeln!(rt.stdout(), "{}", s) let _ = writeln!(rt.stdout(), "{}", s)
@ -341,19 +338,19 @@ fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd:
.map(String::from) .map(String::from)
.unwrap_or_else(|| { .unwrap_or_else(|| {
rt.config() rt.config()
.ok_or_else(|| CE::from("No configuration file".to_owned())) .ok_or_else(|| Error::from(err_msg("No configuration file")))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.read_string(config_value_path) .read_string(config_value_path)
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or_else(|| CE::from("Configuration 'contact.list_format' does not exist".to_owned())) .ok_or_else(|| Error::from(err_msg("Configuration 'contact.list_format' does not exist")))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}); });
let mut hb = Handlebars::new(); let mut hb = Handlebars::new();
let _ = hb let _ = hb
.register_template_string("format", fmt) .register_template_string("format", fmt)
.err_from_str() .map_err(Error::from)
.map_err(CE::from)
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
hb.register_escape_fn(::handlebars::no_escape); hb.register_escape_fn(::handlebars::no_escape);

View file

@ -25,8 +25,9 @@ maintenance = { status = "actively-developed" }
chrono = "0.4" chrono = "0.4"
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
itertools = "0.7" itertools = "0.7"
failure = "0.1"
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }

View file

@ -21,10 +21,11 @@ use clap::ArgMatches;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use chrono::Local; use chrono::Local;
use chrono::Timelike; use chrono::Timelike;
use failure::Error;
use failure::ResultExt;
use failure::err_msg;
use libimagdiary::diary::Diary; use libimagdiary::diary::Diary;
use libimagdiary::error::DiaryErrorKind as DEK;
use libimagdiary::error::ResultExt;
use libimagentryedit::edit::Edit; use libimagentryedit::edit::Edit;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
@ -47,8 +48,7 @@ pub fn create(rt: &Runtime) {
Ok(()) Ok(())
} else { } else {
debug!("Editing new diary entry"); debug!("Editing new diary entry");
entry.edit_content(rt) entry.edit_content(rt).context(err_msg("Diary edit error")).map_err(Error::from)
.chain_err(|| DEK::DiaryEditError)
}; };
let _ = res.map_err_trace_exit_unwrap(1); let _ = res.map_err_trace_exit_unwrap(1);
@ -75,7 +75,9 @@ fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLock
}) })
.map(|timed| { .map(|timed| {
let time = create_id_from_clispec(&create, &diaryname, timed); let time = create_id_from_clispec(&create, &diaryname, timed);
diary.new_entry_at(&diaryname, &time).chain_err(|| DEK::StoreWriteError) diary.new_entry_at(&diaryname, &time)
.context(err_msg("Store write error"))
.map_err(Error::from)
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
debug!("Creating non-timed entry"); debug!("Creating non-timed entry");

View file

@ -29,9 +29,10 @@ use libimagerror::exit::ExitUnwrap;
use libimagutil::debug_result::*; use libimagutil::debug_result::*;
use libimagdiary::diaryid::DiaryId; use libimagdiary::diaryid::DiaryId;
use libimagdiary::diaryid::FromStoreId; use libimagdiary::diaryid::FromStoreId;
use libimagdiary::error::Result;
use libimagstore::storeid::IntoStoreId; use libimagstore::storeid::IntoStoreId;
use failure::Fallible as Result;
use util::get_diary_name; use util::get_diary_name;
pub fn list(rt: &Runtime) { pub fn list(rt: &Runtime) {

View file

@ -33,6 +33,7 @@
)] )]
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate failure;
extern crate clap; extern crate clap;
extern crate chrono; extern crate chrono;
extern crate toml; extern crate toml;

View file

@ -18,10 +18,13 @@
// //
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagdiary::error::*; use libimagerror::errors::ErrorMsg as EM;
use toml::Value; use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use failure::Error;
use failure::Fallible as Result;
use failure::ResultExt;
pub fn get_diary_name(rt: &Runtime) -> Option<String> { pub fn get_diary_name(rt: &Runtime) -> Option<String> {
use libimagdiary::config::get_default_diary_name; use libimagdiary::config::get_default_diary_name;
@ -58,14 +61,15 @@ pub fn get_diary_timed_config(rt: &Runtime, diary_name: &str) -> Result<Option<T
Some(cfg) => { Some(cfg) => {
let v = cfg let v = cfg
.read(&format!("diary.diaries.{}.timed", diary_name)) .read(&format!("diary.diaries.{}.timed", diary_name))
.chain_err(|| DiaryErrorKind::IOError); .context(EM::IO)
.map_err(Error::from);
match v { match v {
Ok(Some(&Value::String(ref s))) => parse_timed_string(s, diary_name).map(Some), Ok(Some(&Value::String(ref s))) => parse_timed_string(s, diary_name).map(Some),
Ok(Some(_)) => { Ok(Some(_)) => {
let s = format!("Type error at 'diary.diaryies.{}.timed': should be either 'd'/'daily', 'h'/'hourly', 'm'/'minutely' or 's'/'secondly'", diary_name); let s = format!("Type error at 'diary.diaryies.{}.timed': should be either 'd'/'daily', 'h'/'hourly', 'm'/'minutely' or 's'/'secondly'", diary_name);
Err(s).map_err(From::from) Err(format_err!("{}", s))
}, },
Ok(None) => Ok(None), Ok(None) => Ok(None),
@ -87,6 +91,6 @@ pub fn parse_timed_string(s: &str, diary_name: &str) -> Result<Timed> {
} else { } else {
let s = format!("Cannot parse config: 'diary.diaries.{}.timed = {}'", let s = format!("Cannot parse config: 'diary.diaries.{}.timed = {}'",
diary_name, s); diary_name, s);
Err(s).map_err(From::from) Err(format_err!("{}", s))
} }
} }

View file

@ -25,9 +25,10 @@ maintenance = { status = "actively-developed" }
chrono = "0.4" chrono = "0.4"
log = "0.4" log = "0.4"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "master" } kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "failure" }
prettytable-rs = "0.8" prettytable-rs = "0.8"
failure = "0.1"
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }

View file

@ -39,6 +39,7 @@ extern crate toml_query;
extern crate kairos; extern crate kairos;
extern crate chrono; extern crate chrono;
extern crate prettytable; extern crate prettytable;
#[macro_use] extern crate failure;
extern crate libimaghabit; extern crate libimaghabit;
extern crate libimagstore; extern crate libimagstore;
@ -53,6 +54,7 @@ use std::process::exit;
use prettytable::Table; use prettytable::Table;
use prettytable::Cell; use prettytable::Cell;
use prettytable::Row; use prettytable::Row;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
@ -232,8 +234,7 @@ fn delete(rt: &Runtime) {
// future flag. If it is true, the check will not be performed and it is assumed that `--future` // future flag. If it is true, the check will not be performed and it is assumed that `--future`
// was passed. // was passed.
fn today(rt: &Runtime, future: bool) { fn today(rt: &Runtime, future: bool) {
use libimaghabit::error::ResultExt; use failure::ResultExt;
use libimaghabit::error::HabitErrorKind as HEK;
let (future, show_done) = { let (future, show_done) = {
if !future { if !future {
@ -296,7 +297,8 @@ fn today(rt: &Runtime, future: bool) {
am.value_of("today-show-next-n") am.value_of("today-show-next-n")
.map(|x| { .map(|x| {
x.parse::<usize>() x.parse::<usize>()
.chain_err(|| HEK::from(format!("Cannot parse String '{}' to integer", x))) .context(format_err!("Cannot parse String '{}' to integer", x))
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
}) })
}).unwrap_or(5); }).unwrap_or(5);

View file

@ -24,9 +24,10 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4" log = "0.4"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
is-match = "0.1" is-match = "0.1"
itertools = "0.7" itertools = "0.7"
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -38,6 +38,7 @@ extern crate clap;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate itertools; extern crate itertools;
extern crate failure;
extern crate libimaglog; extern crate libimaglog;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
@ -47,6 +48,9 @@ extern crate libimagdiary;
use std::io::Write; use std::io::Write;
use failure::Error;
use failure::err_msg;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
@ -55,7 +59,6 @@ use libimagerror::exit::ExitUnwrap;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagdiary::diary::Diary; use libimagdiary::diary::Diary;
use libimaglog::log::Log; use libimaglog::log::Log;
use libimaglog::error::LogError as LE;
use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagstore::iter::get::StoreIdGetIteratorExtension;
mod ui; mod ui;
@ -175,16 +178,17 @@ fn get_diary_name(rt: &Runtime) -> String {
let cfg = rt let cfg = rt
.config() .config()
.ok_or(LE::from("Configuration not present, cannot continue")) .ok_or_else(|| Error::from(err_msg("Configuration not present, cannot continue")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
let logs = cfg let logs = cfg
.read("log.logs") .read("log.logs")
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(LE::from("Configuration missing: 'log.logs'")) .ok_or_else(|| Error::from(err_msg("Configuration missing: 'log.logs'")))
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.as_array() .as_array()
.ok_or(LE::from("Configuration 'log.logs' is not an Array")) .ok_or_else(|| Error::from(err_msg("Configuration 'log.logs' is not an Array")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
if !logs.iter().all(|e| is_match!(e, &Value::String(_))) { if !logs.iter().all(|e| is_match!(e, &Value::String(_))) {
@ -201,8 +205,9 @@ fn get_diary_name(rt: &Runtime) -> String {
let current_log = cfg let current_log = cfg
.read_string("log.default") .read_string("log.default")
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.ok_or(LE::from("Configuration missing: 'log.default'")) .ok_or_else(|| Error::from(err_msg("Configuration missing: 'log.default'")))
.map_err_trace_exit_unwrap(1); .map_err_trace_exit_unwrap(1);
if !logs.contains(&current_log) { if !logs.contains(&current_log) {

View file

@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
failure = "0.1"
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -34,6 +34,7 @@
extern crate clap; extern crate clap;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate failure;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
extern crate libimagmail; extern crate libimagmail;
@ -42,6 +43,9 @@ extern crate libimagutil;
use std::io::Write; use std::io::Write;
use failure::Error;
use failure::err_msg;
use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::trace::{MapErrTrace, trace_error};
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagerror::exit::ExitUnwrap; use libimagerror::exit::ExitUnwrap;
@ -91,8 +95,7 @@ fn import_mail(rt: &Runtime) {
} }
fn list(rt: &Runtime) { fn list(rt: &Runtime) {
use libimagmail::error::MailErrorKind as MEK; use failure::ResultExt;
use libimagmail::error::ResultExt;
// TODO: Implement lister type in libimagmail for this // TODO: Implement lister type in libimagmail for this
fn list_mail(rt: &Runtime, m: Mail) { fn list_mail(rt: &Runtime, m: Mail) {
@ -149,7 +152,8 @@ fn list(rt: &Runtime) {
.filter_map(|id| { .filter_map(|id| {
rt.store() rt.store()
.get(id) .get(id)
.chain_err(|| MEK::RefHandlingError) .context(err_msg("Ref handling error"))
.map_err(Error::from)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.map(|fle| Mail::from_fle(fle).map_err_trace().ok()) .map(|fle| Mail::from_fle(fle).map_err_trace().ok())
}) })

View file

@ -27,7 +27,8 @@ chrono = "0.4"
filters = "0.3" filters = "0.3"
itertools = "0.7" itertools = "0.7"
prettytable-rs = "0.8" prettytable-rs = "0.8"
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "master" } kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "failure" }
failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }

View file

@ -22,13 +22,13 @@ use std::str::FromStr;
use filters::filter::Filter; use filters::filter::Filter;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use failure::Error;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
@ -44,7 +44,7 @@ pub fn day(rt: &Runtime) -> i32 {
let filter = { let filter = {
let start = match cmd.value_of("start").map(NaiveDateTime::from_str) { let start = match cmd.value_of("start").map(NaiveDateTime::from_str) {
None => ::chrono::offset::Local::today().and_hms(0, 0, 0).naive_local(), None => ::chrono::offset::Local::today().and_hms(0, 0, 0).naive_local(),
Some(s) => match s.map_err(TTE::from) { Some(s) => match s.map_err(Error::from) {
Ok(dt) => dt, Ok(dt) => dt,
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);
@ -55,7 +55,7 @@ pub fn day(rt: &Runtime) -> i32 {
let end = match cmd.value_of("end").map(NaiveDateTime::from_str) { let end = match cmd.value_of("end").map(NaiveDateTime::from_str) {
None => ::chrono::offset::Local::today().and_hms(23, 59, 59).naive_local(), None => ::chrono::offset::Local::today().and_hms(23, 59, 59).naive_local(),
Some(s) => match s.map_err(TTE::from) { Some(s) => match s.map_err(Error::from) {
Ok(dt) => dt, Ok(dt) => dt,
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);
@ -91,7 +91,7 @@ pub fn day(rt: &Runtime) -> i32 {
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.trace_unwrap() .trace_unwrap()
.filter(|e| filter.filter(e)) .filter(|e| filter.filter(e))
.map(|e| -> Result<_, TTE> { .map(|e| -> Result<_, Error> {
debug!("Processing {:?}", e.get_location()); debug!("Processing {:?}", e.get_location());
let tag = e.get_timetrack_tag()?; let tag = e.get_timetrack_tag()?;

View file

@ -25,15 +25,17 @@ use prettytable::Cell;
use kairos::parser::Parsed; use kairos::parser::Parsed;
use kairos::parser::parse as kairos_parse; use kairos::parser::parse as kairos_parse;
use clap::ArgMatches; use clap::ArgMatches;
use failure::Fallible as Result;
use failure::ResultExt;
use failure::err_msg;
use failure::Error;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagtimetrack::error::TimeTrackError;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::error::Result;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
@ -63,6 +65,7 @@ pub fn list(rt: &Runtime) -> i32 {
::std::process::exit(1) ::std::process::exit(1)
}, },
Some(Err(e)) => { Some(Err(e)) => {
let e = Error::from(e);
trace_error(&e); trace_error(&e);
::std::process::exit(1) ::std::process::exit(1)
} }
@ -164,7 +167,8 @@ pub fn list_impl(rt: &Runtime,
}) })
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.print(&mut rt.stdout()) .print(&mut rt.stdout())
.map_err(|_| TimeTrackError::from(String::from("Failed printing table"))) .context(err_msg("Failed to print table"))
.map_err(Error::from)
.map(|_| 0) .map(|_| 0)
.map_err_trace() .map_err_trace()
.unwrap_or(1) .unwrap_or(1)

View file

@ -41,6 +41,7 @@ extern crate filters;
extern crate itertools; extern crate itertools;
extern crate prettytable; extern crate prettytable;
extern crate kairos; extern crate kairos;
extern crate failure;
extern crate libimagerror; extern crate libimagerror;
extern crate libimagstore; extern crate libimagstore;

View file

@ -22,13 +22,13 @@ use std::str::FromStr;
use filters::filter::Filter; use filters::filter::Filter;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use failure::Error;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
@ -48,7 +48,7 @@ pub fn month(rt: &Runtime) -> i32 {
let start = match cmd.value_of("start").map(::chrono::naive::NaiveDateTime::from_str) { let start = match cmd.value_of("start").map(::chrono::naive::NaiveDateTime::from_str) {
None => NaiveDate::from_ymd(now.year(), now.month(), 1).and_hms(0, 0, 0), None => NaiveDate::from_ymd(now.year(), now.month(), 1).and_hms(0, 0, 0),
Some(s) => match s.map_err(TTE::from) { Some(s) => match s.map_err(Error::from) {
Ok(dt) => dt, Ok(dt) => dt,
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);
@ -70,7 +70,7 @@ pub fn month(rt: &Runtime) -> i32 {
NaiveDate::from_ymd(year, month, 1).and_hms(0, 0, 0) NaiveDate::from_ymd(year, month, 1).and_hms(0, 0, 0)
}, },
Some(s) => match s.map_err(TTE::from) { Some(s) => match s.map_err(Error::from) {
Ok(dt) => dt, Ok(dt) => dt,
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);
@ -106,7 +106,7 @@ pub fn month(rt: &Runtime) -> i32 {
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.trace_unwrap() .trace_unwrap()
.filter(|e| filter.filter(e)) .filter(|e| filter.filter(e))
.map(|e| -> Result<_, TTE> { .map(|e| -> Result<_, Error> {
debug!("Processing {:?}", e.get_location()); debug!("Processing {:?}", e.get_location());
let tag = e.get_timetrack_tag()?; let tag = e.get_timetrack_tag()?;

View file

@ -20,10 +20,10 @@
use std::str::FromStr; use std::str::FromStr;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
@ -34,7 +34,7 @@ pub fn start(rt: &Runtime) -> i32 {
let start = match cmd.value_of("start-time") { let start = match cmd.value_of("start-time") {
None | Some("now") => ::chrono::offset::Local::now().naive_local(), None | Some("now") => ::chrono::offset::Local::now().naive_local(),
Some(ndt) => match NaiveDateTime::from_str(ndt).map_err(TTE::from) { Some(ndt) => match NaiveDateTime::from_str(ndt).map_err(Error::from) {
Ok(ndt) => ndt, Ok(ndt) => ndt,
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);

View file

@ -21,13 +21,13 @@ use std::str::FromStr;
use filters::filter::Filter; use filters::filter::Filter;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use failure::Error;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
use libimagtimetrack::timetrackingstore::*; use libimagtimetrack::timetrackingstore::*;
@ -42,7 +42,7 @@ pub fn stop(rt: &Runtime) -> i32 {
let stop_time = match cmd.value_of("stop-time") { let stop_time = match cmd.value_of("stop-time") {
None | Some("now") => ::chrono::offset::Local::now().naive_local(), None | Some("now") => ::chrono::offset::Local::now().naive_local(),
Some(ndt) => match NaiveDateTime::from_str(ndt).map_err(TTE::from) { Some(ndt) => match NaiveDateTime::from_str(ndt).map_err(Error::from) {
Ok(ndt) => ndt, Ok(ndt) => ndt,
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);

View file

@ -22,10 +22,10 @@ use std::process::exit;
use clap::ArgMatches; use clap::ArgMatches;
use chrono::naive::NaiveDate; use chrono::naive::NaiveDate;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
@ -43,10 +43,10 @@ pub fn track(rt: &Runtime) -> i32 {
match cmd.value_of(clap_name) { match cmd.value_of(clap_name) {
Some("now") => Some(::chrono::offset::Local::now().naive_local()), Some("now") => Some(::chrono::offset::Local::now().naive_local()),
Some(els) => { Some(els) => {
match NaiveDateTime::parse_from_str(els, DATE_TIME_PARSE_FMT).map_err(TTE::from) { match NaiveDateTime::parse_from_str(els, DATE_TIME_PARSE_FMT).map_err(Error::from) {
Ok(ndt) => Some(ndt), Ok(ndt) => Some(ndt),
Err(e_ndt) => { Err(e_ndt) => {
match NaiveDate::parse_from_str(els, DATE_PARSE_FMT).map_err(TTE::from) { match NaiveDate::parse_from_str(els, DATE_PARSE_FMT).map_err(Error::from) {
Ok(ndt) => Some(ndt.and_hms(0, 0, 0)), Ok(ndt) => Some(ndt.and_hms(0, 0, 0)),
Err(e_nd) => { Err(e_nd) => {
error!("Cannot parse date {}:", errname); error!("Cannot parse date {}:", errname);

View file

@ -22,13 +22,13 @@ use std::str::FromStr;
use filters::filter::Filter; use filters::filter::Filter;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use failure::Error;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
@ -50,7 +50,7 @@ pub fn week(rt: &Runtime) -> i32 {
let start = match cmd let start = match cmd
.value_of("start") .value_of("start")
.map(|s| { .map(|s| {
::chrono::naive::NaiveDateTime::from_str(s).map_err(TTE::from) ::chrono::naive::NaiveDateTime::from_str(s).map_err(Error::from)
}) })
{ {
None => NaiveDate::from_isoywd(this_week.year(), this_week.week(), Weekday::Mon) None => NaiveDate::from_isoywd(this_week.year(), this_week.week(), Weekday::Mon)
@ -65,7 +65,7 @@ pub fn week(rt: &Runtime) -> i32 {
let end = match cmd let end = match cmd
.value_of("end") .value_of("end")
.map(|s| { .map(|s| {
::chrono::naive::NaiveDateTime::from_str(s).map_err(TTE::from) ::chrono::naive::NaiveDateTime::from_str(s).map_err(Error::from)
}) })
{ {
None => NaiveDate::from_isoywd(this_week.year(), this_week.week(), Weekday::Sun) None => NaiveDate::from_isoywd(this_week.year(), this_week.week(), Weekday::Sun)
@ -104,7 +104,7 @@ pub fn week(rt: &Runtime) -> i32 {
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.trace_unwrap() .trace_unwrap()
.filter(|e| filter.filter(e)) .filter(|e| filter.filter(e))
.map(|e| -> Result<_, TTE> { .map(|e| -> Result<_, Error> {
debug!("Processing {:?}", e.get_location()); debug!("Processing {:?}", e.get_location());
let tag = e.get_timetrack_tag()?; let tag = e.get_timetrack_tag()?;

View file

@ -22,13 +22,13 @@ use std::str::FromStr;
use filters::filter::Filter; use filters::filter::Filter;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use failure::Error;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace; use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator; use libimagerror::iter::TraceIterator;
use libimagerror::io::ToExitCode; use libimagerror::io::ToExitCode;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagtimetrack::error::TimeTrackError as TTE;
use libimagtimetrack::timetrackingstore::TimeTrackStore; use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
@ -49,7 +49,7 @@ pub fn year(rt: &Runtime) -> i32 {
let start = match cmd let start = match cmd
.value_of("start") .value_of("start")
.map(|s| { .map(|s| {
::chrono::naive::NaiveDateTime::from_str(s).map_err(TTE::from) ::chrono::naive::NaiveDateTime::from_str(s).map_err(Error::from)
}) })
{ {
None => NaiveDate::from_ymd(now.year(), 1, 1).and_hms(0, 0, 0), None => NaiveDate::from_ymd(now.year(), 1, 1).and_hms(0, 0, 0),
@ -63,7 +63,7 @@ pub fn year(rt: &Runtime) -> i32 {
let end = match cmd let end = match cmd
.value_of("end") .value_of("end")
.map(|s| { .map(|s| {
::chrono::naive::NaiveDateTime::from_str(s).map_err(TTE::from) ::chrono::naive::NaiveDateTime::from_str(s).map_err(Error::from)
}) })
{ {
None => { None => {
@ -104,7 +104,7 @@ pub fn year(rt: &Runtime) -> i32 {
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.trace_unwrap() .trace_unwrap()
.filter(|e| filter.filter(e)) .filter(|e| filter.filter(e))
.map(|e| -> Result<_, TTE> { .map(|e| -> Result<_, Error> {
debug!("Processing {:?}", e.get_location()); debug!("Processing {:?}", e.get_location());
let tag = e.get_timetrack_tag()?; let tag = e.get_timetrack_tag()?;

View file

@ -24,8 +24,9 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4.0" log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
is-match = "0.1" is-match = "0.1"
failure = "0.1"
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -37,6 +37,7 @@ extern crate clap;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
#[macro_use] extern crate is_match; #[macro_use] extern crate is_match;
extern crate failure;
#[macro_use] extern crate libimagrt; #[macro_use] extern crate libimagrt;
extern crate libimagerror; extern crate libimagerror;
@ -45,6 +46,7 @@ extern crate libimagtodo;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::io::stdin; use std::io::stdin;
use std::io::Write; use std::io::Write;
use failure::Error;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
@ -119,7 +121,7 @@ fn list(rt: &Runtime) {
// return Result<T> instead of Result<Option<T>>, which is a real inconvenience. // return Result<T> instead of Result<Option<T>>, which is a real inconvenience.
// //
let no_identifier = |e: &::toml_query::error::Error| -> bool { let no_identifier = |e: &::toml_query::error::Error| -> bool {
is_match!(e.kind(), &::toml_query::error::ErrorKind::IdentifierNotFoundInDocument(_)) is_match!(e, &::toml_query::error::Error::IdentifierNotFoundInDocument(_))
}; };
let res = rt.store().all_tasks() // get all tasks let res = rt.store().all_tasks() // get all tasks
@ -136,7 +138,7 @@ fn list(rt: &Runtime) {
}, },
Err(e) => { Err(e) => {
if !no_identifier(&e) { if !no_identifier(&e) {
trace_error(&e); trace_error(&Error::from(e));
} }
None None
} }

View file

@ -48,7 +48,7 @@ fn main() {
let version = make_imag_version!(); let version = make_imag_version!();
let rt = generate_runtime_setup("imag-wiki", let rt = generate_runtime_setup("imag-wiki",
&version, &version,
"Manage a personal Wiki", "Personal wiki",
build_ui); build_ui);
let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default"); let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default");

View file

@ -22,4 +22,5 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
log = "0.4" log = "0.4"
ansi_term = "0.11" ansi_term = "0.11"
error-chain = "0.12" failure = "0.1"
failure_derive = "0.1"

View file

@ -0,0 +1,105 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 the imag contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#[derive(Debug, Clone, Eq, PartialEq, Fail)]
pub enum ErrorMsg {
#[fail(display = "IO Error")]
IO,
#[fail(display = "Locking error")]
LockError,
#[fail(display = "UTF8 error")]
UTF8Error,
#[fail(display = "Error in external process")]
ExternalProcessError,
#[fail(display = "File Error")]
FileError,
#[fail(display = "File not copied")]
FileNotCopied,
#[fail(display = "File not created")]
FileNotCreated,
#[fail(display = "File not found")]
FileNotFound,
#[fail(display = "Fail not removed")]
FileNotRemoved,
#[fail(display = "Fail not renamed")]
FileNotRenamed,
#[fail(display = "File not seeked")]
FileNotSeeked,
#[fail(display = "File not written")]
FileNotWritten,
#[fail(display = "Directory not created")]
DirNotCreated,
#[fail(display = "Formatting error")]
FormatError,
#[fail(display = "ID is locked")]
IdLocked,
#[fail(display = "Error while converting values")]
ConversionError,
#[fail(display = "Entry exists already: {}", _0)]
EntryAlreadyExists(String),
#[fail(display = "Entry not found: {}", _0)]
EntryNotFound(String),
#[fail(display = "Entry header error")]
EntryHeaderError,
#[fail(display = "Entry header type error")]
EntryHeaderTypeError,
#[fail(display = "Entry header type error at '{}', expected '{}'", _0, _1)]
EntryHeaderTypeError2(&'static str, &'static str),
#[fail(display = "Entry header read error")]
EntryHeaderReadError,
#[fail(display = "Entry header write error")]
EntryHeaderWriteError,
#[fail(display = "Entry header field missing: {}", _0)]
EntryHeaderFieldMissing(&'static str),
#[fail(display = "Toml deserialization error")]
TomlDeserError,
#[fail(display = "Toml querying error")]
TomlQueryError,
}

View file

@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use error_chain::ChainedError; use failure::Error;
/// An iterator that unwraps the `Ok` items of `iter`, while passing the `Err` items to its /// An iterator that unwraps the `Ok` items of `iter`, while passing the `Err` items to its
/// closure `f`. /// closure `f`.
@ -31,9 +31,10 @@ pub struct UnwrapWith<I, F>{
f: F f: F
} }
impl<I, F, T, E> Iterator for UnwrapWith<I, F> where impl<I, F, T> Iterator for UnwrapWith<I, F>
I: Iterator<Item = Result<T, E>>, where
F: FnMut(E) I: Iterator<Item = Result<T, Error>>,
F: FnMut(Error)
{ {
type Item = T; type Item = T;
@ -41,14 +42,13 @@ impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
match self.iter.next() { match self.iter.next() {
Some(Err(e)) => { Some(Err(e)) => { (self.f)(e); },
(self.f)(e);
},
Some(Ok(item)) => return Some(item), Some(Ok(item)) => return Some(item),
None => return None, None => return None,
} }
} }
} }
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint(); let (_, upper) = self.iter.size_hint();
@ -56,32 +56,14 @@ impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
} }
} }
impl<I, F, T, E> DoubleEndedIterator for UnwrapWith<I, F> where
I: DoubleEndedIterator<Item = Result<T, E>>,
F: FnMut(E)
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next_back() {
Some(Err(e)) => {
(self.f)(e);
},
Some(Ok(item)) => return Some(item),
None => return None,
}
}
}
}
/// Iterator helper for Unwrap with exiting on error /// Iterator helper for Unwrap with exiting on error
pub struct UnwrapExit<I, T, E>(I, i32) pub struct UnwrapExit<I, T>(I, i32)
where I: Iterator<Item = Result<T, E>>, where I: Iterator<Item = Result<T, Error>>;
E: ChainedError;
impl<I, T, E> Iterator for UnwrapExit<I, T, E> impl<I, T> Iterator for UnwrapExit<I, T>
where I: Iterator<Item = Result<T, E>>, where I: Iterator<Item = Result<T, Error>>,
E: ChainedError
{ {
type Item = T; type Item = T;
@ -91,9 +73,8 @@ impl<I, T, E> Iterator for UnwrapExit<I, T, E>
} }
} }
impl<I, T, E> DoubleEndedIterator for UnwrapExit<I, T, E> impl<I, T> DoubleEndedIterator for UnwrapExit<I, T>
where I: DoubleEndedIterator<Item = Result<T, E>>, where I: DoubleEndedIterator<Item = Result<T, Error>>,
E: ChainedError
{ {
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
use trace::MapErrTrace; use trace::MapErrTrace;
@ -102,18 +83,21 @@ impl<I, T, E> DoubleEndedIterator for UnwrapExit<I, T, E>
} }
/// This trait provides methods that make it easier to work with iterators that yield a `Result`. /// This trait provides methods that make it easier to work with iterators that yield a `Result`.
pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized { pub trait TraceIterator<T> : Iterator<Item = Result<T, Error>> + Sized {
/// Creates an iterator that yields the item in each `Ok` item, while filtering out the `Err` /// Creates an iterator that yields the item in each `Ok` item, while filtering out the
/// `Err`
/// items. Each filtered `Err` will be trace-logged with [`::trace::trace_error`]. /// items. Each filtered `Err` will be trace-logged with [`::trace::trace_error`].
/// ///
/// As with all iterators, the processing is lazy. If you do not use the result of this method, /// As with all iterators, the processing is lazy. If you do not use the result of this method,
/// nothing will be passed to `::trace::trace_error`, no matter how many `Err` items might /// nothing will be passed to `::trace::trace_error`, no matter how many `Err` items might
/// be present. /// be present.
#[inline] #[inline]
fn trace_unwrap<K>(self) -> UnwrapWith<Self, fn(E)> where E: ChainedError<ErrorKind = K> { fn trace_unwrap(self) -> UnwrapWith<Self, fn(Error)> {
#[inline] #[inline]
fn trace_error<K, E: ChainedError<ErrorKind = K>>(err: E) { fn trace_error(err: Error) {
eprintln!("{}", err.display_chain()); err.iter_chain().for_each(|cause| {
eprintln!("{}", cause);
});
} }
self.unwrap_with(trace_error) self.unwrap_with(trace_error)
@ -127,12 +111,11 @@ pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
/// nothing will be passed to `::trace::trace_error_exit`, no matter how many `Err` items might /// nothing will be passed to `::trace::trace_error_exit`, no matter how many `Err` items might
/// be present. /// be present.
#[inline] #[inline]
fn trace_unwrap_exit(self, exitcode: i32) -> UnwrapExit<Self, T, E> fn trace_unwrap_exit(self, exitcode: i32) -> UnwrapExit<Self, T> {
where E: ChainedError
{
UnwrapExit(self, exitcode) UnwrapExit(self, exitcode)
} }
/// Takes a closure and creates an iterator that will yield the items inside all `Ok` items /// Takes a closure and creates an iterator that will yield the items inside all `Ok` items
/// yielded by the original iterator. All `Err` items will be filtered out, and the contents /// yielded by the original iterator. All `Err` items will be filtered out, and the contents
/// of each `Err` will be passed to the closure. /// of each `Err` will be passed to the closure.
@ -141,50 +124,13 @@ pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
/// for the closure to be called. /// for the closure to be called.
#[inline] #[inline]
fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F> fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F>
where F: FnMut(E) where F: FnMut(Error)
{ {
UnwrapWith { iter: self, f } UnwrapWith { iter: self, f }
} }
} }
impl<I, T, E> TraceIterator<T, E> for I where impl<I, T> TraceIterator<T> for I where
I: Iterator<Item = Result<T, E>> I: Iterator<Item = Result<T, Error>>
{} {}
#[cfg(test)]
mod test {
use super::TraceIterator;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct TestError(i32);
#[test]
fn test_unwrap_with() {
let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
let mut errs = vec![];
let oks = original
.into_iter()
.unwrap_with(|e|errs.push(e))
.collect::<Vec<_>>();
assert_eq!(&oks, &[1, 3]);
assert_eq!(&errs, &[TestError(2), TestError(4)]);
}
#[test]
fn test_unwrap_with_backward() {
let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
let mut errs = vec![];
let oks = original
.into_iter()
.rev()
.unwrap_with(|e|errs.push(e))
.collect::<Vec<_>>();
assert_eq!(&oks, &[3, 1]);
assert_eq!(&errs, &[TestError(4), TestError(2)]);
}
}

View file

@ -35,11 +35,13 @@
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate ansi_term; extern crate ansi_term;
extern crate error_chain; extern crate failure;
#[macro_use] extern crate failure_derive;
pub mod io; pub mod errors;
pub mod exit; pub mod exit;
pub mod trace; pub mod io;
pub mod iter; pub mod iter;
pub mod str; pub mod str;
pub mod trace;

View file

@ -21,7 +21,7 @@ use std::process::exit;
use std::fmt::Display; use std::fmt::Display;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::fmt::Result as FmtResult; use std::fmt::Result as FmtResult;
use error_chain::ChainedError; use failure::Error;
use ansi_term::Colour::Red; use ansi_term::Colour::Red;
struct ImagTrace<'a, T: 'a + ?Sized>(&'a T); struct ImagTrace<'a, T: 'a + ?Sized>(&'a T);
@ -32,32 +32,34 @@ impl<'a, T: 'a + ?Sized> ImagTrace<'a, T> {
} }
} }
impl<'a, T> Display for ImagTrace<'a, T> impl<'a> Display for ImagTrace<'a, Error>
where T: ChainedError
{ {
fn fmt(&self, fmt: &mut Formatter) -> FmtResult { fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
try!(writeln!(fmt, "{}: {}", Red.blink().paint("ERROR[ 0]"), self.0)); let _ = writeln!(fmt, "{}: {}", Red.blink().paint("ERROR[ 0]"), self.0)?;
for (i, e) in self.0.iter().enumerate().skip(1) { {
try!(writeln!(fmt, "{}: {}", Red.blink().paint(format!("ERROR[{:>4}]", i)), e)); for (i, cause) in self.0.iter_causes().enumerate() {
let _ = writeln!(fmt,
"{prefix}: {error}",
prefix = Red.blink().paint(format!("ERROR[{:>4}]", i)),
error = cause)?;
}
} }
if let Some(backtrace) = self.0.backtrace() { let _ = writeln!(fmt, "{}", Red.paint("--- BACKTRACE ---"))?;
try!(writeln!(fmt, "{}", Red.paint("--- BACKTRACE ---"))); let _ = writeln!(fmt, "{:?}", self.0.backtrace())?;
try!(writeln!(fmt, "{:?}", backtrace));
}
Ok(()) Ok(())
} }
} }
pub fn trace_error<K, C: ChainedError<ErrorKind = K>>(e: &C) { pub fn trace_error(e: &Error) {
eprintln!("{}", ImagTrace::new(e)); eprintln!("{}", ImagTrace::new(e));
} }
pub fn trace_error_dbg<K, C: ChainedError<ErrorKind = K>>(e: &C) { pub fn trace_error_dbg(e: &Error) {
debug!("{}", e.display_chain()); debug!("{}", ImagTrace::new(e));
} }
/// Helper functions for `Result<T, E>` types to reduce overhead in the following situations: /// Helper functions for `Result<T, E>` types to reduce overhead in the following situations:
@ -74,7 +76,7 @@ pub trait MapErrTrace {
fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output; fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output;
} }
impl<U, K, E: ChainedError<ErrorKind = K>> MapErrTrace for Result<U, E> { impl<U> MapErrTrace for Result<U, Error> {
type Output = U; type Output = U;
/// Simply call `trace_error()` on the Err (if there is one) and return the error. /// Simply call `trace_error()` on the Err (if there is one) and return the error.

View file

@ -25,10 +25,10 @@ toml = "0.4"
xdg-basedir = "1.0" xdg-basedir = "1.0"
itertools = "0.7" itertools = "0.7"
ansi_term = "0.11" ansi_term = "0.11"
is-match = "0.1" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
toml-query = "0.7"
error-chain = "0.12"
atty = "0.2" atty = "0.2"
failure = "0.1"
failure_derive = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -21,20 +21,19 @@ use std::path::PathBuf;
use toml::Value; use toml::Value;
use clap::App; use clap::App;
use failure::ResultExt;
use failure::Fallible as Result;
use failure::Error;
use failure::err_msg;
use error::RuntimeError as RE; use libimagerror::errors::ErrorMsg as EM;
use error::RuntimeErrorKind as REK;
use error::Result;
use error::ResultExt;
/// Get a new configuration object. /// Get a new configuration object.
/// ///
/// The passed runtimepath is used for searching the configuration file, whereas several file /// The passed runtimepath is used for searching the configuration file, whereas several file
/// names are tested. If that does not work, the home directory and the XDG basedir are tested /// names are tested. If that does not work, the home directory and the XDG basedir are tested
/// with all variants. /// with all variants.
/// pub fn fetch_config(searchpath: &PathBuf) -> Result<Option<Value>> {
/// If that doesn't work either, an error is returned.
pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
@ -65,7 +64,7 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
.unwrap_or(vec![]), .unwrap_or(vec![]),
]; ];
Itertools::flatten(vals.iter()) let config = Itertools::flatten(vals.iter())
.filter(|path| path.exists() && path.is_file()) .filter(|path| path.exists() && path.is_file())
.filter_map(|path| { .filter_map(|path| {
let content = { let content = {
@ -90,13 +89,14 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
.unwrap_or_else(|| String::from("Line unknown, Column unknown")); .unwrap_or_else(|| String::from("Line unknown, Column unknown"));
let _ = write!(stderr(), "Config file parser error at {}", line_col); let _ = write!(stderr(), "Config file parser error at {}", line_col);
let e : RE = RE::from(e); let e = Error::from(EM::TomlDeserError);
trace_error(&e); trace_error(&e);
None None
}) })
}) })
.nth(0) .nth(0);
.ok_or(RE::from_kind(REK::ConfigNoConfigFileFound))
Ok(config)
} }
/// Override the configuration. /// Override the configuration.
@ -120,16 +120,16 @@ pub fn override_config(val: &mut Value, v: Vec<String>) -> Result<()> {
.map(|(k, v)| { .map(|(k, v)| {
let value = val let value = val
.read(&k) .read(&k)
.chain_err(|| REK::ConfigTOMLParserError)? .context(EM::TomlQueryError)?
.ok_or(RE::from_kind(REK::ConfigOverrideKeyNotAvailable))?; .ok_or_else(|| Error::from(err_msg("Confit parser error")))?;
into_value(value, v) into_value(value, v)
.map(|v| info!("Successfully overridden: {} = {}", k, v)) .map(|v| info!("Successfully overridden: {} = {}", k, v))
.ok_or_else(|| RE::from_kind(REK::ConfigOverrideTypeNotMatching)) .ok_or_else(|| Error::from(err_msg("Config override type not matching")))
}); });
for elem in iter { for elem in iter {
let _ = try!(elem.chain_err(|| REK::ConfigOverrideError)); let _ = elem.context(err_msg("Config override error"))?;
} }
Ok(()) Ok(())

View file

@ -1,125 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
error_chain! {
types {
RuntimeError, RuntimeErrorKind, ResultExt, Result;
}
foreign_links {
IO(::std::io::Error);
TomlDeError(::toml::de::Error);
TomlQueryError(::toml_query::error::Error);
HandlebarsTemplateError(::handlebars::TemplateError);
}
errors {
Instantiate {
description("Could not instantiate")
display("Could not instantiate")
}
IOError {
description("IO Error")
display("IO Error")
}
ProcessExitFailure {
description("Process exited with failure")
display("Process exited with failure")
}
IOLogFileOpenError {
description("IO Error: Could not open logfile")
display("IO Error: Could not open logfile")
}
ConfigTypeError(path: String, should_be_type: &'static str) {
description("Error while reading the configuration: Type Error")
display("Type Error: '{}' should be '{}'", path, should_be_type)
}
GlobalLogLevelConfigMissing {
description("Global config 'imag.logging.level' missing")
display("Global config 'imag.logging.level' missing")
}
GlobalDestinationConfigMissing {
description("Global config 'imag.logging.destinations' missing")
display("Global config 'imag.logging.destinations' missing")
}
InvalidLogLevelSpec {
description("Invalid log level specification: Only 'trace', 'debug', 'info', 'warn', 'error' are allowed")
display("Invalid log level specification: Only 'trace', 'debug', 'info', 'warn', 'error' are allowed")
}
ConfigMissingLoggingFormatTrace {
description("Missing config for logging format for trace logging")
display("Missing config for logging format for trace logging")
}
ConfigMissingLoggingFormatDebug {
description("Missing config for logging format for debug logging")
display("Missing config for logging format for debug logging")
}
ConfigMissingLoggingFormatInfo {
description("Missing config for logging format for info logging")
display("Missing config for logging format for info logging")
}
ConfigMissingLoggingFormatWarn {
description("Missing config for logging format for warn logging")
display("Missing config for logging format for warn logging")
}
ConfigMissingLoggingFormatError {
description("Missing config for logging format for error logging")
display("Missing config for logging format for error logging")
}
ConfigTOMLParserError {
description("Configuration: TOML Parsing error")
display("Configuration: TOML Parsing error")
}
ConfigNoConfigFileFound {
description("Configuration: No config file found")
display("Configuration: No config file found")
}
ConfigOverrideError {
description("Configuration: Config override error")
display("Configuration: Config override error")
}
ConfigOverrideKeyNotAvailable {
description("Configuration: Key not available")
display("Configuration: Key not available")
}
ConfigOverrideTypeNotMatching {
description("Configuration: Configuration Type not matching")
display("Configuration: Configuration Type not matching")
}
}
}

View file

@ -36,17 +36,16 @@
)] )]
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate error_chain;
extern crate itertools; extern crate itertools;
#[cfg(unix)] extern crate xdg_basedir; #[cfg(unix)] extern crate xdg_basedir;
extern crate env_logger; extern crate env_logger;
extern crate ansi_term; extern crate ansi_term;
extern crate handlebars; extern crate handlebars;
#[macro_use] extern crate failure;
extern crate clap; extern crate clap;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
#[macro_use] extern crate is_match;
extern crate atty; extern crate atty;
extern crate libimagstore; extern crate libimagstore;
@ -54,7 +53,6 @@ extern crate libimagutil;
extern crate libimagerror; extern crate libimagerror;
extern crate libimaginteraction; extern crate libimaginteraction;
pub mod error;
pub mod configuration; pub mod configuration;
pub mod logger; pub mod logger;
pub mod io; pub mod io;

View file

@ -24,11 +24,12 @@ use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::ops::Deref; use std::ops::Deref;
use error::RuntimeErrorKind as EK;
use error::RuntimeError as RE;
use error::ResultExt;
use runtime::Runtime; use runtime::Runtime;
use failure::ResultExt;
use failure::Fallible as Result;
use failure::Error;
use failure::err_msg;
use clap::ArgMatches; use clap::ArgMatches;
use log::{Log, Level, Record, Metadata}; use log::{Log, Level, Record, Metadata};
use toml::Value; use toml::Value;
@ -36,10 +37,10 @@ use toml_query::read::TomlValueReadExt;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use handlebars::Handlebars; use handlebars::Handlebars;
type ModuleName = String; use libimagerror::errors::ErrorMsg as EM;
type Result<T> = ::std::result::Result<T, RE>;
type ModuleName = String;
#[derive(Debug)]
enum LogDestination { enum LogDestination {
Stderr, Stderr,
File(Arc<Mutex<::std::fs::File>>), File(Arc<Mutex<::std::fs::File>>),
@ -51,7 +52,6 @@ impl Default for LogDestination {
} }
} }
#[derive(Debug)]
struct ModuleSettings { struct ModuleSettings {
enabled: bool, enabled: bool,
level: Option<Level>, level: Option<Level>,
@ -89,32 +89,39 @@ impl ImagLogger {
{ {
let fmt = aggregate_global_format_trace(config)?; let fmt = aggregate_global_format_trace(config)?;
handlebars.register_template_string("TRACE", fmt)?; // name must be uppercase handlebars.register_template_string("TRACE", fmt)
.map_err(Error::from)
.context(err_msg("Handlebars template error"))?; // name must be uppercase
} }
{ {
let fmt = aggregate_global_format_debug(config)?; let fmt = aggregate_global_format_debug(config)?;
handlebars.register_template_string("DEBUG", fmt)?; // name must be uppercase handlebars.register_template_string("DEBUG", fmt)
.map_err(Error::from)
.context(err_msg("Handlebars template error"))?; // name must be uppercase
} }
{ {
let fmt = aggregate_global_format_info(config)?; let fmt = aggregate_global_format_info(config)?;
handlebars.register_template_string("INFO", fmt)?; // name must be uppercase handlebars.register_template_string("INFO", fmt)
.map_err(Error::from)
.context(err_msg("Handlebars template error"))?; // name must be uppercase
} }
{ {
let fmt = aggregate_global_format_warn(config)?; let fmt = aggregate_global_format_warn(config)?;
handlebars.register_template_string("WARN", fmt)?; // name must be uppercase handlebars.register_template_string("WARN", fmt)
.map_err(Error::from)
.context(err_msg("Handlebars template error"))?; // name must be uppercase
} }
{ {
let fmt = aggregate_global_format_error(config)?; let fmt = aggregate_global_format_error(config)?;
handlebars.register_template_string("ERROR", fmt)?; // name must be uppercase handlebars.register_template_string("ERROR", fmt)
.map_err(Error::from)
.context(err_msg("Handlebars template error"))?; // name must be uppercase
} }
let module_settings = aggregate_module_settings(matches, config)?;
eprintln!("Logging: {:?}", module_settings);
Ok(ImagLogger { Ok(ImagLogger {
global_loglevel : aggregate_global_loglevel(matches, config)?, global_loglevel : aggregate_global_loglevel(matches, config)?,
global_destinations : aggregate_global_destinations(matches, config)?, global_destinations : aggregate_global_destinations(matches, config)?,
module_settings : module_settings, module_settings : aggregate_module_settings(matches, config)?,
handlebars : handlebars, handlebars : handlebars,
}) })
} }
@ -179,35 +186,28 @@ impl Log for ImagLogger {
self.module_settings self.module_settings
.get(record_target) .get(record_target)
.map(|module_setting| { .map(|module_setting| {
// We have a module setting some
// * Check whether logging is enabled for this module and
// * check whether the module logging level is >= or, if there is no module logging
// level,
// * check whether the global logging level is >= the record level.
let set = module_setting.enabled && let set = module_setting.enabled &&
module_setting.level.unwrap_or(self.global_loglevel) >= record.level(); module_setting.level.unwrap_or(self.global_loglevel) >= record.level();
if set { // if we want to log from a setting standpoint if set {
// get the destinations for the module and log to all of them
module_setting.destinations.as_ref().map(|destinations| for d in destinations { module_setting.destinations.as_ref().map(|destinations| for d in destinations {
let _ = log_to_destination(&d); // ignore errors, because what else? // If there's an error, we cannot do anything, can we?
let _ = log_to_destination(&d);
}); });
// after that, log to the global destinations as well
for d in self.global_destinations.iter() { for d in self.global_destinations.iter() {
let _ = log_to_destination(&d); // ignore errors, because what else? // If there's an error, we cannot do anything, can we?
let _ = log_to_destination(&d);
} }
} }
}) })
// if we do not have a setting for the record target
.unwrap_or_else(|| { .unwrap_or_else(|| {
if self.global_loglevel >= record.level() { // if logging is enabled for that level if self.global_loglevel >= record.level() {
self.global_destinations // Yes, we log
.iter() for d in self.global_destinations.iter() {
.for_each(|d| { // log to all global destinations // If there's an error, we cannot do anything, can we?
let _ = log_to_destination(&d); // ignore errors, because what else? let _ = log_to_destination(&d);
}); }
} }
}); });
} }
@ -220,7 +220,7 @@ fn match_log_level_str(s: &str) -> Result<Level> {
"info" => Ok(Level::Info), "info" => Ok(Level::Info),
"warn" => Ok(Level::Warn), "warn" => Ok(Level::Warn),
"error" => Ok(Level::Error), "error" => Ok(Level::Error),
_ => return Err(RE::from_kind(EK::InvalidLogLevelSpec)), lvl => return Err(format_err!("Invalid logging level: {}", lvl)),
} }
} }
@ -243,8 +243,10 @@ fn aggregate_global_loglevel(matches: &ArgMatches, config: Option<&Value>) -> Re
if let Some(cfg) = config { if let Some(cfg) = config {
let cfg_loglevel = cfg let cfg_loglevel = cfg
.read_string("imag.logging.level")? .read_string("imag.logging.level")
.ok_or(RE::from_kind(EK::GlobalLogLevelConfigMissing)) .map_err(Error::from)
.context(EM::TomlQueryError)?
.ok_or(err_msg("Global log level config missing"))
.and_then(|s| match_log_level_str(&s))?; .and_then(|s| match_log_level_str(&s))?;
if let Some(cli_loglevel) = get_arg_loglevel(matches)? { if let Some(cli_loglevel) = get_arg_loglevel(matches)? {
@ -273,7 +275,9 @@ fn translate_destination(raw: &str) -> Result<LogDestination> {
.map(Mutex::new) .map(Mutex::new)
.map(Arc::new) .map(Arc::new)
.map(LogDestination::File) .map(LogDestination::File)
.chain_err(|| EK::IOLogFileOpenError) .map_err(Error::from)
.context(EM::IO)
.map_err(Error::from)
} }
} }
} }
@ -285,9 +289,9 @@ fn translate_destinations(raw: &Vec<Value>) -> Result<Vec<LogDestination>> {
acc.and_then(|mut v| { acc.and_then(|mut v| {
let dest = val.as_str() let dest = val.as_str()
.ok_or_else(|| { .ok_or_else(|| {
let path = "imag.logging.modules.<mod>.destinations".to_owned(); let path = "imag.logging.modules.<mod>.destinations";
let ty = "Array<String>"; let ty = "Array<String>";
RE::from_kind(EK::ConfigTypeError(path, ty)) Error::from(format_err!("Type error at {}, expected {}", path, ty))
}) })
.and_then(translate_destination)?; .and_then(translate_destination)?;
v.push(dest); v.push(dest);
@ -299,16 +303,18 @@ fn translate_destinations(raw: &Vec<Value>) -> Result<Vec<LogDestination>> {
fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>) fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
-> Result<Vec<LogDestination>> -> Result<Vec<LogDestination>>
{ {
let config_log_dest_path = "imag.logging.destinations";
match config { match config {
Some(cfg) => cfg Some(cfg) => cfg
.read(&config_log_dest_path)? .read("imag.logging.destinations")
.ok_or_else(|| RE::from_kind(EK::GlobalDestinationConfigMissing))? .map_err(Error::from)
.context(EM::TomlQueryError)?
.ok_or_else(|| err_msg("Global log destination config missing"))?
.as_array() .as_array()
.ok_or_else(|| { .ok_or_else(|| {
let path = config_log_dest_path.to_owned(); let path = "imag.logging.destinations";
let ty = "Array"; let ty = "Array";
RE::from_kind(EK::ConfigTypeError(path, ty)) Error::from(format_err!("Type error at {}, expected {}", path, ty))
}) })
.and_then(translate_destinations), .and_then(translate_destinations),
None => { None => {
@ -330,10 +336,12 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
} }
macro_rules! aggregate_global_format { macro_rules! aggregate_global_format {
($read_str:expr, $error_kind_if_missing:expr, $config:expr) => { ($read_str:expr, $error_msg_if_missing:expr, $config:expr) => {
try!($config.ok_or(RE::from_kind($error_kind_if_missing))) try!($config.ok_or_else(|| Error::from(err_msg($error_msg_if_missing))))
.read_string($read_str)? .read_string($read_str)
.ok_or_else(|| RE::from_kind($error_kind_if_missing)) .map_err(Error::from)
.context(EM::TomlQueryError)?
.ok_or_else(|| Error::from(err_msg($error_msg_if_missing)))
}; };
} }
@ -341,7 +349,7 @@ fn aggregate_global_format_trace(config: Option<&Value>)
-> Result<String> -> Result<String>
{ {
aggregate_global_format!("imag.logging.format.trace", aggregate_global_format!("imag.logging.format.trace",
EK::ConfigMissingLoggingFormatTrace, "Config missing: Logging format: Trace",
config) config)
} }
@ -349,7 +357,7 @@ fn aggregate_global_format_debug(config: Option<&Value>)
-> Result<String> -> Result<String>
{ {
aggregate_global_format!("imag.logging.format.debug", aggregate_global_format!("imag.logging.format.debug",
EK::ConfigMissingLoggingFormatDebug, "Config missing: Logging format: Debug",
config) config)
} }
@ -357,7 +365,7 @@ fn aggregate_global_format_info(config: Option<&Value>)
-> Result<String> -> Result<String>
{ {
aggregate_global_format!("imag.logging.format.info", aggregate_global_format!("imag.logging.format.info",
EK::ConfigMissingLoggingFormatInfo, "Config missing: Logging format: Info",
config) config)
} }
@ -365,7 +373,7 @@ fn aggregate_global_format_warn(config: Option<&Value>)
-> Result<String> -> Result<String>
{ {
aggregate_global_format!("imag.logging.format.warn", aggregate_global_format!("imag.logging.format.warn",
EK::ConfigMissingLoggingFormatWarn, "Config missing: Logging format: Warn",
config) config)
} }
@ -373,11 +381,11 @@ fn aggregate_global_format_error(config: Option<&Value>)
-> Result<String> -> Result<String>
{ {
aggregate_global_format!("imag.logging.format.error", aggregate_global_format!("imag.logging.format.error",
EK::ConfigMissingLoggingFormatError, "Config missing: Logging format: Error",
config) config)
} }
fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>) fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
-> Result<BTreeMap<ModuleName, ModuleSettings>> -> Result<BTreeMap<ModuleName, ModuleSettings>>
{ {
// Helper macro to return the error from Some(Err(_)) and map everything else to an // Helper macro to return the error from Some(Err(_)) and map everything else to an
@ -393,43 +401,42 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
}; };
match config { match config {
Some(cfg) => match cfg.read("imag.logging.modules") { Some(cfg) => match cfg.read("imag.logging.modules").map_err(Error::from) {
Ok(Some(&Value::Table(ref t))) => { Ok(Some(&Value::Table(ref t))) => {
// translate the module settings from the table `t` // translate the module settings from the table `t`
let mut settings = BTreeMap::new(); let mut settings = BTreeMap::new();
for (module_name, v) in t { for (module_name, v) in t {
let destinations = inner_try! { let destinations = inner_try! {
v.read("destinations")? v.read("destinations")
.map_err(Error::from)
.context(EM::TomlQueryError)?
.map(|val| { .map(|val| {
val.as_array() val.as_array()
.ok_or_else(|| { .ok_or_else(|| {
let path = "imag.logging.modules.<mod>.destinations".to_owned(); let path = "imag.logging.modules.<mod>.destinations";
let ty = "Array"; let ty = "Array";
RE::from_kind(EK::ConfigTypeError(path, ty)) Error::from(format_err!("Type error at {}, expected {}", path, ty))
}) })
.and_then(translate_destinations) .and_then(translate_destinations)
}) })
}; };
let (pre_enabled, level) = if matches.is_present(Runtime::arg_debugging_name()) {
(true, Some(Level::Debug))
} else {
let level = inner_try! { let level = inner_try! {
v.read_string("level")?.map(|s| match_log_level_str(&s)) v.read_string("level")
.map_err(Error::from)
.context(EM::TomlQueryError)?
.map(|s| match_log_level_str(&s))
}; };
(false, level) let enabled = v.read("enabled")
}; .map_err(Error::from)
.context(EM::TomlQueryError)?
let enabled = pre_enabled ||
v.read("enabled")?
.map(|v| v.as_bool().unwrap_or(false)) .map(|v| v.as_bool().unwrap_or(false))
.ok_or_else(|| { .ok_or_else(|| {
let path = "imag.logging.modules.<mod>.enabled".to_owned(); let path = "imag.logging.modules.<mod>.enabled";
let ty = "Boolean"; let ty = "Boolean";
RE::from_kind(EK::ConfigTypeError(path, ty)) Error::from(format_err!("Type error at {}, expected {}", path, ty))
})?; })?;
let module_settings = ModuleSettings { let module_settings = ModuleSettings {
@ -445,15 +452,15 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
Ok(settings) Ok(settings)
}, },
Ok(Some(_)) => { Ok(Some(_)) => {
let path = "imag.logging.modules".to_owned(); let path = "imag.logging.modules";
let ty = "Table"; let ty = "Table";
Err(RE::from_kind(EK::ConfigTypeError(path, ty))) Err(Error::from(format_err!("Type error at {}, expected {}", path, ty)))
}, },
Ok(None) => { Ok(None) => {
// No modules configured. This is okay! // No modules configured. This is okay!
Ok(BTreeMap::new()) Ok(BTreeMap::new())
}, },
Err(e) => Err(e).map_err(From::from), Err(e) => Err(e).context(EM::TomlQueryError).map_err(Error::from),
}, },
None => { None => {
write!(stderr(), "No Configuration.").ok(); write!(stderr(), "No Configuration.").ok();

View file

@ -30,14 +30,16 @@ use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use clap::{Arg, ArgMatches}; use clap::{Arg, ArgMatches};
use failure::ResultExt;
use failure::Fallible as Result;
use failure::Error;
use failure::err_msg;
use configuration::{fetch_config, override_config, InternalConfiguration}; use configuration::{fetch_config, override_config, InternalConfiguration};
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::ResultExt;
use logger::ImagLogger; use logger::ImagLogger;
use io::OutputProxy; use io::OutputProxy;
use libimagerror::errors::ErrorMsg as EM;
use libimagerror::trace::*; use libimagerror::trace::*;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::file_abstraction::InMemoryFileAbstraction; use libimagstore::file_abstraction::InMemoryFileAbstraction;
@ -62,7 +64,7 @@ impl<'a> Runtime<'a> {
/// and builds the Runtime object with it. /// and builds the Runtime object with it.
/// ///
/// The cli_app object should be initially build with the ::get_default_cli_builder() function. /// The cli_app object should be initially build with the ::get_default_cli_builder() function.
pub fn new<C>(cli_app: C) -> Result<Runtime<'a>, RuntimeError> pub fn new<C>(cli_app: C) -> Result<Runtime<'a>>
where C: Clone + CliSpec<'a> + InternalConfiguration where C: Clone + CliSpec<'a> + InternalConfiguration
{ {
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
@ -76,17 +78,15 @@ impl<'a> Runtime<'a> {
debug!("Config path = {:?}", configpath); debug!("Config path = {:?}", configpath);
let config = match fetch_config(&configpath) { let config = match fetch_config(&configpath)? {
Err(e) => if !is_match!(e.kind(), &RuntimeErrorKind::ConfigNoConfigFileFound) { None => {
return Err(e).chain_err(|| RuntimeErrorKind::Instantiate); return Err(err_msg("No configuration file found"))
} else { .context(err_msg("Maybe try to use 'imag-init' to initialize imag?"))
eprintln!("No config file found."); .context(err_msg("Continuing without configuration file"))
eprintln!("Maybe try to use 'imag-init' to initialize imag?"); .context(err_msg("Cannot instantiate runtime"))
eprintln!("Continuing without configuration file"); .map_err(Error::from);
None
}, },
Some(mut config) => {
Ok(mut config) => {
if let Err(e) = override_config(&mut config, get_override_specs(&matches)) { if let Err(e) = override_config(&mut config, get_override_specs(&matches)) {
error!("Could not apply config overrides"); error!("Could not apply config overrides");
trace_error(&e); trace_error(&e);
@ -102,16 +102,14 @@ impl<'a> Runtime<'a> {
} }
/// Builds the Runtime object using the given `config`. /// Builds the Runtime object using the given `config`.
pub fn with_configuration<C>(cli_app: C, config: Option<Value>) pub fn with_configuration<C>(cli_app: C, config: Option<Value>) -> Result<Runtime<'a>>
-> Result<Runtime<'a>, RuntimeError>
where C: Clone + CliSpec<'a> + InternalConfiguration where C: Clone + CliSpec<'a> + InternalConfiguration
{ {
let matches = cli_app.clone().matches(); let matches = cli_app.clone().matches();
Runtime::_new(cli_app, matches, config) Runtime::_new(cli_app, matches, config)
} }
fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>) fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>) -> Result<Runtime<'a>>
-> Result<Runtime<'a>, RuntimeError>
where C: Clone + CliSpec<'a> + InternalConfiguration where C: Clone + CliSpec<'a> + InternalConfiguration
{ {
if cli_app.enable_logging() { if cli_app.enable_logging() {
@ -146,7 +144,8 @@ impl<'a> Runtime<'a> {
store: store, store: store,
} }
}) })
.chain_err(|| RuntimeErrorKind::Instantiate) .context(err_msg("Cannot instantiate runtime"))
.map_err(Error::from)
} }
/// ///
@ -379,7 +378,7 @@ impl<'a> Runtime<'a> {
} }
/// Get a editor command object which can be called to open the $EDITOR /// Get a editor command object which can be called to open the $EDITOR
pub fn editor(&self) -> Result<Option<Command>, RuntimeError> { pub fn editor(&self) -> Result<Option<Command>> {
self.cli() self.cli()
.value_of("editor") .value_of("editor")
.map(String::from) .map(String::from)
@ -391,7 +390,7 @@ impl<'a> Runtime<'a> {
}) })
}) })
.or(env::var("EDITOR").ok()) .or(env::var("EDITOR").ok())
.ok_or_else(|| RuntimeErrorKind::IOError.into()) .ok_or_else(|| Error::from(EM::IO))
.map_dbg(|s| format!("Editing with '{}'", s)) .map_dbg(|s| format!("Editing with '{}'", s))
.and_then(|s| { .and_then(|s| {
let mut split = s.split_whitespace(); let mut split = s.split_whitespace();
@ -401,7 +400,7 @@ impl<'a> Runtime<'a> {
} }
let mut c = Command::new(command.unwrap()); // secured above let mut c = Command::new(command.unwrap()); // secured above
c.args(split); c.args(split);
c.stdin(::std::fs::File::open("/dev/tty")?); c.stdin(::std::fs::File::open("/dev/tty").context(EM::IO)?);
c.stderr(::std::process::Stdio::inherit()); c.stderr(::std::process::Stdio::inherit());
Ok(Some(c)) Ok(Some(c))
}) })
@ -442,8 +441,6 @@ impl<'a> Runtime<'a> {
/// # Return value /// # Return value
/// ///
/// On success, the exit status object of the `Command` invocation is returned. /// On success, the exit status object of the `Command` invocation is returned.
/// On Error, a RuntimeError object is returned. This is also the case if writing the error
/// message does not work.
/// ///
/// # Details /// # Details
/// ///
@ -457,7 +454,7 @@ impl<'a> Runtime<'a> {
command: S, command: S,
subcommand: S, subcommand: S,
args: &ArgMatches) args: &ArgMatches)
-> Result<::std::process::ExitStatus, RuntimeError> -> Result<::std::process::ExitStatus>
{ {
use std::io::Write; use std::io::Write;
use std::io::ErrorKind; use std::io::ErrorKind;
@ -465,8 +462,7 @@ impl<'a> Runtime<'a> {
let rtp_str = self.rtp() let rtp_str = self.rtp()
.to_str() .to_str()
.map(String::from) .map(String::from)
.ok_or(RuntimeErrorKind::IOError) .ok_or_else(|| Error::from(EM::IO))?;
.map_err(RuntimeError::from_kind)?;
let command = format!("{}-{}", command.as_ref(), subcommand.as_ref()); let command = format!("{}-{}", command.as_ref(), subcommand.as_ref());
@ -497,7 +493,8 @@ impl<'a> Runtime<'a> {
}, },
_ => e, _ => e,
}) })
.map_err(RuntimeError::from) .context(EM::IO)
.map_err(Error::from)
} }
} }

View file

@ -29,8 +29,8 @@ walkdir = "2"
is-match = "0.1" is-match = "0.1"
serde = "1" serde = "1"
serde_json = "1" serde_json = "1"
error-chain = "0.12" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
toml-query = "0.7" failure = "0.1"
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
libimagutil = { version = "0.9.0", path = "../../../lib/etc/libimagutil" } libimagutil = { version = "0.9.0", path = "../../../lib/etc/libimagutil" }

View file

@ -19,9 +19,11 @@
use toml::Value; use toml::Value;
use store::Result; use failure::Fallible as Result;
use error::StoreError as SE; use failure::ResultExt;
use error::StoreErrorKind as SEK; use failure::Error;
use libimagerror::errors::ErrorMsg as EM;
/// Checks whether the store configuration has a key "implicit-create" which maps to a boolean /// Checks whether the store configuration has a key "implicit-create" which maps to a boolean
/// value. If that key is present, the boolean is returned, otherwise false is returned. /// value. If that key is present, the boolean is returned, otherwise false is returned.
@ -31,7 +33,10 @@ pub fn config_implicit_store_create_allowed(config: &Option<Value>) -> Result<bo
let key = "store.implicit-create"; let key = "store.implicit-create";
if let Some(ref t) = *config { if let Some(ref t) = *config {
t.read_bool(key)?.ok_or_else(|| SE::from_kind(SEK::ConfigKeyMissingError(key))) t.read_bool(key)
.map_err(Error::from)
.context(EM::TomlQueryError)?
.ok_or_else(|| format_err!("Config key missing: {}", key))
} else { } else {
Ok(false) Ok(false)
} }

View file

@ -1,253 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
use std::path::PathBuf;
use storeid::StoreId;
error_chain! {
types {
StoreError, StoreErrorKind, ResultExt, Result;
}
foreign_links {
Io(::std::io::Error);
Fmt(::std::fmt::Error);
TomlDeserError(::toml::de::Error);
TomlSerError(::toml::ser::Error);
GlobPatternError(::glob::PatternError);
TomlQueryError(::toml_query::error::Error);
}
errors {
ConfigurationError {
description("Store Configuration Error")
display("Store Configuration Error")
}
ConfigTypeError(key: &'static str, expected: &'static str) {
description("Store configuration type error")
display("Store configuration type error at '{}', expected {}", key, expected)
}
ConfigKeyMissingError(key: &'static str) {
description("Configuration Key missing")
display("Configuration Key missing: '{}'", key)
}
VersionError {
description("Incompatible store versions detected")
display("Incompatible store versions detected")
}
CreateStoreDirDenied {
description("Creating store directory implicitely denied")
display("Creating store directory implicitely denied")
}
FileError {
description("File Error")
display("File Error")
}
IoError {
description("IO Error")
display("IO Error")
}
IdLocked {
description("ID locked")
display("ID locked")
}
IdNotFound(sid: StoreId) {
description("ID not found")
display("ID not found: {}", sid)
}
FileNotFound {
description("File corresponding to ID not found")
display("File corresponding to ID not found")
}
FileNotCreated {
description("File corresponding to ID could not be created")
display("File corresponding to ID could not be created")
}
FileNotWritten {
description("File corresponding to ID could not be written to")
display("File corresponding to ID could not be written to")
}
FileNotSeeked {
description("File corresponding to ID could not be seeked")
display("File corresponding to ID could not be seeked")
}
FileNotRemoved {
description("File corresponding to ID could not be removed")
display("File corresponding to ID could not be removed")
}
FileNotRenamed {
description("File corresponding to ID could not be renamed")
display("File corresponding to ID could not be renamed")
}
FileNotCopied {
description("File could not be copied")
display("File could not be copied")
}
DirNotCreated {
description("Directory/Directories could not be created")
display("Directory/Directories could not be created")
}
StorePathExists(pb: PathBuf) {
description("Store path exists")
display("Store path exists: {:?}", pb)
}
StorePathCreate(pb: PathBuf) {
description("Store path create")
display("Store path create: {:?}", pb)
}
LockError {
description("Error locking datastructure")
display("Error locking datastructure")
}
LockPoisoned {
description("The internal Store Lock has been poisoned")
display("The internal Store Lock has been poisoned")
}
EntryAlreadyBorrowed(id: StoreId) {
description("Entry is already borrowed")
display("Entry is already borrowed: {:?}", id)
}
EntryAlreadyExists(id: StoreId) {
description("Entry already exists")
display("Entry already exists: {:?}", id)
}
MalformedEntry {
description("Entry has invalid formatting, missing header")
display("Entry has invalid formatting, missing header")
}
HeaderTypeFailure {
description("Header type is wrong")
display("Header type is wrong")
}
EncodingError {
description("Encoding error")
display("Encoding error")
}
EntryRenameError(old: PathBuf, new: PathBuf) {
description("Entry rename error")
display("Entry rename error: {:?} -> {:?}", old, new)
}
StoreIdHandlingError {
description("StoreId handling error")
display("StoreId handling error")
}
StoreIdLocalPartAbsoluteError(pb: PathBuf) {
description("StoreId 'id' part is absolute (starts with '/') which is not allowed")
display("StoreId 'id' part is absolute (starts with '/') which is not allowed: {:?}", pb)
}
StoreIdBuildFromFullPathError {
description("Building StoreId from full file path failed")
display("Building StoreId from full file path failed")
}
StoreIdHasNoBaseError(pb: PathBuf) {
description("StoreId has no 'base' part")
display("StoreId has no 'base' part: {:?}", pb)
}
CreateCallError(sid: StoreId) {
description("Error when calling create()")
display("Error when calling create({:?})", sid)
}
RetrieveCallError(sid: StoreId) {
description("Error when calling retrieve()")
display("Error when calling retrieve({:?})", sid)
}
GetCallError(sid: StoreId) {
description("Error when calling get()")
display("Error when calling get({:?})", sid)
}
UpdateCallError(sid: StoreId) {
description("Error when calling update()")
display("Error when calling update({:?})", sid)
}
RetrieveCopyCallError(sid: StoreId) {
description("Error when calling retrieve_copy()")
display("Error when calling retrieve_copy({:?})", sid)
}
DeleteCallError(sid: StoreId) {
description("Error when calling delete()")
display("Error when calling delete({:?})", sid)
}
MoveCallError(old: StoreId, new: StoreId) {
description("Error when calling move()")
display("Error when calling move({:?} -> {:?})", old, new)
}
// Parser-related errors
MissingMainSection {
description("Missing main section")
display("Missing main section")
}
MissingVersionInfo {
description("Missing version information in main section")
display("Missing version information in main section")
}
NonTableInBaseTable {
description("A non-table was found in the base table")
display("A non-table was found in the base table")
}
HeaderInconsistency {
description("The header is inconsistent")
display("The header is inconsistent")
}
}
}

View file

@ -22,8 +22,7 @@ use std::io::{Seek, SeekFrom, Read};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use error::{StoreError as SE, StoreErrorKind as SEK}; use libimagerror::errors::ErrorMsg as EM;
use error::ResultExt;
use super::FileAbstraction; use super::FileAbstraction;
use super::FileAbstractionInstance; use super::FileAbstractionInstance;
@ -34,6 +33,9 @@ use file_abstraction::iter::PathIterator;
use file_abstraction::iter::PathIterBuilder; use file_abstraction::iter::PathIterBuilder;
use walkdir::WalkDir; use walkdir::WalkDir;
use failure::ResultExt;
use failure::Fallible as Result;
use failure::Error;
#[derive(Debug)] #[derive(Debug)]
pub struct FSFileAbstractionInstance(PathBuf); pub struct FSFileAbstractionInstance(PathBuf);
@ -43,34 +45,41 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
/** /**
* Get the content behind this file * Get the content behind this file
*/ */
fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE> { fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>> {
debug!("Getting lazy file: {:?}", self); debug!("Getting lazy file: {:?}", self);
let mut file = open_file(&self.0) let mut file = match open_file(&self.0) {
.chain_err(|| SEK::FileNotFound)?; Err(err) => return Err(Error::from(err)),
Ok(None) => return Ok(None),
Ok(Some(file)) => file,
};
file.seek(SeekFrom::Start(0)).chain_err(|| SEK::FileNotSeeked)?; file.seek(SeekFrom::Start(0)).context(EM::FileNotSeeked)?;
let mut s = String::new(); let mut s = String::new();
file.read_to_string(&mut s) file.read_to_string(&mut s)
.chain_err(|| SEK::IoError) .context(EM::IO)
.map_err(Error::from)
.map(|_| s) .map(|_| s)
.and_then(|s| Entry::from_str(id, &s)) .and_then(|s: String| Entry::from_str(id, &s))
.map(Some)
} }
/** /**
* Write the content of this file * Write the content of this file
*/ */
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> { fn write_file_content(&mut self, buf: &Entry) -> Result<()> {
use std::io::Write; use std::io::Write;
let buf = buf.to_str()?.into_bytes(); let buf = buf.to_str()?.into_bytes();
let mut file = create_file(&self.0).chain_err(|| SEK::FileNotCreated)?; let mut file = create_file(&self.0).context(EM::FileNotCreated)?;
file.seek(SeekFrom::Start(0)).chain_err(|| SEK::FileNotCreated)?; file.seek(SeekFrom::Start(0)).context(EM::FileNotCreated)?;
file.set_len(buf.len() as u64).chain_err(|| SEK::FileNotWritten)?; file.set_len(buf.len() as u64).context(EM::FileNotWritten)?;
file.write_all(&buf).chain_err(|| SEK::FileNotWritten) file.write_all(&buf)
.context(EM::FileNotWritten)
.map_err(Error::from)
} }
} }
@ -82,19 +91,24 @@ pub struct FSFileAbstraction {}
impl FileAbstraction for FSFileAbstraction { impl FileAbstraction for FSFileAbstraction {
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> { fn remove_file(&self, path: &PathBuf) -> Result<()> {
remove_file(path).chain_err(|| SEK::FileNotRemoved) remove_file(path)
.context(EM::FileNotRemoved)
.map_err(Error::from)
} }
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> { fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
copy(from, to).chain_err(|| SEK::FileNotCopied).map(|_| ()) copy(from, to)
.map(|_| ())
.context(EM::FileNotCopied)
.map_err(Error::from)
} }
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> { fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
match to.parent() { match to.parent() {
Some(p) => if !p.exists() { Some(p) => if !p.exists() {
debug!("Creating: {:?}", p); debug!("Creating: {:?}", p);
let _ = create_dir_all(&PathBuf::from(p))?; let _ = create_dir_all(&PathBuf::from(p)).context(EM::DirNotCreated)?;
}, },
None => { None => {
debug!("Failed to find parent. This looks like it will fail now"); debug!("Failed to find parent. This looks like it will fail now");
@ -103,19 +117,23 @@ impl FileAbstraction for FSFileAbstraction {
} }
debug!("Renaming {:?} to {:?}", from, to); debug!("Renaming {:?} to {:?}", from, to);
rename(from, to).chain_err(|| SEK::FileNotRenamed) rename(from, to)
.context(EM::FileNotRenamed)
.map_err(Error::from)
} }
fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> { fn create_dir_all(&self, path: &PathBuf) -> Result<()> {
debug!("Creating: {:?}", path); debug!("Creating: {:?}", path);
create_dir_all(path).chain_err(|| SEK::DirNotCreated) create_dir_all(path)
.context(EM::DirNotCreated)
.map_err(Error::from)
} }
fn exists(&self, path: &PathBuf) -> Result<bool, SE> { fn exists(&self, path: &PathBuf) -> Result<bool> {
Ok(path.exists()) Ok(path.exists())
} }
fn is_file(&self, path: &PathBuf) -> Result<bool, SE> { fn is_file(&self, path: &PathBuf) -> Result<bool> {
Ok(path.is_file()) Ok(path.is_file())
} }
@ -124,13 +142,13 @@ impl FileAbstraction for FSFileAbstraction {
} }
/// We return nothing from the FS here. /// We return nothing from the FS here.
fn drain(&self) -> Result<Drain, SE> { fn drain(&self) -> Result<Drain> {
Ok(Drain::empty()) Ok(Drain::empty())
} }
/// FileAbstraction::fill implementation that consumes the Drain and writes everything to the /// FileAbstraction::fill implementation that consumes the Drain and writes everything to the
/// filesystem /// filesystem
fn fill(&mut self, mut d: Drain) -> Result<(), SE> { fn fill(&mut self, mut d: Drain) -> Result<()> {
d.iter() d.iter()
.fold(Ok(()), |acc, (path, element)| { .fold(Ok(()), |acc, (path, element)| {
acc.and_then(|_| self.new_instance(path).write_file_content(&element)) acc.and_then(|_| self.new_instance(path).write_file_content(&element))
@ -141,7 +159,7 @@ impl FileAbstraction for FSFileAbstraction {
basepath: PathBuf, basepath: PathBuf,
storepath: PathBuf, storepath: PathBuf,
backend: Arc<FileAbstraction>) backend: Arc<FileAbstraction>)
-> Result<PathIterator, SE> -> Result<PathIterator>
{ {
trace!("Building PathIterator object"); trace!("Building PathIterator object");
Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend)) Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend))
@ -153,13 +171,15 @@ pub(crate) struct WalkDirPathIterBuilder {
} }
impl PathIterBuilder for WalkDirPathIterBuilder { impl PathIterBuilder for WalkDirPathIterBuilder {
fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf, SE>>> { fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>> {
Box::new(WalkDir::new(self.basepath.clone()) Box::new(WalkDir::new(self.basepath.clone())
.min_depth(1) .min_depth(1)
.max_open(100) .max_open(100)
.into_iter() .into_iter()
.map(|r| { .map(|r| {
r.map(|e| PathBuf::from(e.path())).chain_err(|| SE::from_kind(SEK::FileError)) r.map(|e| PathBuf::from(e.path()))
.context(format_err!("Error in Walkdir"))
.map_err(Error::from)
})) }))
} }
@ -168,8 +188,16 @@ impl PathIterBuilder for WalkDirPathIterBuilder {
} }
} }
fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> { fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<Option<File>> {
OpenOptions::new().write(true).read(true).open(p) match OpenOptions::new().write(true).read(true).open(p) {
Err(e) => {
match e.kind() {
::std::io::ErrorKind::NotFound => return Ok(None),
_ => return Err(e),
}
},
Ok(file) => Ok(Some(file))
}
} }
fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> { fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {

View file

@ -18,15 +18,17 @@
// //
use std::path::PathBuf; use std::path::PathBuf;
use error::StoreError as SE;
use error::StoreErrorKind as SEK;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::Arc; use std::sync::Arc;
use std::ops::Deref; use std::ops::Deref;
use libimagerror::errors::ErrorMsg as EM;
use failure::Fallible as Result;
use failure::Error;
use super::FileAbstraction; use super::FileAbstraction;
use super::FileAbstractionInstance; use super::FileAbstractionInstance;
use super::Drain; use super::Drain;
@ -62,21 +64,21 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
/** /**
* Get the mutable file behind a InMemoryFileAbstraction object * Get the mutable file behind a InMemoryFileAbstraction object
*/ */
fn get_file_content(&mut self, _: StoreId) -> Result<Entry, SE> { fn get_file_content(&mut self, _: StoreId) -> Result<Option<Entry>> {
debug!("Getting lazy file: {:?}", self); debug!("Getting lazy file: {:?}", self);
self.fs_abstraction self.fs_abstraction
.lock() .lock()
.map_err(|_| SE::from_kind(SEK::LockError)) .map_err(|_| Error::from(EM::LockError))
.and_then(|mut mtx| { .map(|mut mtx| {
mtx.get_mut() mtx.get_mut()
.get(&self.absent_path) .get(&self.absent_path)
.cloned() .cloned()
.ok_or_else(|| SE::from_kind(SEK::FileNotFound))
}) })
.map_err(Error::from)
} }
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> { fn write_file_content(&mut self, buf: &Entry) -> Result<()> {
match *self { match *self {
InMemoryFileAbstractionInstance { ref absent_path, .. } => { InMemoryFileAbstractionInstance { ref absent_path, .. } => {
let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed"); let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
@ -99,18 +101,19 @@ impl InMemoryFileAbstraction {
&self.virtual_filesystem &self.virtual_filesystem
} }
fn backend_cloned<'a>(&'a self) -> Result<HashMap<PathBuf, Entry>, SE> { fn backend_cloned<'a>(&'a self) -> Result<HashMap<PathBuf, Entry>> {
self.virtual_filesystem self.virtual_filesystem
.lock() .lock()
.map_err(|_| SE::from_kind(SEK::LockError)) .map_err(|_| Error::from(EM::LockError))
.map(|mtx| mtx.deref().borrow().clone()) .map(|mtx| mtx.deref().borrow().clone())
.into()
} }
} }
impl FileAbstraction for InMemoryFileAbstraction { impl FileAbstraction for InMemoryFileAbstraction {
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> { fn remove_file(&self, path: &PathBuf) -> Result<()> {
debug!("Removing: {:?}", path); debug!("Removing: {:?}", path);
self.backend() self.backend()
.lock() .lock()
@ -118,43 +121,43 @@ impl FileAbstraction for InMemoryFileAbstraction {
.get_mut() .get_mut()
.remove(path) .remove(path)
.map(|_| ()) .map(|_| ())
.ok_or_else(|| SE::from_kind(SEK::FileNotFound)) .ok_or_else(|| EM::FileNotFound.into())
} }
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> { fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
debug!("Copying : {:?} -> {:?}", from, to); debug!("Copying : {:?} -> {:?}", from, to);
let mut mtx = self.backend().lock().expect("Locking Mutex failed"); let mut mtx = self.backend().lock().expect("Locking Mutex failed");
let backend = mtx.get_mut(); let backend = mtx.get_mut();
let a = backend.get(from).cloned().ok_or_else(|| SE::from_kind(SEK::FileNotFound))?; let a = backend.get(from).cloned().ok_or_else(|| EM::FileNotFound)?;
backend.insert(to.clone(), a); backend.insert(to.clone(), a);
debug!("Copying: {:?} -> {:?} worked", from, to); debug!("Copying: {:?} -> {:?} worked", from, to);
Ok(()) Ok(())
} }
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> { fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
debug!("Renaming: {:?} -> {:?}", from, to); debug!("Renaming: {:?} -> {:?}", from, to);
let mut mtx = self.backend().lock().expect("Locking Mutex failed"); let mut mtx = self.backend().lock().expect("Locking Mutex failed");
let backend = mtx.get_mut(); let backend = mtx.get_mut();
let a = backend.remove(from).ok_or_else(|| SE::from_kind(SEK::FileNotFound))?; let a = backend.get(from).cloned().ok_or_else(|| EM::FileNotFound)?;
backend.insert(to.clone(), a); backend.insert(to.clone(), a);
debug!("Renaming: {:?} -> {:?} worked", from, to); debug!("Renaming: {:?} -> {:?} worked", from, to);
Ok(()) Ok(())
} }
fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE> { fn create_dir_all(&self, _: &PathBuf) -> Result<()> {
Ok(()) Ok(())
} }
fn exists(&self, pb: &PathBuf) -> Result<bool, SE> { fn exists(&self, pb: &PathBuf) -> Result<bool> {
let mut mtx = self.backend().lock().expect("Locking Mutex failed"); let mut mtx = self.backend().lock().expect("Locking Mutex failed");
let backend = mtx.get_mut(); let backend = mtx.get_mut();
Ok(backend.contains_key(pb)) Ok(backend.contains_key(pb))
} }
fn is_file(&self, pb: &PathBuf) -> Result<bool, SE> { fn is_file(&self, pb: &PathBuf) -> Result<bool> {
// Because we only store Entries in the memory-internal backend, we only have to check for // Because we only store Entries in the memory-internal backend, we only have to check for
// existance here, as if a path exists in the inmemory storage, it is always mapped to an // existance here, as if a path exists in the inmemory storage, it is always mapped to an
// entry. hence it is always a path to a file // entry. hence it is always a path to a file
@ -165,13 +168,15 @@ impl FileAbstraction for InMemoryFileAbstraction {
Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p)) Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p))
} }
fn drain(&self) -> Result<Drain, SE> { fn drain(&self) -> Result<Drain> {
self.backend_cloned().map(Drain::new) self.backend_cloned().map(Drain::new)
} }
fn fill<'a>(&'a mut self, mut d: Drain) -> Result<(), SE> { fn fill<'a>(&'a mut self, mut d: Drain) -> Result<()> {
debug!("Draining into : {:?}", self); debug!("Draining into : {:?}", self);
let mut mtx = self.backend().lock().map_err(|_| SEK::LockError)?; let mut mtx = self.backend()
.lock()
.map_err(|_| EM::LockError)?;
let backend = mtx.get_mut(); let backend = mtx.get_mut();
for (path, element) in d.iter() { for (path, element) in d.iter() {
@ -182,17 +187,17 @@ impl FileAbstraction for InMemoryFileAbstraction {
Ok(()) Ok(())
} }
fn pathes_recursively(&self, _basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator, SE> { fn pathes_recursively(&self, _basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator> {
trace!("Building PathIterator object (inmemory implementation)"); trace!("Building PathIterator object (inmemory implementation)");
let keys : Vec<PathBuf> = self let keys : Vec<PathBuf> = self
.backend() .backend()
.lock() .lock()
.map_err(|_| SE::from_kind(SEK::FileError))? .map_err(|_| EM::LockError)?
.get_mut() .get_mut()
.keys() .keys()
.map(PathBuf::from) .map(PathBuf::from)
.map(Ok) .map(Ok)
.collect::<Result<_, SE>>()?; // we have to collect() because of the lock() above. .collect::<Result<_>>()?; // we have to collect() because of the lock() above.
Ok(PathIterator::new(Box::new(InMemPathIterBuilder(keys)), storepath, backend)) Ok(PathIterator::new(Box::new(InMemPathIterBuilder(keys)), storepath, backend))
} }
@ -201,7 +206,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
pub(crate) struct InMemPathIterBuilder(Vec<PathBuf>); pub(crate) struct InMemPathIterBuilder(Vec<PathBuf>);
impl PathIterBuilder for InMemPathIterBuilder { impl PathIterBuilder for InMemPathIterBuilder {
fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf, SE>>> { fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>> {
Box::new(self.0.clone().into_iter().map(Ok)) Box::new(self.0.clone().into_iter().map(Ok))
} }

View file

@ -20,7 +20,8 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use error::Result; use failure::Fallible as Result;
use storeid::StoreId; use storeid::StoreId;
use file_abstraction::FileAbstraction; use file_abstraction::FileAbstraction;

View file

@ -22,7 +22,8 @@ use std::fmt::Debug;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use error::StoreError as SE; use failure::Fallible as Result;
use store::Entry; use store::Entry;
use storeid::StoreId; use storeid::StoreId;
@ -38,20 +39,20 @@ use self::iter::PathIterator;
/// An abstraction trait over filesystem actions /// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug { pub trait FileAbstraction : Debug {
fn remove_file(&self, path: &PathBuf) -> Result<(), SE>; fn remove_file(&self, path: &PathBuf) -> Result<()>;
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>; fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>; fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE>; fn create_dir_all(&self, _: &PathBuf) -> Result<()>;
fn exists(&self, &PathBuf) -> Result<bool, SE>; fn exists(&self, &PathBuf) -> Result<bool>;
fn is_file(&self, &PathBuf) -> Result<bool, SE>; fn is_file(&self, &PathBuf) -> Result<bool>;
fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>; fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>;
fn drain(&self) -> Result<Drain, SE>; fn drain(&self) -> Result<Drain>;
fn fill<'a>(&'a mut self, d: Drain) -> Result<(), SE>; fn fill<'a>(&'a mut self, d: Drain) -> Result<()>;
fn pathes_recursively(&self, basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator, SE>; fn pathes_recursively(&self, basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator>;
} }
/// An abstraction trait over actions on files /// An abstraction trait over actions on files
@ -61,8 +62,8 @@ pub trait FileAbstractionInstance : Debug {
/// ///
/// The `StoreId` is passed because the backend does not know where the Entry lives, but the /// The `StoreId` is passed because the backend does not know where the Entry lives, but the
/// Entry type itself must be constructed with the id. /// Entry type itself must be constructed with the id.
fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE>; fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>>;
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE>; fn write_file_content(&mut self, buf: &Entry) -> Result<()>;
} }
pub struct Drain(HashMap<PathBuf, Entry>); pub struct Drain(HashMap<PathBuf, Entry>);
@ -119,7 +120,7 @@ version = "{}"
Hello World"#, env!("CARGO_PKG_VERSION"))).unwrap(); Hello World"#, env!("CARGO_PKG_VERSION"))).unwrap();
lf.write_file_content(&file).unwrap(); lf.write_file_content(&file).unwrap();
let bah = lf.get_file_content(loca).unwrap(); let bah = lf.get_file_content(loca).unwrap().unwrap();
assert_eq!(bah.get_content(), "Hello World"); assert_eq!(bah.get_content(), "Hello World");
} }
@ -140,7 +141,7 @@ Hello World
baz"#, env!("CARGO_PKG_VERSION"))).unwrap(); baz"#, env!("CARGO_PKG_VERSION"))).unwrap();
lf.write_file_content(&file).unwrap(); lf.write_file_content(&file).unwrap();
let bah = lf.get_file_content(loca).unwrap(); let bah = lf.get_file_content(loca).unwrap().unwrap();
assert_eq!(bah.get_content(), "Hello World\nbaz"); assert_eq!(bah.get_content(), "Hello World\nbaz");
} }
@ -163,7 +164,7 @@ baz
"#, env!("CARGO_PKG_VERSION"))).unwrap(); "#, env!("CARGO_PKG_VERSION"))).unwrap();
lf.write_file_content(&file).unwrap(); lf.write_file_content(&file).unwrap();
let bah = lf.get_file_content(loca).unwrap(); let bah = lf.get_file_content(loca).unwrap().unwrap();
assert_eq!(bah.get_content(), "Hello World\nbaz\n\n"); assert_eq!(bah.get_content(), "Hello World\nbaz\n\n");
} }

View file

@ -31,41 +31,34 @@ macro_rules! mk_iterator_mod {
#[allow(unused_imports)] #[allow(unused_imports)]
use store::FileLockEntry; use store::FileLockEntry;
use store::Store; use store::Store;
use error::StoreError; use failure::Fallible as Result;
use std::result::Result as RResult;
pub struct $itername<'a, E>(Box<Iterator<Item = RResult<StoreId, E>> + 'a>, &'a Store) pub struct $itername<'a>(Box<Iterator<Item = Result<StoreId>> + 'a>, &'a Store);
where E: From<StoreError>;
impl<'a, E> $itername<'a, E> impl<'a> $itername<'a>
where E: From<StoreError>
{ {
pub fn new(inner: Box<Iterator<Item = RResult<StoreId, E>> + 'a>, store: &'a Store) -> Self { pub fn new(inner: Box<Iterator<Item = Result<StoreId>> + 'a>, store: &'a Store) -> Self {
$itername(inner, store) $itername(inner, store)
} }
} }
impl<'a, E> Iterator for $itername<'a, E> impl<'a> Iterator for $itername<'a>
where E: From<StoreError>
{ {
type Item = RResult<$yield, E>; type Item = Result<$yield>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|id| $fun(id?, self.1).map_err(E::from)) self.0.next().map(|id| $fun(id?, self.1))
} }
} }
pub trait $extname<'a, E> pub trait $extname<'a> {
where E: From<StoreError> fn $extfnname(self, store: &'a Store) -> $itername<'a>;
{
fn $extfnname(self, store: &'a Store) -> $itername<'a, E>;
} }
impl<'a, I, E> $extname<'a, E> for I impl<'a, I> $extname<'a> for I
where I: Iterator<Item = RResult<StoreId, E>> + 'a, where I: Iterator<Item = Result<StoreId>> + 'a
E: From<StoreError>
{ {
fn $extfnname(self, store: &'a Store) -> $itername<'a, E> { fn $extfnname(self, store: &'a Store) -> $itername<'a> {
$itername(Box::new(self), store) $itername(Box::new(self), store)
} }
} }
@ -151,8 +144,7 @@ use self::get::StoreGetIterator;
use self::retrieve::StoreRetrieveIterator; use self::retrieve::StoreRetrieveIterator;
use file_abstraction::iter::PathIterator; use file_abstraction::iter::PathIterator;
use store::Store; use store::Store;
use error::StoreError; use failure::Fallible as Result;
use error::Result;
/// Iterator for iterating over all (or a subset of all) entries /// Iterator for iterating over all (or a subset of all) entries
/// ///
@ -194,21 +186,21 @@ impl<'a> Entries<'a> {
/// Transform the iterator into a StoreDeleteIterator /// Transform the iterator into a StoreDeleteIterator
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_delete_iter(self) -> StoreDeleteIterator<'a, StoreError> { pub fn into_delete_iter(self) -> StoreDeleteIterator<'a> {
StoreDeleteIterator::new(Box::new(self.0), self.1) StoreDeleteIterator::new(Box::new(self.0), self.1)
} }
/// Transform the iterator into a StoreGetIterator /// Transform the iterator into a StoreGetIterator
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_get_iter(self) -> StoreGetIterator<'a, StoreError> { pub fn into_get_iter(self) -> StoreGetIterator<'a> {
StoreGetIterator::new(Box::new(self.0), self.1) StoreGetIterator::new(Box::new(self.0), self.1)
} }
/// Transform the iterator into a StoreRetrieveIterator /// Transform the iterator into a StoreRetrieveIterator
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a, StoreError> { pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a> {
StoreRetrieveIterator::new(Box::new(self.0), self.1) StoreRetrieveIterator::new(Box::new(self.0), self.1)
} }

View file

@ -44,7 +44,7 @@ extern crate semver;
extern crate walkdir; extern crate walkdir;
#[macro_use] extern crate is_match; #[macro_use] extern crate is_match;
extern crate serde_json; extern crate serde_json;
#[macro_use] extern crate error_chain; #[macro_use] extern crate failure;
extern crate toml_query; extern crate toml_query;
extern crate libimagerror; extern crate libimagerror;
@ -53,7 +53,6 @@ extern crate libimagutil;
#[macro_use] mod util; #[macro_use] mod util;
pub mod storeid; pub mod storeid;
pub mod error;
pub mod iter; pub mod iter;
pub mod store; pub mod store;
mod configuration; mod configuration;

View file

@ -31,12 +31,16 @@ use std::fmt::Formatter;
use std::fmt::Debug; use std::fmt::Debug;
use std::fmt::Error as FMTError; use std::fmt::Error as FMTError;
use libimagerror::errors::ErrorMsg as EM;
use toml::Value; use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use failure::Fallible as Result;
use failure::ResultExt;
use failure::err_msg;
use failure::Error;
use error::{StoreError as SE, StoreErrorKind as SEK};
use error::ResultExt;
use storeid::{IntoStoreId, StoreId}; use storeid::{IntoStoreId, StoreId};
use iter::Entries; use iter::Entries;
use file_abstraction::FileAbstractionInstance; use file_abstraction::FileAbstractionInstance;
@ -48,9 +52,6 @@ pub use file_abstraction::InMemoryFileAbstraction;
use libimagutil::debug_result::*; use libimagutil::debug_result::*;
/// The Result Type returned by any interaction with the store that could fail
pub type Result<T> = RResult<T, SE>;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum StoreEntryStatus { enum StoreEntryStatus {
@ -76,7 +77,7 @@ impl StoreEntry {
{ {
open_file(pb.clone()) open_file(pb.clone())
.and_then(|f| f.lock_exclusive()) .and_then(|f| f.lock_exclusive())
.chain_err(|| SEK::IoError)?; .with_context(|| EM::IO)?;
} }
Ok(StoreEntry { Ok(StoreEntry {
@ -94,15 +95,12 @@ impl StoreEntry {
fn get_entry(&mut self) -> Result<Entry> { fn get_entry(&mut self) -> Result<Entry> {
if !self.is_borrowed() { if !self.is_borrowed() {
self.file match self.file.get_file_content(self.id.clone())? {
.get_file_content(self.id.clone()) Some(file) => Ok(file),
.or_else(|err| if is_match!(err.kind(), &SEK::FileNotFound) { None => Ok(Entry::new(self.id.clone()))
Ok(Entry::new(self.id.clone())) }
} else { } else {
Err(err) Err(format_err!("EntryAlreadyBorrowed: {}", self.id))
})
} else {
Err(SE::from_kind(SEK::EntryAlreadyBorrowed(self.id.clone())))
} }
} }
@ -184,18 +182,19 @@ impl Store {
debug!("Building new Store object"); debug!("Building new Store object");
if !location.exists() { if !location.exists() {
if !config_implicit_store_create_allowed(store_config)? { if !config_implicit_store_create_allowed(store_config)? {
return Err(SE::from_kind(SEK::CreateStoreDirDenied)) return Err(format_err!("CreateStoreDirDenied"))
.chain_err(|| SEK::FileError) .context(EM::FileError)
.chain_err(|| SEK::IoError); .context(EM::IO)
.map_err(Error::from)
} }
backend backend
.create_dir_all(&location) .create_dir_all(&location)
.chain_err(|| SEK::StorePathCreate(location.clone())) .context(format_err!("StorePathCreate: {}", location.display()))
.map_dbg_err_str("Failed")?; .map_dbg_err_str("Failed")?;
} else if location.is_file() { } else if location.is_file() {
debug!("Store path exists as file"); debug!("Store path exists as file");
return Err(SE::from_kind(SEK::StorePathExists(location))); return Err(format_err!("StorePathExists: {}", location.display()));
} }
let store = Store { let store = Store {
@ -218,45 +217,34 @@ impl Store {
/// ///
/// On success: FileLockEntry /// On success: FileLockEntry
/// ///
/// On error:
/// - Errors StoreId::into_storeid() might return
/// - EntryAlreadyExists(id) if the entry exists
/// - CreateCallError(LockPoisoned()) if the internal lock is poisened.
/// - CreateCallError(EntryAlreadyExists()) if the entry exists already.
///
pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> { pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
let id = id.into_storeid()?.with_base(self.path().clone()); let id = id.into_storeid()?.with_base(self.path().clone());
debug!("Creating id: '{}'", id); debug!("Creating id: '{}'", id);
let exists = self.entries let exists = id.exists()? || self.entries
.read() .read()
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
.map(|map| map.contains_key(&id)) .map(|map| map.contains_key(&id))
.and_then(|exists| if exists { .map_err(|_| Error::from(EM::LockError))
Ok(exists) .context(format_err!("CreateCallError: {}", id))?;
} else {
let pb = id.clone().into_pathbuf().map_err(SE::from)?;
self.backend.exists(&pb)
})
.chain_err(|| SEK::CreateCallError(id.clone()))?;
if exists { if exists {
debug!("Entry exists: {:?}", id); debug!("Entry exists: {:?}", id);
return Err(SEK::EntryAlreadyExists(id).into()); return Err(format_err!("EntryAlreadyExists: {}", id));
} }
{ {
let mut hsmap = self let mut hsmap = self
.entries .entries
.write() .write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned)) .map_err(|_| Error::from(EM::LockError))
.chain_err(|| SEK::CreateCallError(id.clone()))?; .context(format_err!("CreateCallError: {}", id))?;
if hsmap.contains_key(&id) { if hsmap.contains_key(&id) {
debug!("Cannot create, internal cache already contains: '{}'", id); debug!("Cannot create, internal cache already contains: '{}'", id);
return Err(SE::from_kind(SEK::EntryAlreadyExists(id.clone()))) return Err(format_err!("EntryAlreadyExists: {}", id))
.chain_err(|| SEK::CreateCallError(id.clone())); .context(format_err!("CreateCallError: {}", id))
.map_err(Error::from)
} }
hsmap.insert(id.clone(), { hsmap.insert(id.clone(), {
debug!("Creating: '{}'", id); debug!("Creating: '{}'", id);
@ -281,17 +269,13 @@ impl Store {
/// ///
/// On success: FileLockEntry /// On success: FileLockEntry
/// ///
/// On error:
/// - Errors StoreId::into_storeid() might return
/// - RetrieveCallError(LockPoisoned()) if the internal lock is poisened.
///
pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> { pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
let id = id.into_storeid()?.with_base(self.path().clone()); let id = id.into_storeid()?.with_base(self.path().clone());
debug!("Retrieving id: '{}'", id); debug!("Retrieving id: '{}'", id);
let entry = self let entry = self
.entries .entries
.write() .write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned)) .map_err(|_| Error::from(EM::LockError))
.and_then(|mut es| { .and_then(|mut es| {
let new_se = StoreEntry::new(id.clone(), &self.backend)?; let new_se = StoreEntry::new(id.clone(), &self.backend)?;
let se = es.entry(id.clone()).or_insert(new_se); let se = es.entry(id.clone()).or_insert(new_se);
@ -299,7 +283,7 @@ impl Store {
se.status = StoreEntryStatus::Borrowed; se.status = StoreEntryStatus::Borrowed;
entry entry
}) })
.chain_err(|| SEK::RetrieveCallError(id.clone()))?; .context(format_err!("RetrieveCallError: {}", id))?;
debug!("Constructing FileLockEntry: '{}'", id); debug!("Constructing FileLockEntry: '{}'", id);
Ok(FileLockEntry::new(self, entry)) Ok(FileLockEntry::new(self, entry))
@ -320,24 +304,21 @@ impl Store {
debug!("Getting id: '{}'", id); debug!("Getting id: '{}'", id);
let exists = self.entries let exists = id.exists()? || self.entries
.read() .read()
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
.map(|map| map.contains_key(&id)) .map(|map| map.contains_key(&id))
.and_then(|exists| if exists { .map_err(|_| Error::from(EM::LockError))
Ok(exists) .context(format_err!("GetCallError: {}", id))?;
} else {
let pb = id.clone().into_pathbuf().map_err(SE::from)?;
self.backend.exists(&pb)
})
.chain_err(|| SEK::GetCallError(id.clone()))?;
if !exists { if !exists {
debug!("Does not exist in internal cache or filesystem: {:?}", id); debug!("Does not exist in internal cache or filesystem: {:?}", id);
return Ok(None); return Ok(None);
} }
self.retrieve(id.clone()).map(Some).chain_err(|| SEK::GetCallError(id)) self.retrieve(id.clone())
.map(Some)
.context(format_err!("GetCallError: {}", id))
.map_err(Error::from)
} }
/// Write (update) the `FileLockEntry` to disk /// Write (update) the `FileLockEntry` to disk
@ -346,15 +327,11 @@ impl Store {
/// ///
/// On success: Entry /// On success: Entry
/// ///
/// On error:
/// - UpdateCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - IdNotFound() if the entry was not found in the stor
/// - Errors Entry::verify() might return
/// - Errors StoreEntry::write_entry() might return
///
pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> { pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> {
debug!("Updating FileLockEntry at '{}'", entry.get_location()); debug!("Updating FileLockEntry at '{}'", entry.get_location());
self._update(entry, false).chain_err(|| SEK::UpdateCallError(entry.get_location().clone())) self._update(entry, false)
.context(format_err!("UpdateCallError: {}", entry.get_location()))
.map_err(Error::from)
} }
/// Internal method to write to the filesystem store. /// Internal method to write to the filesystem store.
@ -365,10 +342,11 @@ impl Store {
/// it is not public. /// it is not public.
/// ///
fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> { fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; let mut hsmap = self.entries.write()
.map_err(|_| Error::from(EM::LockError))?;
let se = hsmap.get_mut(&entry.location).ok_or_else(|| { let se = hsmap.get_mut(&entry.location).ok_or_else(|| {
SE::from_kind(SEK::IdNotFound(entry.location.clone())) EM::EntryNotFound(entry.location.local_display_string())
})?; })?;
assert!(se.is_borrowed(), "Tried to update a non borrowed entry."); assert!(se.is_borrowed(), "Tried to update a non borrowed entry.");
@ -401,7 +379,8 @@ impl Store {
pub fn flush_cache(&self) -> Result<()> { pub fn flush_cache(&self) -> Result<()> {
// We borrow this early so that between the aggregation of the flushables and the actual // We borrow this early so that between the aggregation of the flushables and the actual
// flush, there is no borrowing from the store. // flush, there is no borrowing from the store.
let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; let mut hsmap = self.entries.write()
.map_err(|_| Error::from(EM::LockError))?;
let mut to_flush = vec![]; let mut to_flush = vec![];
for (storeid, se) in hsmap.deref() { for (storeid, se) in hsmap.deref() {
@ -421,37 +400,34 @@ impl Store {
/// The number of elements in the internal cache /// The number of elements in the internal cache
pub fn cache_size(&self) -> Result<usize> { pub fn cache_size(&self) -> Result<usize> {
let hsmap = self.entries.read().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; let hsmap = self.entries.read().map_err(|_| Error::from(EM::LockError))?;
Ok(hsmap.iter().count()) Ok(hsmap.iter().count())
} }
/// The size of the internal cache /// The size of the internal cache
pub fn cache_capacity(&self) -> Result<usize> { pub fn cache_capacity(&self) -> Result<usize> {
let hsmap = self.entries.read().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; let hsmap = self.entries.read().map_err(|_| Error::from(EM::LockError))?;
Ok(hsmap.capacity()) Ok(hsmap.capacity())
} }
/// Get a copy of a given entry, this cannot be used to mutate the one on disk // Get a copy of a given entry, this cannot be used to mutate the one on disk
/// ///
/// # Return value /// # Return value
/// ///
/// On success: Entry /// On success: Entry
/// ///
/// On error:
/// - RetrieveCopyCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - RetrieveCopyCallError(IdLocked()) if the Entry is borrowed currently
/// - Errors StoreEntry::new() might return
///
pub fn get_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> { pub fn get_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
let id = id.into_storeid()?.with_base(self.path().clone()); let id = id.into_storeid()?.with_base(self.path().clone());
debug!("Retrieving copy of '{}'", id); debug!("Retrieving copy of '{}'", id);
let entries = self.entries.write() let entries = self.entries.write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned)) .map_err(|_| Error::from(EM::LockError))
.chain_err(|| SEK::RetrieveCopyCallError(id.clone()))?; .context(format_err!("RetrieveCopyCallError: {}", id))?;
// if the entry is currently modified by the user, we cannot drop it // if the entry is currently modified by the user, we cannot drop it
if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) { if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) {
return Err(SE::from_kind(SEK::IdLocked)).chain_err(|| SEK::RetrieveCopyCallError(id)); return Err(EM::IdLocked)
.context(format_err!("RetrieveCopyCallError: {}", id))
.map_err(Error::from)
} }
StoreEntry::new(id, &self.backend)?.get_entry() StoreEntry::new(id, &self.backend)?.get_entry()
@ -463,27 +439,29 @@ impl Store {
/// ///
/// On success: () /// On success: ()
/// ///
/// On error:
/// - DeleteCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - DeleteCallError(FileNotFound()) if the StoreId refers to a non-existing entry.
/// - DeleteCallError(FileError()) if the internals failed to remove the file.
///
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> { pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
let id = id.into_storeid()?.with_base(self.path().clone()); let id = id.into_storeid()?.with_base(self.path().clone());
debug!("Deleting id: '{}'", id); debug!("Deleting id: '{}'", id);
// Small optimization: We need the pathbuf for deleting, but when calling
// StoreId::exists(), a PathBuf object gets allocated. So we simply get a
// PathBuf here, check whether it is there and if it is, we can re-use it to
// delete the filesystem file.
let pb = id.clone().into_pathbuf()?; let pb = id.clone().into_pathbuf()?;
{ {
let mut entries = self let mut entries = self
.entries .entries
.write() .write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned)) .map_err(|_| Error::from(EM::LockError))
.chain_err(|| SEK::DeleteCallError(id.clone()))?; .context(format_err!("DeleteCallError: {}", id))?;
let do_remove = match entries.get(&id) { let do_remove = match entries.get(&id) {
Some(e) => if e.is_borrowed() { // entry is currently borrowed, we cannot delete it Some(e) => if e.is_borrowed() { // entry is currently borrowed, we cannot delete it
return Err(SE::from_kind(SEK::IdLocked)).chain_err(|| SEK::DeleteCallError(id)); return Err(Error::from(EM::LockError))
.context(format_err!("DeleteCallError: {}", id))
.map_err(Error::from)
// false // false
} else { // Entry is in the cache } else { // Entry is in the cache
// Remove Entry from the cache // Remove Entry from the cache
@ -496,8 +474,9 @@ impl Store {
if !self.backend.exists(&pb)? { if !self.backend.exists(&pb)? {
debug!("Seems like {:?} is not even on the FS", pb); debug!("Seems like {:?} is not even on the FS", pb);
return Err(SE::from_kind(SEK::FileNotFound)) return Err(EM::FileNotFound)
.chain_err(|| SEK::DeleteCallError(id)) .context(format_err!("DeleteCallError: {}", id))
.map_err(Error::from)
} // else { continue } } // else { continue }
false false
@ -513,8 +492,8 @@ impl Store {
let _ = self let _ = self
.backend .backend
.remove_file(&pb) .remove_file(&pb)
.chain_err(|| SEK::FileError) .context(EM::FileError)
.chain_err(|| SEK::DeleteCallError(id))?; .context(format_err!("DeleteCallError: {}", id))?;
debug!("Deleted"); debug!("Deleted");
Ok(()) Ok(())
@ -540,12 +519,13 @@ impl Store {
let hsmap = self let hsmap = self
.entries .entries
.write() .write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned)) .map_err(|_| Error::from(EM::LockError))
.chain_err(|| SEK::MoveCallError(entry.get_location().clone(), new_id.clone()))?; .context(format_err!("MoveCallError: {} -> {}", entry.get_location(), new_id))?;
if hsmap.contains_key(&new_id) { if hsmap.contains_key(&new_id) {
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone()))) return Err(format_err!("Entry exists already: {}", new_id.clone()))
.chain_err(|| SEK::MoveCallError(entry.get_location().clone(), new_id.clone())) .context(format_err!("MoveCallError: {} -> {}", entry.get_location(), new_id))
.map_err(Error::from)
} }
let old_id = entry.get_location().clone(); let old_id = entry.get_location().clone();
@ -560,8 +540,9 @@ impl Store {
} else { } else {
Ok(()) Ok(())
}) })
.chain_err(|| SEK::FileError) .context(EM::FileError)
.chain_err(|| SEK::MoveCallError(old_id, new_id)) .context(format_err!("MoveCallError: {} -> {}", old_id, new_id))
.map_err(Error::from)
} }
/// Move an entry without loading /// Move an entry without loading
@ -604,10 +585,11 @@ impl Store {
debug!("Moving '{}' to '{}'", old_id, new_id); debug!("Moving '{}' to '{}'", old_id, new_id);
{ {
let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; let mut hsmap = self.entries.write()
.map_err(|_| Error::from(EM::LockError))?;
if hsmap.contains_key(&new_id) { if hsmap.contains_key(&new_id) {
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone()))); return Err(format_err!("Entry already exists: {}", new_id));
} }
debug!("New id does not exist in cache"); debug!("New id does not exist in cache");
@ -615,7 +597,7 @@ impl Store {
// if we have one, but it is borrowed, we really should not rename it, as this might // if we have one, but it is borrowed, we really should not rename it, as this might
// lead to strange errors // lead to strange errors
if hsmap.get(&old_id).map(|e| e.is_borrowed()).unwrap_or(false) { if hsmap.get(&old_id).map(|e| e.is_borrowed()).unwrap_or(false) {
return Err(SE::from_kind(SEK::EntryAlreadyBorrowed(old_id.clone()))); return Err(format_err!("Entry already borrowed: {}", old_id));
} }
debug!("Old id is not yet borrowed"); debug!("Old id is not yet borrowed");
@ -624,14 +606,18 @@ impl Store {
let new_id_pb = new_id.clone().with_base(self.path().clone()).into_pathbuf()?; let new_id_pb = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
if self.backend.exists(&new_id_pb)? { if self.backend.exists(&new_id_pb)? {
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone()))); return Err(format_err!("Entry already exists: {}", new_id));
} }
debug!("New entry does not yet exist on filesystem. Good."); debug!("New entry does not yet exist on filesystem. Good.");
let _ = self let _ = self
.backend .backend
.rename(&old_id_pb, &new_id_pb) .rename(&old_id_pb, &new_id_pb)
.chain_err(|| SEK::EntryRenameError(old_id_pb, new_id_pb))?; .context({
let old = old_id_pb.display().to_string();
let new = new_id_pb.display().to_string();
format_err!("Rename error: {} -> {}", old, new)
})?;
debug!("Rename worked on filesystem"); debug!("Rename worked on filesystem");
@ -792,7 +778,7 @@ impl Entry {
pub fn from_reader<S: IntoStoreId>(loc: S, file: &mut Read) -> Result<Entry> { pub fn from_reader<S: IntoStoreId>(loc: S, file: &mut Read) -> Result<Entry> {
let text = { let text = {
let mut s = String::new(); let mut s = String::new();
file.read_to_string(&mut s)?; file.read_to_string(&mut s).context(EM::IO)?;
s s
}; };
Self::from_str(loc, &text[..]) Self::from_str(loc, &text[..])
@ -828,7 +814,9 @@ impl Entry {
/// disk). /// disk).
pub fn to_str(&self) -> Result<String> { pub fn to_str(&self) -> Result<String> {
Ok(format!("---\n{header}---\n{content}", Ok(format!("---\n{header}---\n{content}",
header = ::toml::ser::to_string_pretty(&self.header)?, header = ::toml::ser::to_string_pretty(&self.header)
.map_err(Error::from)
.context(err_msg("TOML Error"))?,
content = self.content)) content = self.content))
} }
@ -872,12 +860,12 @@ impl Entry {
/// Currently, this only verifies the header. This might change in the future. /// Currently, this only verifies the header. This might change in the future.
pub fn verify(&self) -> Result<()> { pub fn verify(&self) -> Result<()> {
if !has_main_section(&self.header)? { if !has_main_section(&self.header)? {
Err(SE::from_kind(SEK::MissingMainSection)) Err(format_err!("MissingMainSection"))
} else if !has_imag_version_in_main_section(&self.header)? { } else if !has_imag_version_in_main_section(&self.header)? {
Err(SE::from_kind(SEK::MissingVersionInfo)) Err(format_err!("MissingVersionInfo"))
} else if !has_only_tables(&self.header)? { } else if !has_only_tables(&self.header)? {
debug!("Could not verify that it only has tables in its base table"); debug!("Could not verify that it only has tables in its base table");
Err(SE::from_kind(SEK::NonTableInBaseTable)) Err(format_err!("NonTableInBaseTable"))
} else { } else {
Ok(()) Ok(())
} }
@ -899,21 +887,26 @@ fn has_only_tables(t: &Value) -> Result<bool> {
debug!("Verifying that table has only tables"); debug!("Verifying that table has only tables");
match *t { match *t {
Value::Table(ref tab) => Ok(tab.iter().all(|(_, x)| is_match!(*x, Value::Table(_)))), Value::Table(ref tab) => Ok(tab.iter().all(|(_, x)| is_match!(*x, Value::Table(_)))),
_ => Err(SE::from_kind(SEK::HeaderTypeFailure)), _ => Err(format_err!("HeaderTypeFailure")),
} }
} }
fn has_main_section(t: &Value) -> Result<bool> { fn has_main_section(t: &Value) -> Result<bool> {
t.read("imag")? t.read("imag")
.ok_or_else(|| SE::from_kind(SEK::ConfigKeyMissingError("imag"))) .map_err(Error::from)
.context(EM::TomlQueryError)?
.ok_or_else(|| format_err!("ConfigKeyMissingError('imag')"))
.map(Value::is_table) .map(Value::is_table)
} }
fn has_imag_version_in_main_section(t: &Value) -> Result<bool> { fn has_imag_version_in_main_section(t: &Value) -> Result<bool> {
t.read_string("imag.version")? t.read_string("imag.version")
.ok_or_else(|| SE::from_kind(SEK::ConfigKeyMissingError("imag.version"))) .map_err(Error::from)
.context(EM::TomlQueryError)?
.ok_or_else(|| format_err!("ConfigKeyMissingError('imag.version')"))
.map_err(Error::from)
.map(String::from) .map(String::from)
.map(|s| ::semver::Version::parse(&s).is_ok()) .map(|s: String| ::semver::Version::parse(&s).is_ok())
} }
@ -1095,14 +1088,12 @@ mod store_tests {
#[test] #[test]
fn test_store_create_twice() { fn test_store_create_twice() {
use error::StoreErrorKind as SEK;
let store = get_store(); let store = get_store();
for n in 1..100 { for n in 1..100 {
let s = format!("test-{}", n % 50); let s = format!("test-{}", n % 50);
store.create(PathBuf::from(s.clone())) store.create(PathBuf::from(s.clone()))
.map_err(|e| assert!(is_match!(e.kind(), &SEK::EntryAlreadyExists(_)) && n >= 50))
.ok() .ok()
.map(|entry| { .map(|entry| {
assert!(entry.verify().is_ok()); assert!(entry.verify().is_ok());
@ -1190,8 +1181,8 @@ mod store_tests {
assert!(store.create(id.clone()).is_ok()); assert!(store.create(id.clone()).is_ok());
} }
let id_with_base = id.clone().with_base(store.path().clone());
{ {
let id_with_base = id.clone().with_base(store.path().clone());
assert!(store.entries.read().unwrap().get(&id_with_base).is_some()); assert!(store.entries.read().unwrap().get(&id_with_base).is_some());
} }
@ -1203,16 +1194,8 @@ mod store_tests {
assert!(store.entries.read().unwrap().get(&id_mv_with_base).is_some()); assert!(store.entries.read().unwrap().get(&id_mv_with_base).is_some());
} }
{ assert!(match store.get(id.clone()) { Ok(None) => true, _ => false },
let pb = id_with_base.into_pathbuf().unwrap(); "Moved id ({:?}) is still there", id);
let exists = store.backend.exists(&pb).unwrap();
assert!(!exists, "Old entry exists in Filesystem, but shouldn't");
}
let result = store.get(id.clone());
assert!(match result { Ok(None) => true, _ => false },
"Moved id ({:?}) is still there: {:?}", id, result);
assert!(match store.get(id_mv.clone()) { Ok(Some(_)) => true, _ => false }, assert!(match store.get(id_mv.clone()) { Ok(Some(_)) => true, _ => false },
"New id ({:?}) is not in store...", id_mv); "New id ({:?}) is not in store...", id_mv);
} }

View file

@ -26,10 +26,11 @@ use std::fmt::Error as FmtError;
use std::result::Result as RResult; use std::result::Result as RResult;
use std::path::Components; use std::path::Components;
use error::StoreErrorKind as SEK; use failure::ResultExt;
use error::StoreError as SE; use failure::Fallible as Result;
use error::ResultExt; use failure::err_msg;
use store::Result; use failure::Error;
use store::Store; use store::Store;
use iter::create::StoreCreateIterator; use iter::create::StoreCreateIterator;
@ -64,14 +65,13 @@ impl StoreId {
/// ///
/// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
/// the `store_part` from the `full_path` succeeded. /// the `store_part` from the `full_path` succeeded.
///
/// Returns a `StoreErrorKind::StoreIdBuildFromFullPathError` if stripping failes.
pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId> pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId>
where D: Deref<Target = Path> where D: Deref<Target = Path>
{ {
let p = full_path let p = full_path
.strip_prefix(store_part) .strip_prefix(store_part)
.chain_err(|| SEK::StoreIdBuildFromFullPathError)?; .map_err(Error::from)
.context(err_msg("Error building Store Id from full path"))?;
StoreId::new(Some(store_part.clone()), PathBuf::from(p)) StoreId::new(Some(store_part.clone()), PathBuf::from(p))
} }
@ -79,7 +79,7 @@ impl StoreId {
debug!("Trying to get a new baseless id from: {:?}", id); debug!("Trying to get a new baseless id from: {:?}", id);
if id.is_absolute() { if id.is_absolute() {
debug!("Error: Id is absolute!"); debug!("Error: Id is absolute!");
Err(SE::from_kind(SEK::StoreIdLocalPartAbsoluteError(id))) Err(format_err!("Store Id local part is absolute: {}", id.display()))
} else { } else {
debug!("Building Storeid object baseless"); debug!("Building Storeid object baseless");
Ok(StoreId { Ok(StoreId {
@ -103,7 +103,9 @@ impl StoreId {
/// specified. /// specified.
pub fn into_pathbuf(mut self) -> Result<PathBuf> { pub fn into_pathbuf(mut self) -> Result<PathBuf> {
let base = self.base.take(); let base = self.base.take();
let mut base = base.ok_or_else(|| SEK::StoreIdHasNoBaseError(self.id.clone()))?; let mut base = base.ok_or_else(|| {
format_err!("Store Id has no base: {:?}", self.id.display().to_string())
})?;
base.push(self.id); base.push(self.id);
Ok(base) Ok(base)
} }
@ -125,7 +127,8 @@ impl StoreId {
.unwrap_or_else(|| self.id.clone()) .unwrap_or_else(|| self.id.clone())
.to_str() .to_str()
.map(String::from) .map(String::from)
.ok_or_else(|| SE::from_kind(SEK::StoreIdHandlingError)) .ok_or_else(|| err_msg("Store ID Handling error"))
.map_err(Error::from)
} }
/// Helper function for creating a displayable String from StoreId /// Helper function for creating a displayable String from StoreId
@ -232,7 +235,7 @@ macro_rules! module_entry_path_mod {
use std::path::PathBuf; use std::path::PathBuf;
use $crate::storeid::StoreId; use $crate::storeid::StoreId;
use $crate::store::Result; use failure::Fallible as Result;
/// A Struct giving you the ability to choose store entries assigned /// A Struct giving you the ability to choose store entries assigned
/// to it. /// to it.
@ -313,8 +316,6 @@ impl<'a> Iterator for StoreIdIteratorWithStore<'a> {
} }
} }
use error::StoreError;
impl<'a> StoreIdIteratorWithStore<'a> { impl<'a> StoreIdIteratorWithStore<'a> {
pub fn new(iter: Box<Iterator<Item = Result<StoreId>>>, store: &'a Store) -> Self { pub fn new(iter: Box<Iterator<Item = Result<StoreId>>>, store: &'a Store) -> Self {
@ -328,7 +329,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
/// Transform the iterator into a StoreCreateIterator /// Transform the iterator into a StoreCreateIterator
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_create_iter(self) -> StoreCreateIterator<'a, StoreError> { pub fn into_create_iter(self) -> StoreCreateIterator<'a> {
StoreCreateIterator::new(Box::new(self.0), self.1) StoreCreateIterator::new(Box::new(self.0), self.1)
} }
@ -336,7 +337,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
/// ///
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_delete_iter(self) -> StoreDeleteIterator<'a, StoreError> { pub fn into_delete_iter(self) -> StoreDeleteIterator<'a> {
StoreDeleteIterator::new(Box::new(self.0), self.1) StoreDeleteIterator::new(Box::new(self.0), self.1)
} }
@ -344,7 +345,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
/// ///
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_get_iter(self) -> StoreGetIterator<'a, StoreError> { pub fn into_get_iter(self) -> StoreGetIterator<'a> {
StoreGetIterator::new(Box::new(self.0), self.1) StoreGetIterator::new(Box::new(self.0), self.1)
} }
@ -352,7 +353,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
/// ///
/// ///
/// This immitates the API from `libimagstore::iter`. /// This immitates the API from `libimagstore::iter`.
pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a, StoreError> { pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a> {
StoreRetrieveIterator::new(Box::new(self.0), self.1) StoreRetrieveIterator::new(Box::new(self.0), self.1)
} }
@ -364,7 +365,6 @@ mod test {
use storeid::StoreId; use storeid::StoreId;
use storeid::IntoStoreId; use storeid::IntoStoreId;
use error::StoreErrorKind as SEK;
module_entry_path_mod!("test"); module_entry_path_mod!("test");
@ -444,8 +444,6 @@ mod test {
let pb = id.unwrap().into_pathbuf(); let pb = id.unwrap().into_pathbuf();
assert!(pb.is_err()); assert!(pb.is_err());
assert!(is_match!(pb.unwrap_err().kind(), &SEK::StoreIdHasNoBaseError(_)));
} }
#[test] #[test]

View file

@ -20,8 +20,10 @@
use std::fmt::Write; use std::fmt::Write;
use toml::Value; use toml::Value;
use failure::Fallible as Result;
use failure::ResultExt;
use store::Result; use libimagerror::errors::ErrorMsg as EM;
#[cfg(feature = "early-panic")] #[cfg(feature = "early-panic")]
#[macro_export] #[macro_export]
@ -40,6 +42,7 @@ macro_rules! if_cfg_panic {
} }
pub fn entry_buffer_to_header_content(buf: &str) -> Result<(Value, String)> { pub fn entry_buffer_to_header_content(buf: &str) -> Result<(Value, String)> {
debug!("Building entry from string"); debug!("Building entry from string");
let mut header = String::new(); let mut header = String::new();
let mut content = String::new(); let mut content = String::new();
@ -52,15 +55,16 @@ pub fn entry_buffer_to_header_content(buf: &str) -> Result<(Value, String)> {
header_consumed = true; header_consumed = true;
// do not further process the line // do not further process the line
} else if !header_consumed { } else if !header_consumed {
let _ = writeln!(header, "{}", line)?; let _ = writeln!(header, "{}", line).context(EM::FormatError)?;
} else if iter.peek().is_some() { } else if iter.peek().is_some() {
let _ = writeln!(content, "{}", line)?; let _ = writeln!(content, "{}", line).context(EM::FormatError)?;
} else { } else {
let _ = write!(content, "{}", line)?; let _ = write!(content, "{}", line).context(EM::FormatError)?;
} }
} }
::toml::de::from_str(&header).map_err(From::from).map(|h| (h, content)) let h = ::toml::de::from_str(&header).context(EM::TomlDeserError)?;
Ok((h, content))
} }
#[cfg(test)] #[cfg(test)]

View file

@ -22,7 +22,7 @@ maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
url = "1.5" url = "1.5"
regex = "1" regex = "1"
error-chain = "0.12" failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -26,7 +26,8 @@
use regex::Regex; use regex::Regex;
use error::Result; use failure::Fallible as Result;
use failure::Error;
use module_path::ModuleEntryPath; use module_path::ModuleEntryPath;
use libimagstore::store::Store; use libimagstore::store::Store;
@ -53,22 +54,22 @@ impl<'a> BookmarkCollectionStore<'a> for Store {
fn new(&'a self, name: &str) -> Result<FileLockEntry<'a>> { fn new(&'a self, name: &str) -> Result<FileLockEntry<'a>> {
ModuleEntryPath::new(name) ModuleEntryPath::new(name)
.into_storeid() .into_storeid()
.and_then(|id| self.create(id).map_err(From::from)) .and_then(|id| self.create(id).map_err(Error::from))
.map_err(From::from) .map_err(Error::from)
} }
fn get(&'a self, name: &str) -> Result<Option<FileLockEntry<'a>>> { fn get(&'a self, name: &str) -> Result<Option<FileLockEntry<'a>>> {
ModuleEntryPath::new(name) ModuleEntryPath::new(name)
.into_storeid() .into_storeid()
.and_then(|id| self.get(id).map_err(From::from)) .and_then(|id| self.get(id).map_err(Error::from))
.map_err(From::from) .map_err(Error::from)
} }
fn delete(&'a self, name: &str) -> Result<()> { fn delete(&'a self, name: &str) -> Result<()> {
ModuleEntryPath::new(name) ModuleEntryPath::new(name)
.into_storeid() .into_storeid()
.and_then(|id| self.delete(id).map_err(From::from)) .and_then(|id| self.delete(id).map_err(Error::from))
.map_err(From::from) .map_err(Error::from)
} }
} }
@ -84,47 +85,35 @@ pub trait BookmarkCollection : Sized + InternalLinker + ExternalLinker {
impl BookmarkCollection for Entry { impl BookmarkCollection for Entry {
fn links<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>> { fn links<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>> {
self.get_external_links(store).map_err(From::from) self.get_external_links(store)
} }
fn link_entries(&self) -> Result<Vec<StoreLink>> { fn link_entries(&self) -> Result<Vec<StoreLink>> {
use libimagentrylink::external::is_external_link_storeid; use libimagentrylink::external::is_external_link_storeid;
self.get_internal_links().map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
self.get_internal_links()
.map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
.map_err(From::from)
} }
fn add_link(&mut self, store: &Store, l: Link) -> Result<()> { fn add_link(&mut self, store: &Store, l: Link) -> Result<()> {
use link::IntoUrl; use link::IntoUrl;
l.into_url().and_then(|url| self.add_external_link(store, url))
l.into_url()
.and_then(|url| self.add_external_link(store, url).map_err(From::from))
.map_err(From::from)
} }
fn get_links_matching<'a>(&self, store: &'a Store, r: Regex) -> Result<LinksMatchingRegexIter<'a>> { fn get_links_matching<'a>(&self, store: &'a Store, r: Regex) -> Result<LinksMatchingRegexIter<'a>> {
use self::iter::IntoLinksMatchingRegexIter; use self::iter::IntoLinksMatchingRegexIter;
self.get_external_links(store).map(|iter| iter.matching_regex(r))
self.get_external_links(store)
.map(|iter| iter.matching_regex(r))
.map_err(From::from)
} }
fn remove_link(&mut self, store: &Store, l: Link) -> Result<()> { fn remove_link(&mut self, store: &Store, l: Link) -> Result<()> {
use link::IntoUrl; use link::IntoUrl;
l.into_url().and_then(|url| self.remove_external_link(store, url))
l.into_url()
.and_then(|url| self.remove_external_link(store, url).map_err(From::from))
.map_err(From::from)
} }
} }
pub mod iter { pub mod iter {
use link::Link; use link::Link;
use error::Result; use failure::Fallible as Result;
use error::BookmarkError as BE; use failure::Error;
pub struct LinkIter<I>(I) pub struct LinkIter<I>(I)
where I: Iterator<Item = Link>; where I: Iterator<Item = Link>;
@ -167,7 +156,7 @@ pub mod iter {
loop { loop {
let n = match self.0.next() { let n = match self.0.next() {
Some(Ok(n)) => n, Some(Ok(n)) => n,
Some(Err(e)) => return Some(Err(BE::from(e))), Some(Err(e)) => return Some(Err(Error::from(e))),
None => return None, None => return None,
}; };

View file

@ -1,48 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
error_chain! {
types {
BookmarkError, BookmarkErrorKind, ResultExt, Result;
}
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
LinkError(::libimagentrylink::error::LinkError, ::libimagentrylink::error::LinkErrorKind);
}
errors {
LinkParsingError {
description("Link parsing error")
display("Link parsing error")
}
LinkingError {
description("Error while linking")
display("Error while linking")
}
CollectionNotFound {
description("Link-Collection not found")
display("Link-Collection not found")
}
}
}

View file

@ -37,7 +37,7 @@
extern crate url; extern crate url;
extern crate regex; extern crate regex;
#[macro_use] extern crate error_chain; extern crate failure;
#[macro_use] extern crate libimagstore; #[macro_use] extern crate libimagstore;
extern crate libimagerror; extern crate libimagerror;
@ -46,5 +46,4 @@ extern crate libimagentrylink;
module_entry_path_mod!("bookmark"); module_entry_path_mod!("bookmark");
pub mod collection; pub mod collection;
pub mod error;
pub mod link; pub mod link;

View file

@ -19,7 +19,10 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use error::Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error;
use failure::err_msg;
use url::Url; use url::Url;
@ -66,10 +69,7 @@ pub trait IntoUrl {
impl IntoUrl for Link { impl IntoUrl for Link {
fn into_url(self) -> Result<Url> { fn into_url(self) -> Result<Url> {
use error::BookmarkErrorKind as BEK; Url::parse(&self[..]).context(err_msg("Link parsing error")).map_err(Error::from)
use error::ResultExt;
Url::parse(&self[..]).chain_err(|| BEK::LinkParsingError)
} }
} }

View file

@ -20,11 +20,11 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
error-chain = "0.12" failure = "0.1"
log = "0.4" log = "0.4"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "update-errorchain" } vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "master" }
uuid = "0.7" uuid = "0.7"
serde = "1" serde = "1"
serde_derive = "1" serde_derive = "1"

View file

@ -20,15 +20,15 @@
use toml::to_string as toml_to_string; use toml::to_string as toml_to_string;
use toml::from_str as toml_from_str; use toml::from_str as toml_from_str;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use failure::Fallible as Result;
use failure::Error;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagentryutil::isa::Is; use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider; use libimagentryutil::isa::IsKindHeaderPathProvider;
use libimagerror::errors::ErrorMsg as EM;
use deser::DeserVcard; use deser::DeserVcard;
use error::Result;
use error::ContactError as CE;
use error::ContactErrorKind as CEK;
/// Trait to be implemented on ::libimagstore::store::Entry /// Trait to be implemented on ::libimagstore::store::Entry
pub trait Contact { pub trait Contact {
@ -48,14 +48,14 @@ provide_kindflag_path!(pub IsContact, "contact.is_contact");
impl Contact for Entry { impl Contact for Entry {
fn is_contact(&self) -> Result<bool> { fn is_contact(&self) -> Result<bool> {
self.is::<IsContact>().map_err(From::from) self.is::<IsContact>()
} }
fn deser(&self) -> Result<DeserVcard> { fn deser(&self) -> Result<DeserVcard> {
let data = self let data = self
.get_header() .get_header()
.read("contact.data")? .read("contact.data")?
.ok_or_else(|| CE::from_kind(CEK::HeaderDataMissing("contact.data")))?; .ok_or_else(|| Error::from(EM::EntryHeaderFieldMissing("contact.data")))?;
// ugly hack // ugly hack
let data_str = toml_to_string(&data)?; let data_str = toml_to_string(&data)?;

View file

@ -1,65 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
use libimagstore::storeid::StoreId;
error_chain! {
types {
ContactError, ContactErrorKind, ResultExt, Result;
}
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
VObjectError(::vobject::error::VObjectError, ::vobject::error::VObjectErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {
Io(::std::io::Error);
TomlDe(::toml::de::Error);
TomlSer(::toml::ser::Error);
TomlQueryError(::toml_query::error::Error);
UuidError(::uuid::parser::ParseError);
}
errors {
HeaderTypeError(ty: &'static str, loc: &'static str) {
description("Type error in header")
display("Type error in header, expected {} at '{}', found other type", ty, loc)
}
HeaderDataMissing(datapath: &'static str) {
description("Data missing in header")
display("Data missing in header at '{}'", datapath)
}
EntryNotFound(sid: StoreId) {
description("Entry not found with StoreId")
display("Entry {:?} not found", sid)
}
UidMissing(buf: String) {
description("Vcard object has no UID")
display("Vcard has no UID : {}", buf)
}
}
}

View file

@ -20,11 +20,11 @@
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagerror::errors::ErrorMsg as EM;
use contact::Contact; use contact::Contact;
use error::ContactError as CE; use failure::Fallible as Result;
use error::ContactErrorKind as CEK; use failure::Error;
use error::Result;
pub struct ContactIter<'a>(StoreIdIterator, &'a Store); pub struct ContactIter<'a>(StoreIdIterator, &'a Store);
@ -44,11 +44,12 @@ impl<'a> Iterator for ContactIter<'a> {
loop { loop {
match self.0.next() { match self.0.next() {
None => return None, None => return None,
Some(Err(e)) => return Some(Err(e).map_err(CE::from)), Some(Err(e)) => return Some(Err(e).map_err(Error::from)),
Some(Ok(sid)) => match self.1.get(sid.clone()).map_err(From::from) { Some(Ok(sid)) => match self.1.get(sid.clone()).map_err(From::from) {
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
Ok(None) => return Some(Err(CE::from_kind(CEK::EntryNotFound(sid)))), Ok(None) => return
Ok(Some(entry)) => match entry.is_contact().map_err(From::from) { Some(Err(Error::from(EM::EntryNotFound(sid.local_display_string())))),
Ok(Some(entry)) => match entry.is_contact().map_err(Error::from) {
Ok(true) => return Some(Ok(entry)), Ok(true) => return Some(Ok(entry)),
Ok(false) => continue, Ok(false) => continue,
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),

View file

@ -36,7 +36,7 @@
#![recursion_limit="128"] #![recursion_limit="128"]
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate error_chain; #[macro_use] extern crate failure;
extern crate vobject; extern crate vobject;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
@ -51,7 +51,6 @@ extern crate libimagerror;
module_entry_path_mod!("contact"); module_entry_path_mod!("contact");
pub mod contact; pub mod contact;
pub mod error;
pub mod iter; pub mod iter;
pub mod store; pub mod store;
pub mod deser; pub mod deser;

View file

@ -24,6 +24,8 @@ use toml::to_string as toml_to_string;
use toml::from_str as toml_from_str; use toml::from_str as toml_from_str;
use toml_query::insert::TomlValueInsertExt; use toml_query::insert::TomlValueInsertExt;
use vobject::vcard::Vcard; use vobject::vcard::Vcard;
use failure::Error;
use failure::Fallible as Result;
use libimagstore::storeid::IntoStoreId; use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
@ -35,9 +37,6 @@ use libimagentryutil::isa::Is;
use contact::IsContact; use contact::IsContact;
use deser::DeserVcard; use deser::DeserVcard;
use module_path::ModuleEntryPath; use module_path::ModuleEntryPath;
use error::ContactError as CE;
use error::ContactErrorKind as CEK;
use error::Result;
use util; use util;
pub trait ContactStore<'a> { pub trait ContactStore<'a> {
@ -95,10 +94,11 @@ impl<'a> ContactStore<'a> for Store {
/// ///
/// That means calculating the StoreId and the Value from the vcard data /// That means calculating the StoreId and the Value from the vcard data
fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> { fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
let vcard = Vcard::build(&buf)?; let vcard = Vcard::build(&buf).map_err(Error::from)?;
debug!("Parsed: {:?}", vcard); debug!("Parsed: {:?}", vcard);
let uid = vcard.uid().ok_or_else(|| CE::from_kind(CEK::UidMissing(buf.to_string())))?; let uid = vcard.uid()
.ok_or_else(|| Error::from(format_err!("UID Missing: {}", buf.to_string())))?;
let value = { // dirty ugly hack let value = { // dirty ugly hack
let serialized = DeserVcard::from(vcard); let serialized = DeserVcard::from(vcard);

View file

@ -22,7 +22,7 @@ use std::fmt::Debug;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use error::Result; use failure::Fallible as Result;
pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> { pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
let mut cont = String::new(); let mut cont = String::new();

View file

@ -25,7 +25,7 @@ log = "0.4.0"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = "0.7"
itertools = "0.7" itertools = "0.7"
error-chain = "0.12" failure = "0.1"
filters = "0.3" filters = "0.3"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }

View file

@ -29,13 +29,12 @@ use chrono::Datelike;
use itertools::Itertools; use itertools::Itertools;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use chrono::Timelike; use chrono::Timelike;
use failure::Fallible as Result;
use failure::Error;
use entry::IsDiaryEntry; use entry::IsDiaryEntry;
use diaryid::DiaryId; use diaryid::DiaryId;
use diaryid::FromStoreId; use diaryid::FromStoreId;
use error::DiaryErrorKind as DEK;
use error::ResultExt;
use error::Result;
use iter::DiaryEntryIterator; use iter::DiaryEntryIterator;
use iter::DiaryNameIterator; use iter::DiaryNameIterator;
@ -67,7 +66,7 @@ impl Diary for Store {
let ndt = dt.naive_local(); let ndt = dt.naive_local();
let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0, 0); let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0, 0);
let mut entry = self.retrieve(id).chain_err(|| DEK::StoreReadError)?; let mut entry = self.retrieve(id)?;
let _ = entry.set_isflag::<IsDiaryEntry>()?; let _ = entry.set_isflag::<IsDiaryEntry>()?;
Ok(entry) Ok(entry)
} }
@ -87,7 +86,7 @@ impl Diary for Store {
ndt.minute(), ndt.minute(),
ndt.second()); ndt.second());
let mut entry = self.retrieve(id).chain_err(|| DEK::StoreReadError)?; let mut entry = self.retrieve(id)?;
let _ = entry.set_isflag::<IsDiaryEntry>()?; let _ = entry.set_isflag::<IsDiaryEntry>()?;
Ok(entry) Ok(entry)
} }
@ -97,15 +96,12 @@ impl Diary for Store {
debug!("Building iterator for module 'diary' with diary name = '{}'", diary_name); debug!("Building iterator for module 'diary' with diary name = '{}'", diary_name);
Store::entries(self) Store::entries(self)
.map(|iter| DiaryEntryIterator::new(String::from(diary_name), iter.without_store())) .map(|iter| DiaryEntryIterator::new(String::from(diary_name), iter.without_store()))
.chain_err(|| DEK::StoreReadError)
} }
/// get the id of the youngest entry /// get the id of the youngest entry
/// ///
/// TODO: We collect internally here. We shouldn't do that. Solution unclear. /// TODO: We collect internally here. We shouldn't do that. Solution unclear.
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> { fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> {
use error::DiaryError as DE;
match Diary::entries(self, diary_name) { match Diary::entries(self, diary_name) {
Err(e) => Some(Err(e)), Err(e) => Some(Err(e)),
Ok(entries) => { Ok(entries) => {
@ -114,7 +110,7 @@ impl Diary for Store {
for entry in entries { for entry in entries {
let entry = match entry { let entry = match entry {
Ok(e) => DiaryId::from_storeid(&e), Ok(e) => DiaryId::from_storeid(&e),
Err(e) => return Some(Err(e).map_err(DE::from)), Err(e) => return Some(Err(e)),
}; };
sorted_entries.push(entry); sorted_entries.push(entry);
@ -156,7 +152,7 @@ impl Diary for Store {
fn diary_names(&self) -> Result<DiaryNameIterator> { fn diary_names(&self) -> Result<DiaryNameIterator> {
self.entries() self.entries()
.map(|it| DiaryNameIterator::new(it.without_store())) .map(|it| DiaryNameIterator::new(it.without_store()))
.map_err(::error::DiaryError::from) .map_err(Error::from)
} }
} }

View file

@ -19,20 +19,20 @@
use std::convert::Into; use std::convert::Into;
use std::fmt::{Display, Formatter, Error as FmtError}; use std::fmt::{Display, Formatter, Error as FmtError};
use std::result::Result as RResult;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use chrono::naive::NaiveTime; use chrono::naive::NaiveTime;
use chrono::naive::NaiveDate; use chrono::naive::NaiveDate;
use chrono::Datelike; use chrono::Datelike;
use chrono::Timelike; use chrono::Timelike;
use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error;
use failure::err_msg;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId; use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Result as StoreResult;
use error::DiaryError as DE;
use error::DiaryErrorKind as DEK;
use error::ResultExt;
use module_path::ModuleEntryPath; use module_path::ModuleEntryPath;
@ -149,7 +149,7 @@ impl DiaryId {
impl IntoStoreId for DiaryId { impl IntoStoreId for DiaryId {
fn into_storeid(self) -> StoreResult<StoreId> { fn into_storeid(self) -> Result<StoreId> {
let s : String = self.into(); let s : String = self.into();
ModuleEntryPath::new(s).into_storeid() ModuleEntryPath::new(s).into_storeid()
} }
@ -167,7 +167,7 @@ impl Into<String> for DiaryId {
impl Display for DiaryId { impl Display for DiaryId {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}:{:0>2}", write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}:{:0>2}",
self.name, self.year, self.month, self.day, self.hour, self.minute, self.second) self.name, self.year, self.month, self.day, self.hour, self.minute, self.second)
} }
@ -185,32 +185,30 @@ impl Into<NaiveDateTime> for DiaryId {
} }
pub trait FromStoreId : Sized { pub trait FromStoreId : Sized {
fn from_storeid(&StoreId) -> Result<Self>;
fn from_storeid(&StoreId) -> Result<Self, DE>;
} }
use std::path::Component; use std::path::Component;
fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str, DE> { fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str> {
match com { match com {
Component::Normal(s) => Some(s), Component::Normal(s) => Some(s),
_ => None, _ => None,
}.and_then(|s| s.to_str()) }.and_then(|s| s.to_str())
.ok_or(DE::from_kind(DEK::IdParseError)) .ok_or_else(|| Error::from(err_msg("ID Parse error")))
} }
impl FromStoreId for DiaryId { impl FromStoreId for DiaryId {
fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> { fn from_storeid(s: &StoreId) -> Result<DiaryId> {
use std::str::FromStr; use std::str::FromStr;
use std::path::Components; use std::path::Components;
use std::iter::Rev; use std::iter::Rev;
fn next_component<'a>(components: &'a mut Rev<Components>) -> Result<&'a str, DE> { fn next_component<'a>(components: &'a mut Rev<Components>) -> Result<&'a str> {
components.next() components.next()
.ok_or(DE::from_kind(DEK::IdParseError)) .ok_or_else(|| Error::from(err_msg("ID parse error")))
.and_then(component_to_str) .and_then(component_to_str)
} }
@ -228,21 +226,33 @@ impl FromStoreId for DiaryId {
match (hour, minute, second) { match (hour, minute, second) {
(Some(h), Some(m), Some(s)) => Ok((h, m, s)), (Some(h), Some(m), Some(s)) => Ok((h, m, s)),
_ => return Err(DE::from_kind(DEK::IdParseError)), _ => return Err(Error::from(err_msg("ID Parse error"))),
} }
})?; })?;
let day: Result<u32,_> = next_component(&mut cmps) let day: Result<u32> = next_component(&mut cmps)
.and_then(|s| s.parse::<u32>() .and_then(|s| {
.chain_err(|| DEK::IdParseError)); s.parse::<u32>()
.map_err(Error::from)
.context(err_msg("ID parse error"))
.map_err(Error::from)
});
let month: Result<u32,_> = next_component(&mut cmps) let month: Result<u32> = next_component(&mut cmps)
.and_then(|s| s.parse::<u32>() .and_then(|s| {
.chain_err(|| DEK::IdParseError)); s.parse::<u32>()
.map_err(Error::from)
.context(err_msg("ID Parse error"))
.map_err(Error::from)
});
let year: Result<i32,_> = next_component(&mut cmps) let year: Result<i32> = next_component(&mut cmps)
.and_then(|s| s.parse::<i32>() .and_then(|s| {
.chain_err(|| DEK::IdParseError)); s.parse::<i32>()
.map_err(Error::from)
.context(err_msg("ID Parse error"))
.map_err(Error::from)
});
let name = next_component(&mut cmps).map(String::from); let name = next_component(&mut cmps).map(String::from);

View file

@ -21,9 +21,10 @@ use libimagstore::store::Entry;
use libimagentryutil::isa::Is; use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider; use libimagentryutil::isa::IsKindHeaderPathProvider;
use failure::Fallible as Result;
use diaryid::DiaryId; use diaryid::DiaryId;
use diaryid::FromStoreId; use diaryid::FromStoreId;
use error::Result;
provide_kindflag_path!(pub IsDiaryEntry, "diary.is_diary_entry"); provide_kindflag_path!(pub IsDiaryEntry, "diary.is_diary_entry");

View file

@ -1,92 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
error_chain! {
types {
DiaryError, DiaryErrorKind, ResultExt, Result;
}
foreign_links {
Io(::std::io::Error);
}
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
errors {
StoreWriteError {
description("Error writing store")
display("Error writing store")
}
StoreReadError {
description("Error reading store")
display("Error reading store")
}
CannotFindDiary {
description("Cannot find diary")
display("Cannot find diary")
}
CannotCreateNote {
description("Cannot create Note object for diary entry")
display("Cannot create Note object for diary entry")
}
DiaryEditError {
description("Cannot edit diary entry")
display("Cannot edit diary entry")
}
PathConversionError {
description("Error while converting paths internally")
display("Error while converting paths internally")
}
EntryNotInDiary {
description("Entry not in Diary")
display("Entry not in Diary")
}
IOError {
description("IO Error")
display("IO Error")
}
ViewError {
description("Error viewing diary entry")
display("Error viewing diary entry")
}
IdParseError {
description("Error while parsing ID")
display("Error while parsing ID")
}
DiaryNameFindingError {
description("Error while finding a diary name")
display("Error while finding a diary name")
}
}
}

View file

@ -26,10 +26,9 @@ use libimagstore::storeid::StoreIdIterator;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use is_in_diary::IsInDiary; use is_in_diary::IsInDiary;
use error::DiaryErrorKind as DEK; use failure::Fallible as Result;
use error::DiaryError as DE; use failure::Error;
use error::ResultExt; use failure::err_msg;
use error::Result;
/// A iterator for iterating over diary entries /// A iterator for iterating over diary entries
pub struct DiaryEntryIterator { pub struct DiaryEntryIterator {
@ -109,7 +108,7 @@ impl Iterator for DiaryEntryIterator {
loop { loop {
match self.iter.next() { match self.iter.next() {
None => return None, None => return None,
Some(Err(e)) => return Some(Err(e).map_err(DE::from)), Some(Err(e)) => return Some(Err(e)),
Some(Ok(s)) => { Some(Ok(s)) => {
debug!("Next element: {:?}", s); debug!("Next element: {:?}", s);
if Filter::filter(self, &s) { if Filter::filter(self, &s) {
@ -143,16 +142,15 @@ impl Iterator for DiaryNameIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(next) = self.0.next() { while let Some(next) = self.0.next() {
match next { match next {
Err(e) => return Some(Err(e).map_err(DE::from)), Err(e) => return Some(Err(e)),
Ok(next) => if next.is_in_collection(&["diary"]) { Ok(next) => if next.is_in_collection(&["diary"]) {
return Some(next return Some(next
.to_str() .to_str()
.chain_err(|| DEK::DiaryNameFindingError)
.and_then(|s| { .and_then(|s| {
s.split("diary/") s.split("diary/")
.nth(1) .nth(1)
.and_then(|n| n.split("/").nth(0).map(String::from)) .and_then(|n| n.split("/").nth(0).map(String::from))
.ok_or(DE::from_kind(DEK::DiaryNameFindingError)) .ok_or_else(|| Error::from(err_msg("Error finding diary name")))
})); }));
}, },
} }

View file

@ -40,7 +40,7 @@ extern crate chrono;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate itertools; extern crate itertools;
#[macro_use] extern crate error_chain; extern crate failure;
extern crate filters; extern crate filters;
#[macro_use] extern crate libimagstore; #[macro_use] extern crate libimagstore;
@ -53,7 +53,6 @@ extern crate libimagrt;
module_entry_path_mod!("diary"); module_entry_path_mod!("diary");
pub mod config; pub mod config;
pub mod error;
pub mod diaryid; pub mod diaryid;
pub mod diary; pub mod diary;
pub mod is_in_diary; pub mod is_in_diary;

View file

@ -22,11 +22,13 @@
use std::io::Write; use std::io::Write;
use std::ops::Deref; use std::ops::Deref;
use failure::Fallible as Result;
use failure::ResultExt;
use failure::err_msg;
use failure::Error;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagentryview::viewer::Viewer; use libimagentryview::viewer::Viewer;
use libimagentryview::error::ViewErrorKind as VEK;
use libimagentryview::error::ResultExt;
use libimagentryview::error::Result as ViewResult;
use libimagentryview::builtin::plain::PlainViewer; use libimagentryview::builtin::plain::PlainViewer;
use entry::DiaryEntry; use entry::DiaryEntry;
@ -51,7 +53,7 @@ impl DiaryViewer {
impl Viewer for DiaryViewer { impl Viewer for DiaryViewer {
fn view_entry<W>(&self, e: &Entry, sink: &mut W) -> ViewResult<()> fn view_entry<W>(&self, e: &Entry, sink: &mut W) -> Result<()>
where W: Write where W: Write
{ {
self.0.view_entry(e, sink) self.0.view_entry(e, sink)
@ -59,14 +61,20 @@ impl Viewer for DiaryViewer {
/// View all entries from the iterator, or stop immediately if an error occurs, returning that /// View all entries from the iterator, or stop immediately if an error occurs, returning that
/// error. /// error.
fn view_entries<I, E, W>(&self, entries: I, sink: &mut W) -> ViewResult<()> fn view_entries<I, E, W>(&self, entries: I, sink: &mut W) -> Result<()>
where I: Iterator<Item = E>, where I: Iterator<Item = E>,
E: Deref<Target = Entry>, E: Deref<Target = Entry>,
W: Write W: Write
{ {
let mut entries = entries let mut entries = entries
.map(|e| e.deref().diary_id().map(|id| (id, e)).chain_err(|| VEK::ViewError)) .map(|e| {
.collect::<ViewResult<Vec<_>>>()?; e.deref()
.diary_id()
.map(|id| (id, e))
.context(err_msg("View error"))
.map_err(Error::from)
})
.collect::<Result<Vec<_>>>()?;
entries.sort_by_key(|&(ref id, _)| { entries.sort_by_key(|&(ref id, _)| {
[id.year() as u32, id.month(), id.day(), id.hour(), id.minute(), id.second()] [id.year() as u32, id.month(), id.day(), id.hour(), id.minute(), id.second()]

View file

@ -23,9 +23,9 @@ maintenance = { status = "actively-developed" }
chrono = "0.4" chrono = "0.4"
log = "0.4" log = "0.4"
toml = "0.4" toml = "0.4"
toml-query = "0.7" toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
error-chain = "0.12" kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "failure" }
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "master" } failure = "0.1"
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }

View file

@ -1,60 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
error_chain! {
types {
HabitError, HabitErrorKind, ResultExt, Result;
}
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
LinkError(::libimagentrylink::error::LinkError, ::libimagentrylink::error::LinkErrorKind);
KairosError(::kairos::error::KairosError, ::kairos::error::KairosErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {
TomlError(::toml_query::error::Error);
ChronoError(::chrono::format::ParseError);
}
errors {
HabitBuilderMissing(variable_name: &'static str) {
description("Habit builder has not all required information")
display("Habit builder misses {}", variable_name)
}
HabitBuilderLogicError(text: &'static str) {
description("Logic error in Habit builder")
display("Logic error: {}", text)
}
HeaderFieldMissing(path: &'static str) {
description("Header field missing")
display("Header field missing: {}", path)
}
HeaderTypeError(path: &'static str, required_type: &'static str) {
description("Header type error")
display("Header type error: Expected {} at {}, found other type", required_type, path)
}
}
}

View file

@ -23,10 +23,10 @@ use toml_query::insert::TomlValueInsertExt;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use chrono::Local; use chrono::Local;
use chrono::NaiveDate; use chrono::NaiveDate;
use failure::Error;
use failure::Fallible as Result;
use failure::err_msg;
use error::HabitError as HE;
use error::HabitErrorKind as HEK;
use error::*;
use iter::HabitInstanceStoreIdIterator; use iter::HabitInstanceStoreIdIterator;
use util::IsHabitCheck; use util::IsHabitCheck;
use util::get_string_header_from_entry; use util::get_string_header_from_entry;
@ -148,7 +148,7 @@ impl HabitTemplate for Entry {
match parse(&r)? { match parse(&r)? {
Parsed::TimeType(tt) => Ok(tt), Parsed::TimeType(tt) => Ok(tt),
Parsed::Iterator(_) => { Parsed::Iterator(_) => {
Err(format!("'{}' yields an iterator. Cannot use.", r).into()) Err(format_err!("'{}' yields an iterator. Cannot use.", r))
}, },
} }
}; };
@ -166,10 +166,7 @@ impl HabitTemplate for Entry {
.calculate()? .calculate()?
.get_moment() .get_moment()
.map(Clone::clone) .map(Clone::clone)
.ok_or_else(|| { .ok_or_else(|| Error::from(err_msg("until-date seems to have non-date value")))
let kind : HEK = "until-date seems to have non-date value".to_owned().into();
HE::from_kind(kind)
})
}); });
debug!("Until-Date is {:?}", basedate); debug!("Until-Date is {:?}", basedate);
@ -192,7 +189,7 @@ impl HabitTemplate for Entry {
} }
} }
} else { } else {
return Err("Iterator seems to return bogus values.".to_owned().into()); return Err(err_msg("Iterator seems to return bogus values."));
} }
} }
@ -265,7 +262,7 @@ fn instance_id_for_name_and_datestr(habit_name: &String, habit_date: &String) ->
ModuleEntryPath::new(format!("instance/{}-{}", habit_name, habit_date)) ModuleEntryPath::new(format!("instance/{}-{}", habit_name, habit_date))
.into_storeid() .into_storeid()
.map_err(HE::from) .map_err(Error::from)
} }
pub mod builder { pub mod builder {
@ -280,9 +277,10 @@ pub mod builder {
use libimagentryutil::isa::Is; use libimagentryutil::isa::Is;
use libimagutil::debug_result::DebugResult; use libimagutil::debug_result::DebugResult;
use error::HabitError as HE; use failure::Error;
use error::HabitErrorKind as HEK; use failure::Fallible as Result;
use error::*; use failure::err_msg;
use libimagutil::date::date_to_string; use libimagutil::date::date_to_string;
use habit::IsHabitTemplate; use habit::IsHabitTemplate;
@ -324,8 +322,8 @@ pub mod builder {
pub fn build<'a>(self, store: &'a Store) -> Result<FileLockEntry<'a>> { pub fn build<'a>(self, store: &'a Store) -> Result<FileLockEntry<'a>> {
#[inline] #[inline]
fn mkerr(s: &'static str) -> HE { fn mkerr(s: &'static str) -> Error {
HE::from_kind(HEK::HabitBuilderMissing(s)) Error::from(format_err!("Habit builder missing: {}", s))
} }
let name = self.name let name = self.name
@ -336,21 +334,21 @@ pub mod builder {
.ok_or_else(|| mkerr("date")) .ok_or_else(|| mkerr("date"))
.map_dbg_str("Success: Date present")?; .map_dbg_str("Success: Date present")?;
let recur = self.recurspec let recur : String = self.recurspec
.ok_or_else(|| mkerr("recurspec")) .ok_or_else(|| mkerr("recurspec"))
.map_dbg_str("Success: Recurr spec present")?; .map_dbg_str("Success: Recurr spec present")?;
if let Some(until) = self.untildate { if let Some(until) = self.untildate {
debug!("Success: Until-Date present"); debug!("Success: Until-Date present");
if dateobj > until { if dateobj > until {
let e = HE::from_kind(HEK::HabitBuilderLogicError("until-date before start date")); let e = Error::from(err_msg("Habit builder logic error: until-date before start date"));
return Err(e); return Err(e);
} }
} }
if let Err(e) = ::kairos::parser::parse(&recur) { if let Err(e) = ::kairos::parser::parse(&recur).map_err(Error::from) {
debug!("Kairos failed: {:?}", e); debug!("Kairos failed: {:?}", e);
return Err(e).map_err(From::from); return Err(e)
} }
let date = date_to_string(&dateobj); let date = date_to_string(&dateobj);
debug!("Success: Date valid"); debug!("Success: Date valid");

View file

@ -20,8 +20,8 @@
use chrono::NaiveDate; use chrono::NaiveDate;
use toml::Value; use toml::Value;
use toml_query::set::TomlValueSetExt; use toml_query::set::TomlValueSetExt;
use failure::Fallible as Result;
use error::*;
use util::*; use util::*;
use libimagstore::store::Entry; use libimagstore::store::Entry;

View file

@ -17,13 +17,14 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use failure::Error;
use failure::Fallible as Result;
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagstore::storeid::StoreIdIteratorWithStore; use libimagstore::storeid::StoreIdIteratorWithStore;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use util::IsHabitCheck; use util::IsHabitCheck;
use error::Result;
use error::HabitError as HE;
pub struct HabitTemplateStoreIdIterator(StoreIdIterator); pub struct HabitTemplateStoreIdIterator(StoreIdIterator);
@ -36,7 +37,7 @@ impl Iterator for HabitTemplateStoreIdIterator {
Ok(n) => if n.is_habit_template() { Ok(n) => if n.is_habit_template() {
return Some(Ok(n)) return Some(Ok(n))
}, },
Err(e) => return Some(Err(e).map_err(HE::from)), Err(e) => return Some(Err(e).map_err(Error::from)),
} }
} }
None None
@ -72,7 +73,7 @@ impl Iterator for HabitInstanceStoreIdIterator {
Ok(n) => if n.is_habit_instance() { Ok(n) => if n.is_habit_instance() {
return Some(Ok(n)); return Some(Ok(n));
}, },
Err(e) => return Some(Err(e).map_err(HE::from)), Err(e) => return Some(Err(e).map_err(Error::from)),
} }
} }
None None

Some files were not shown because too many files have changed in this diff Show more