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:
commit
a749d97a16
231 changed files with 1579 additions and 3404 deletions
|
@ -26,6 +26,7 @@ log = "0.4.0"
|
|||
url = "1.2"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimagentryannotation;
|
||||
extern crate libimagentryedit;
|
||||
|
@ -46,9 +47,11 @@ extern crate libimagutil;
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagentryannotation::annotateable::*;
|
||||
use libimagentryannotation::annotation_fetcher::*;
|
||||
use libimagentryannotation::error::AnnotationError as AE;
|
||||
use libimagentryedit::edit::*;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
|
@ -97,7 +100,7 @@ fn add(rt: &Runtime) {
|
|||
let _ = rt.store()
|
||||
.get(entry_name)
|
||||
.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)
|
||||
.annotate(rt.store(), annotation_name)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
|
@ -114,7 +117,7 @@ fn remove(rt: &Runtime) {
|
|||
let mut entry = rt.store()
|
||||
.get(PathBuf::from(entry_name).into_storeid().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);
|
||||
|
||||
let annotation = entry
|
||||
|
@ -148,7 +151,7 @@ fn list(rt: &Runtime) {
|
|||
.store()
|
||||
.get(pb.into_storeid().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)
|
||||
.annotations(rt.store())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
|
|
|
@ -24,7 +24,7 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4.0"
|
||||
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" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -18,8 +18,9 @@ build = "../../../build.rs"
|
|||
[dependencies]
|
||||
log = "0.4"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
indicatif = "0.9"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -36,6 +36,7 @@ extern crate clap;
|
|||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate indicatif;
|
||||
extern crate failure;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
#[macro_use] extern crate libimagrt;
|
||||
|
@ -52,12 +53,14 @@ use libimagerror::io::ToExitCode;
|
|||
use libimagerror::exit::ExitUnwrap;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::error::StoreError as Error;
|
||||
use libimagentrylink::internal::*;
|
||||
|
||||
use toml::Value;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
|
@ -76,7 +79,7 @@ struct 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 {
|
||||
id: entry.get_location().clone(),
|
||||
entry_store_version: entry
|
||||
|
@ -142,7 +145,7 @@ fn main() {
|
|||
.into_get_iter()
|
||||
.map(|e| {
|
||||
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(|e| {
|
||||
|
@ -163,7 +166,7 @@ fn main() {
|
|||
|
||||
diag
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
spinner.finish();
|
||||
|
@ -265,6 +268,7 @@ fn main() {
|
|||
fn get_config(rt: &Runtime, s: &'static str) -> Option<String> {
|
||||
rt.config().and_then(|cfg| {
|
||||
cfg.read(s)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.map(|opt| match opt {
|
||||
&Value::String(ref s) => s.to_owned(),
|
||||
|
|
|
@ -26,6 +26,7 @@ log = "0.4.0"
|
|||
url = "1.2"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimagentrygps;
|
||||
#[macro_use] extern crate libimagrt;
|
||||
|
@ -47,8 +48,9 @@ use std::process::exit;
|
|||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use libimagentrygps::error::GPSError as GE;
|
||||
use libimagentrygps::error::GPSErrorKind as GEK;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagentrygps::types::*;
|
||||
use libimagentrygps::entry::*;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
|
@ -100,7 +102,7 @@ fn add(rt: &Runtime) {
|
|||
.map(|v| {debug!("Parsing = {}", v); v})
|
||||
.map(FromStr::from_str)
|
||||
.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)
|
||||
})
|
||||
.collect::<Vec<i64>>();
|
||||
|
|
|
@ -26,8 +26,9 @@ filters = "0.3"
|
|||
nom = "3.2"
|
||||
log = "0.4"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
is-match = "0.1"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -51,6 +51,7 @@ pub mod header_filter_lang {
|
|||
|
||||
use nom::digit;
|
||||
use nom::multispace;
|
||||
use failure::Error;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
@ -403,6 +404,7 @@ pub mod header_filter_lang {
|
|||
entry
|
||||
.get_header()
|
||||
.read(selector_str)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.map(|value| {
|
||||
let comp = Comparator(&self.compare_operator, &self.compare_value);
|
||||
|
|
|
@ -39,6 +39,7 @@ extern crate filters;
|
|||
#[macro_use] extern crate is_match;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate failure;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
|
@ -68,7 +69,7 @@ fn main() {
|
|||
let version = make_imag_version!();
|
||||
let rt = generate_runtime_setup("imag-ids",
|
||||
&version,
|
||||
"Print all ids, optionally filtered with a user-defined filter",
|
||||
"print all ids",
|
||||
build_ui);
|
||||
|
||||
let print_storepath = rt.cli().is_present("print-storepath");
|
||||
|
|
|
@ -25,8 +25,9 @@ maintenance = { status = "actively-developed" }
|
|||
log = "0.4.0"
|
||||
url = "1.5"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
prettytable-rs = "0.8"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#[macro_use] extern crate log;
|
||||
extern crate clap;
|
||||
extern crate url;
|
||||
extern crate failure;
|
||||
#[macro_use] extern crate prettytable;
|
||||
#[cfg(test)] extern crate toml;
|
||||
#[cfg(test)] extern crate toml_query;
|
||||
|
@ -55,22 +56,24 @@ extern crate libimagutil;
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagentrylink::external::ExternalLinker;
|
||||
use libimagentrylink::internal::InternalLinker;
|
||||
use libimagentrylink::internal::store_check::StoreLinkConsistentExt;
|
||||
use libimagentrylink::error::LinkError as LE;
|
||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagstore::error::StoreError;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagutil::warn_exit::warn_exit;
|
||||
use libimagutil::warn_result::*;
|
||||
|
||||
use url::Url;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
mod ui;
|
||||
|
||||
|
@ -80,7 +83,7 @@ fn main() {
|
|||
let version = make_imag_version!();
|
||||
let rt = generate_runtime_setup("imag-link",
|
||||
&version,
|
||||
"Add/Remove links between entries",
|
||||
"Link entries",
|
||||
build_ui);
|
||||
if rt.cli().is_present("check-consistency") {
|
||||
let exit_code = match rt.store().check_link_consistency() {
|
||||
|
@ -119,11 +122,11 @@ fn main() {
|
|||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
debug!("Getting: {:?}", name);
|
||||
|
@ -336,11 +339,12 @@ mod tests {
|
|||
|
||||
use toml::value::Value;
|
||||
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 libimagstore::storeid::StoreId;
|
||||
use libimagstore::store::{Result as StoreResult, FileLockEntry, Entry};
|
||||
use libimagstore::store::{FileLockEntry, Entry};
|
||||
|
||||
fn setup_logging() {
|
||||
let _ = ::env_logger::try_init();
|
||||
|
@ -355,7 +359,7 @@ mod tests {
|
|||
use self::mock::generate_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();
|
||||
path.set_file_name(name);
|
||||
|
||||
|
@ -376,11 +380,10 @@ mod tests {
|
|||
Ok(id)
|
||||
}
|
||||
|
||||
fn get_entry_links<'a>(entry: &'a FileLockEntry<'a>) -> TomlQueryResult<&'a Value> {
|
||||
match entry.get_header().read(&"links.internal".to_owned()) {
|
||||
Err(e) => Err(e),
|
||||
Ok(Some(v)) => Ok(v),
|
||||
Ok(None) => panic!("Didn't find 'links' in {:?}", entry),
|
||||
fn get_entry_links<'a>(entry: &'a FileLockEntry<'a>) -> Result<&'a Value> {
|
||||
match entry.get_header().read(&"links.internal".to_owned()).map_err(Error::from)? {
|
||||
Some(v) => Ok(v),
|
||||
None => panic!("Didn't find 'links' in {:?}", entry),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,7 +397,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_link_modificates() {
|
||||
setup_logging();
|
||||
let rt = generate_test_runtime(vec!["test1", "test2"])
|
||||
let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
|
||||
.unwrap();
|
||||
|
||||
debug!("Runtime created");
|
||||
|
@ -423,7 +426,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_linking_links() {
|
||||
setup_logging();
|
||||
let rt = generate_test_runtime(vec!["test1", "test2"])
|
||||
let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
|
||||
.unwrap();
|
||||
|
||||
debug!("Runtime created");
|
||||
|
@ -452,7 +455,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_multilinking() {
|
||||
setup_logging();
|
||||
let rt = generate_test_runtime(vec!["test1", "test2"])
|
||||
let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
|
||||
.unwrap();
|
||||
|
||||
debug!("Runtime created");
|
||||
|
@ -482,7 +485,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_linking_more_than_two() {
|
||||
setup_logging();
|
||||
let rt = generate_test_runtime(vec!["test1", "test2", "test3"])
|
||||
let rt = generate_test_runtime(vec!["internal", "test1", "test2", "test3"])
|
||||
.unwrap();
|
||||
|
||||
debug!("Runtime created");
|
||||
|
@ -519,7 +522,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_linking_links_unlinking_removes_links() {
|
||||
setup_logging();
|
||||
let rt = generate_test_runtime(vec!["test1", "test2"])
|
||||
let rt = generate_test_runtime(vec!["internal", "test1", "test2"])
|
||||
.unwrap();
|
||||
|
||||
debug!("Runtime created");
|
||||
|
@ -555,7 +558,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_linking_and_unlinking_more_than_two() {
|
||||
setup_logging();
|
||||
let rt = generate_test_runtime(vec!["test1", "test2", "test3"])
|
||||
let rt = generate_test_runtime(vec!["internal", "test1", "test2", "test3"])
|
||||
.unwrap();
|
||||
|
||||
debug!("Runtime created");
|
||||
|
|
|
@ -53,7 +53,6 @@ use libimagerror::iter::TraceIterator;
|
|||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::error::StoreError;
|
||||
use libimagentrylink::internal::InternalLinker;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
|
||||
|
@ -93,7 +92,7 @@ fn main() {
|
|||
})
|
||||
.get_internal_links()
|
||||
.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())
|
||||
.trace_unwrap_exit(1)
|
||||
.map(|e| {
|
||||
|
|
|
@ -24,7 +24,7 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4.0"
|
||||
toml = "0.4"
|
||||
error-chain = "0.12"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore", features = ["verify"] }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -20,12 +20,13 @@
|
|||
use std::path::PathBuf;
|
||||
use std::io::stdin;
|
||||
use std::fs::OpenOptions;
|
||||
use std::result::Result as RResult;
|
||||
use std::io::Read;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use toml::Value;
|
||||
use failure::Fallible as Result;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagstore::store::Entry;
|
||||
|
@ -33,13 +34,8 @@ use libimagstore::storeid::StoreId;
|
|||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagutil::debug_result::*;
|
||||
|
||||
use error::StoreError;
|
||||
use error::StoreErrorKind;
|
||||
use error::ResultExt;
|
||||
use util::build_toml_header;
|
||||
|
||||
type Result<T> = RResult<T, StoreError>;
|
||||
|
||||
pub fn create(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("create").unwrap();
|
||||
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<()> {
|
||||
let content = matches
|
||||
.value_of("from-raw")
|
||||
.ok_or(StoreError::from_kind(StoreErrorKind::NoCommandlineCall))
|
||||
.map(string_from_raw_src);
|
||||
.ok_or_else(|| err_msg("No Commandline call"))
|
||||
.map(string_from_raw_src)?;
|
||||
|
||||
if content.is_err() {
|
||||
return content.map(|_| ());
|
||||
}
|
||||
let content = content.unwrap();
|
||||
debug!("Content with len = {}", content.len());
|
||||
|
||||
Entry::from_str(path.clone(), &content[..])
|
||||
|
@ -118,7 +110,6 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Res
|
|||
r
|
||||
})
|
||||
.map_dbg_err(|e| format!("Error storing entry: {:?}", e))
|
||||
.chain_err(|| StoreErrorKind::BackendError)
|
||||
}
|
||||
|
||||
fn create_with_content_and_header(rt: &Runtime,
|
||||
|
@ -142,7 +133,6 @@ fn create_with_content_and_header(rt: &Runtime,
|
|||
debug!("New header set");
|
||||
}
|
||||
})
|
||||
.chain_err(|| StoreErrorKind::BackendError)
|
||||
}
|
||||
|
||||
fn string_from_raw_src(raw_src: &str) -> String {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ extern crate clap;
|
|||
#[macro_use] extern crate log;
|
||||
extern crate toml;
|
||||
#[cfg(test)] extern crate toml_query;
|
||||
#[macro_use] extern crate error_chain;
|
||||
extern crate failure;
|
||||
|
||||
#[macro_use] extern crate libimagrt;
|
||||
extern crate libimagstore;
|
||||
|
@ -54,7 +54,6 @@ use libimagerror::trace::MapErrTrace;
|
|||
|
||||
mod create;
|
||||
mod delete;
|
||||
mod error;
|
||||
mod get;
|
||||
mod retrieve;
|
||||
mod ui;
|
||||
|
|
|
@ -37,8 +37,9 @@ default-features = false
|
|||
features = ["color", "suggestions", "wrap_help"]
|
||||
|
||||
[dev-dependencies]
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
env_logger = "0.5"
|
||||
failure = "0.1"
|
||||
|
||||
[dev-dependencies.libimagutil]
|
||||
version = "0.9.0"
|
||||
|
|
|
@ -36,6 +36,7 @@ extern crate clap;
|
|||
#[macro_use] extern crate log;
|
||||
|
||||
#[cfg(test)] extern crate toml;
|
||||
#[cfg(test)] extern crate failure;
|
||||
|
||||
extern crate libimagstore;
|
||||
#[macro_use] extern crate libimagrt;
|
||||
|
@ -80,7 +81,7 @@ fn main() {
|
|||
let version = make_imag_version!();
|
||||
let rt = generate_runtime_setup("imag-tag",
|
||||
&version,
|
||||
"Add and remove tags for entries",
|
||||
"Direct interface to the store. Use with great care!",
|
||||
build_ui);
|
||||
|
||||
let ids : Vec<PathBuf> = rt
|
||||
|
@ -269,11 +270,12 @@ mod tests {
|
|||
|
||||
use toml::value::Value;
|
||||
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 libimagstore::storeid::StoreId;
|
||||
use libimagstore::store::{Result as StoreResult, FileLockEntry, Entry};
|
||||
use libimagstore::store::{FileLockEntry, Entry};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -285,7 +287,7 @@ mod tests {
|
|||
}
|
||||
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();
|
||||
path.set_file_name(name);
|
||||
|
||||
|
@ -300,8 +302,8 @@ mod tests {
|
|||
Ok(id)
|
||||
}
|
||||
|
||||
fn get_entry_tags<'a>(entry: &'a FileLockEntry<'a>) -> TomlQueryResult<Option<&'a Value>> {
|
||||
entry.get_header().read(&"tag.values".to_owned())
|
||||
fn get_entry_tags<'a>(entry: &'a FileLockEntry<'a>) -> Result<Option<&'a Value>> {
|
||||
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 {
|
||||
|
|
|
@ -24,9 +24,10 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4.0"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
handlebars = "1.0"
|
||||
tempfile = "3"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -38,6 +38,7 @@ extern crate handlebars;
|
|||
extern crate tempfile;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimagentryview;
|
||||
extern crate libimagerror;
|
||||
|
@ -55,10 +56,11 @@ use std::process::exit;
|
|||
|
||||
use handlebars::Handlebars;
|
||||
use toml_query::read::TomlValueReadTypeExt;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::str::ErrFromStr;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::io::ToExitCode;
|
||||
|
@ -66,10 +68,8 @@ use libimagerror::exit::ExitUnwrap;
|
|||
use libimagentryview::builtin::stdout::StdoutViewer;
|
||||
use libimagentryview::builtin::md::MarkdownViewer;
|
||||
use libimagentryview::viewer::Viewer;
|
||||
use libimagentryview::error::ViewError as VE;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreIdIterator;
|
||||
use libimagstore::error::StoreError;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
|
||||
|
@ -92,8 +92,7 @@ fn main() {
|
|||
.into_get_iter(rt.store())
|
||||
.trace_unwrap_exit(1)
|
||||
.map(|e| {
|
||||
e.ok_or_else(|| String::from("Entry not found"))
|
||||
.map_err(StoreError::from)
|
||||
e.ok_or_else(|| err_msg("Entry not found"))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
})
|
||||
.map(|entry| create_tempfile_for(&entry, view_header, hide_content))
|
||||
|
@ -103,18 +102,19 @@ fn main() {
|
|||
let viewer = rt
|
||||
.cli()
|
||||
.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);
|
||||
|
||||
let config = rt
|
||||
.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);
|
||||
|
||||
let query = format!("view.viewers.{}", viewer);
|
||||
|
||||
let viewer_template = config
|
||||
.read_string(&query)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| {
|
||||
error!("Cannot find '{}' in config", query);
|
||||
|
@ -126,8 +126,7 @@ fn main() {
|
|||
|
||||
let _ = handlebars
|
||||
.register_template_string("template", viewer_template)
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
|
@ -142,13 +141,12 @@ fn main() {
|
|||
|
||||
let call = handlebars
|
||||
.render("template", &data)
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
let mut elems = call.split_whitespace();
|
||||
let command_string = elems
|
||||
.next()
|
||||
.ok_or::<VE>("No command".to_owned().into())
|
||||
.ok_or_else(|| Error::from(err_msg("No command")))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
let mut cmd = Command::new(command_string);
|
||||
|
||||
|
@ -163,8 +161,7 @@ fn main() {
|
|||
|
||||
if !command
|
||||
.status()
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.success()
|
||||
{
|
||||
|
@ -177,8 +174,7 @@ fn main() {
|
|||
.into_get_iter(rt.store())
|
||||
.map(|e| {
|
||||
e.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| String::from("Entry not found"))
|
||||
.map_err(StoreError::from)
|
||||
.ok_or_else(|| err_msg("Entry not found"))
|
||||
.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)
|
||||
{
|
||||
let mut tmpfile = tempfile::NamedTempFile::new()
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
if view_header {
|
||||
let hdr = toml::ser::to_string_pretty(entry.get_header())
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes())
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
if !hide_content {
|
||||
let _ = tmpfile.write(entry.get_content().as_bytes())
|
||||
.err_from_str()
|
||||
.map_err(VE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
|
@ -308,7 +300,7 @@ fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_co
|
|||
.path()
|
||||
.to_str()
|
||||
.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);
|
||||
|
||||
(tmpfile, file_path)
|
||||
|
|
|
@ -32,7 +32,6 @@ walkdir = "2"
|
|||
log = "0.4.0"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
is-match = "0.1"
|
||||
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -37,7 +37,6 @@ extern crate clap;
|
|||
extern crate walkdir;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
#[macro_use] extern crate is_match;
|
||||
|
||||
#[macro_use] extern crate libimagrt;
|
||||
extern crate libimagerror;
|
||||
|
@ -56,7 +55,6 @@ use clap::{Arg, ArgMatches, AppSettings, SubCommand};
|
|||
use toml::Value;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
|
||||
use libimagrt::error::RuntimeErrorKind;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::spec::CliSpec;
|
||||
use libimagerror::io::ToExitCode;
|
||||
|
@ -91,7 +89,7 @@ fn help_text(cmds: Vec<String>) -> String {
|
|||
Call a command with 'imag <command> <args>'
|
||||
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.
|
||||
|
||||
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())
|
||||
.map_or_else(|| rtp.clone(), PathBuf::from);
|
||||
debug!("Config path = {:?}", configpath);
|
||||
let config = match ::libimagrt::configuration::fetch_config(&configpath) {
|
||||
Ok(c) => Some(c),
|
||||
Err(e) => if !is_match!(e.kind(), &RuntimeErrorKind::ConfigNoConfigFileFound) {
|
||||
trace_error(&e);
|
||||
::std::process::exit(1)
|
||||
} else {
|
||||
println!("No config file found.");
|
||||
println!("Continuing without configuration file");
|
||||
None
|
||||
},
|
||||
};
|
||||
let config = ::libimagrt::configuration::fetch_config(&configpath)
|
||||
.unwrap_or_else(|e| {
|
||||
trace_error(&e);
|
||||
exit(1)
|
||||
});
|
||||
|
||||
debug!("matches: {:?}", matches);
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4.0"
|
||||
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" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -36,6 +36,7 @@ extern crate clap;
|
|||
#[macro_use] extern crate log;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
#[macro_use] extern crate failure;
|
||||
|
||||
extern crate libimagbookmark;
|
||||
#[macro_use] extern crate libimagrt;
|
||||
|
@ -46,12 +47,12 @@ use std::io::Write;
|
|||
use std::process::exit;
|
||||
|
||||
use toml_query::read::TomlValueReadTypeExt;
|
||||
use failure::Error;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagbookmark::collection::BookmarkCollection;
|
||||
use libimagbookmark::collection::BookmarkCollectionStore;
|
||||
use libimagbookmark::error::BookmarkError as BE;
|
||||
use libimagbookmark::link::Link as BookmarkLink;
|
||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
||||
use libimagerror::io::ToExitCode;
|
||||
|
@ -94,7 +95,7 @@ fn add(rt: &Runtime) {
|
|||
|
||||
let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
|
||||
.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);
|
||||
|
||||
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)
|
||||
.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);
|
||||
|
||||
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)
|
||||
.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);
|
||||
|
||||
for url in scmd.values_of("urls").unwrap() { // enforced by clap
|
||||
|
@ -182,6 +183,7 @@ fn get_collection_name(rt: &Runtime,
|
|||
rt.config()
|
||||
.map(|cfg| {
|
||||
cfg.read_string("bookmark.default_collection")
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| {
|
||||
error!("Missing config: 'bookmark.default_collection'. Set or use commandline to specify.");
|
||||
|
|
|
@ -24,12 +24,13 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4.0"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "update-errorchain" }
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "master" }
|
||||
handlebars = "1.0"
|
||||
walkdir = "2"
|
||||
uuid = { version = "0.7", features = ["v4"] }
|
||||
serde_json = "1"
|
||||
failure = "0.1"
|
||||
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
|
|
|
@ -44,11 +44,10 @@ use vobject::write_component;
|
|||
use toml_query::read::TomlValueReadExt;
|
||||
use toml::Value;
|
||||
use uuid::Uuid;
|
||||
use failure::Error;
|
||||
|
||||
use libimagcontact::store::ContactStore;
|
||||
use libimagcontact::error::ContactError as CE;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::str::ErrFromStr;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagutil::warn_result::WarnResult;
|
||||
|
@ -126,8 +125,7 @@ pub fn create(rt: &Runtime) {
|
|||
.create_new(true)
|
||||
.open(fl.clone())
|
||||
.map_warn_err_str("Cannot create/open destination File. Stopping.")
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let uuid_string = uuid
|
||||
|
@ -161,8 +159,7 @@ pub fn create(rt: &Runtime) {
|
|||
|
||||
match ::toml::de::from_str(&template)
|
||||
.map(|toml| parse_toml_into_vcard(toml, uuid.clone()))
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
{
|
||||
Err(e) => {
|
||||
error!("Error parsing template");
|
||||
|
@ -183,7 +180,7 @@ pub fn create(rt: &Runtime) {
|
|||
let vcard_string = write_component(&vcard);
|
||||
let _ = dest
|
||||
.write_all(&vcard_string.as_bytes())
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
break;
|
||||
|
@ -244,7 +241,7 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
|||
|
||||
{ // parse 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)) => {
|
||||
for (i, element) in ary.iter().enumerate() {
|
||||
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
|
||||
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)) => {
|
||||
for (i, element) in ary.iter().enumerate() {
|
||||
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
|
||||
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)) => {
|
||||
for (i, element) in ary.iter().enumerate() {
|
||||
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
|
||||
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)) => {
|
||||
for (i, element) in ary.iter().enumerate() {
|
||||
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>> {
|
||||
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))) => {
|
||||
let mut v = Vec::new();
|
||||
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> {
|
||||
let v = toml.read(path)
|
||||
.map_err(Error::from)
|
||||
.map_warn_err_str(&format!("Failed to read value at '{}'", path));
|
||||
|
||||
match v {
|
||||
|
|
|
@ -41,6 +41,7 @@ extern crate handlebars;
|
|||
extern crate walkdir;
|
||||
extern crate uuid;
|
||||
extern crate serde_json;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimagcontact;
|
||||
extern crate libimagstore;
|
||||
|
@ -58,16 +59,16 @@ use handlebars::Handlebars;
|
|||
use clap::ArgMatches;
|
||||
use toml_query::read::TomlValueReadTypeExt;
|
||||
use walkdir::WalkDir;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagerror::str::ErrFromStr;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagcontact::store::ContactStore;
|
||||
use libimagcontact::error::ContactError as CE;
|
||||
use libimagcontact::contact::Contact;
|
||||
use libimagcontact::deser::DeserVcard;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
|
@ -121,7 +122,7 @@ fn list(rt: &Runtime) {
|
|||
.map(|fle| {
|
||||
let fle = fle
|
||||
.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);
|
||||
|
||||
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);
|
||||
|
||||
list_format.render("format", &data)
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
})
|
||||
|
||||
|
@ -175,8 +175,7 @@ fn import(rt: &Runtime) {
|
|||
} else if path.is_dir() {
|
||||
for entry in WalkDir::new(path).min_depth(1).into_iter() {
|
||||
let entry = entry
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
if entry.file_type().is_file() {
|
||||
let pb = PathBuf::from(entry.path());
|
||||
|
@ -233,8 +232,7 @@ fn show(rt: &Runtime) {
|
|||
|
||||
let s = show_format
|
||||
.render("format", &data)
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
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 s = fmt
|
||||
.render("format", &data)
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
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)
|
||||
.unwrap_or_else(|| {
|
||||
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)
|
||||
.read_string(config_value_path)
|
||||
.map_err(Error::from)
|
||||
.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)
|
||||
});
|
||||
|
||||
let mut hb = Handlebars::new();
|
||||
let _ = hb
|
||||
.register_template_string("format", fmt)
|
||||
.err_from_str()
|
||||
.map_err(CE::from)
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
hb.register_escape_fn(::handlebars::no_escape);
|
||||
|
|
|
@ -25,8 +25,9 @@ maintenance = { status = "actively-developed" }
|
|||
chrono = "0.4"
|
||||
log = "0.4.0"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
itertools = "0.7"
|
||||
failure = "0.1"
|
||||
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
|
|
|
@ -21,10 +21,11 @@ use clap::ArgMatches;
|
|||
use chrono::NaiveDateTime;
|
||||
use chrono::Local;
|
||||
use chrono::Timelike;
|
||||
use failure::Error;
|
||||
use failure::ResultExt;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagdiary::diary::Diary;
|
||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
||||
use libimagdiary::error::ResultExt;
|
||||
use libimagentryedit::edit::Edit;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
@ -47,8 +48,7 @@ pub fn create(rt: &Runtime) {
|
|||
Ok(())
|
||||
} else {
|
||||
debug!("Editing new diary entry");
|
||||
entry.edit_content(rt)
|
||||
.chain_err(|| DEK::DiaryEditError)
|
||||
entry.edit_content(rt).context(err_msg("Diary edit error")).map_err(Error::from)
|
||||
};
|
||||
|
||||
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| {
|
||||
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(|| {
|
||||
debug!("Creating non-timed entry");
|
||||
|
|
|
@ -29,9 +29,10 @@ use libimagerror::exit::ExitUnwrap;
|
|||
use libimagutil::debug_result::*;
|
||||
use libimagdiary::diaryid::DiaryId;
|
||||
use libimagdiary::diaryid::FromStoreId;
|
||||
use libimagdiary::error::Result;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
|
||||
use util::get_diary_name;
|
||||
|
||||
pub fn list(rt: &Runtime) {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate failure;
|
||||
extern crate clap;
|
||||
extern crate chrono;
|
||||
extern crate toml;
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
//
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagdiary::error::*;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use toml::Value;
|
||||
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> {
|
||||
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) => {
|
||||
let v = cfg
|
||||
.read(&format!("diary.diaries.{}.timed", diary_name))
|
||||
.chain_err(|| DiaryErrorKind::IOError);
|
||||
.context(EM::IO)
|
||||
.map_err(Error::from);
|
||||
|
||||
match v {
|
||||
Ok(Some(&Value::String(ref s))) => parse_timed_string(s, diary_name).map(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);
|
||||
Err(s).map_err(From::from)
|
||||
Err(format_err!("{}", s))
|
||||
},
|
||||
|
||||
Ok(None) => Ok(None),
|
||||
|
@ -87,6 +91,6 @@ pub fn parse_timed_string(s: &str, diary_name: &str) -> Result<Timed> {
|
|||
} else {
|
||||
let s = format!("Cannot parse config: 'diary.diaries.{}.timed = {}'",
|
||||
diary_name, s);
|
||||
Err(s).map_err(From::from)
|
||||
Err(format_err!("{}", s))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,10 @@ maintenance = { status = "actively-developed" }
|
|||
chrono = "0.4"
|
||||
log = "0.4"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "master" }
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "failure" }
|
||||
prettytable-rs = "0.8"
|
||||
failure = "0.1"
|
||||
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
|
|
|
@ -39,6 +39,7 @@ extern crate toml_query;
|
|||
extern crate kairos;
|
||||
extern crate chrono;
|
||||
extern crate prettytable;
|
||||
#[macro_use] extern crate failure;
|
||||
|
||||
extern crate libimaghabit;
|
||||
extern crate libimagstore;
|
||||
|
@ -53,6 +54,7 @@ use std::process::exit;
|
|||
use prettytable::Table;
|
||||
use prettytable::Cell;
|
||||
use prettytable::Row;
|
||||
use failure::Error;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
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`
|
||||
// was passed.
|
||||
fn today(rt: &Runtime, future: bool) {
|
||||
use libimaghabit::error::ResultExt;
|
||||
use libimaghabit::error::HabitErrorKind as HEK;
|
||||
use failure::ResultExt;
|
||||
|
||||
let (future, show_done) = {
|
||||
if !future {
|
||||
|
@ -296,7 +297,8 @@ fn today(rt: &Runtime, future: bool) {
|
|||
am.value_of("today-show-next-n")
|
||||
.map(|x| {
|
||||
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)
|
||||
})
|
||||
}).unwrap_or(5);
|
||||
|
|
|
@ -24,9 +24,10 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
is-match = "0.1"
|
||||
itertools = "0.7"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -38,6 +38,7 @@ extern crate clap;
|
|||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate itertools;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimaglog;
|
||||
#[macro_use] extern crate libimagrt;
|
||||
|
@ -47,6 +48,9 @@ extern crate libimagdiary;
|
|||
|
||||
use std::io::Write;
|
||||
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
@ -55,7 +59,6 @@ use libimagerror::exit::ExitUnwrap;
|
|||
use libimagerror::iter::TraceIterator;
|
||||
use libimagdiary::diary::Diary;
|
||||
use libimaglog::log::Log;
|
||||
use libimaglog::error::LogError as LE;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
|
||||
mod ui;
|
||||
|
@ -175,16 +178,17 @@ fn get_diary_name(rt: &Runtime) -> String {
|
|||
|
||||
let cfg = rt
|
||||
.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);
|
||||
|
||||
let logs = cfg
|
||||
.read("log.logs")
|
||||
.map_err(Error::from)
|
||||
.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)
|
||||
.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);
|
||||
|
||||
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
|
||||
.read_string("log.default")
|
||||
.map_err(Error::from)
|
||||
.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);
|
||||
|
||||
if !logs.contains(¤t_log) {
|
||||
|
|
|
@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" }
|
|||
|
||||
[dependencies]
|
||||
log = "0.4.0"
|
||||
failure = "0.1"
|
||||
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
extern crate clap;
|
||||
#[macro_use] extern crate log;
|
||||
extern crate failure;
|
||||
|
||||
#[macro_use] extern crate libimagrt;
|
||||
extern crate libimagmail;
|
||||
|
@ -42,6 +43,9 @@ extern crate libimagutil;
|
|||
|
||||
use std::io::Write;
|
||||
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
|
@ -91,8 +95,7 @@ fn import_mail(rt: &Runtime) {
|
|||
}
|
||||
|
||||
fn list(rt: &Runtime) {
|
||||
use libimagmail::error::MailErrorKind as MEK;
|
||||
use libimagmail::error::ResultExt;
|
||||
use failure::ResultExt;
|
||||
|
||||
// TODO: Implement lister type in libimagmail for this
|
||||
fn list_mail(rt: &Runtime, m: Mail) {
|
||||
|
@ -149,7 +152,8 @@ fn list(rt: &Runtime) {
|
|||
.filter_map(|id| {
|
||||
rt.store()
|
||||
.get(id)
|
||||
.chain_err(|| MEK::RefHandlingError)
|
||||
.context(err_msg("Ref handling error"))
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.map(|fle| Mail::from_fle(fle).map_err_trace().ok())
|
||||
})
|
||||
|
|
|
@ -27,7 +27,8 @@ chrono = "0.4"
|
|||
filters = "0.3"
|
||||
itertools = "0.7"
|
||||
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" }
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
|
|
|
@ -22,13 +22,13 @@ use std::str::FromStr;
|
|||
|
||||
use filters::filter::Filter;
|
||||
use chrono::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagtimetrack::timetracking::TimeTracking;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
|
@ -44,7 +44,7 @@ pub fn day(rt: &Runtime) -> i32 {
|
|||
let filter = {
|
||||
let start = match cmd.value_of("start").map(NaiveDateTime::from_str) {
|
||||
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,
|
||||
Err(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) {
|
||||
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,
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
|
@ -91,7 +91,7 @@ pub fn day(rt: &Runtime) -> i32 {
|
|||
.map_err_trace_exit_unwrap(1)
|
||||
.trace_unwrap()
|
||||
.filter(|e| filter.filter(e))
|
||||
.map(|e| -> Result<_, TTE> {
|
||||
.map(|e| -> Result<_, Error> {
|
||||
debug!("Processing {:?}", e.get_location());
|
||||
|
||||
let tag = e.get_timetrack_tag()?;
|
||||
|
|
|
@ -25,15 +25,17 @@ use prettytable::Cell;
|
|||
use kairos::parser::Parsed;
|
||||
use kairos::parser::parse as kairos_parse;
|
||||
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::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagtimetrack::error::TimeTrackError;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagtimetrack::timetracking::TimeTracking;
|
||||
use libimagtimetrack::error::Result;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
|
||||
|
@ -63,6 +65,7 @@ pub fn list(rt: &Runtime) -> i32 {
|
|||
::std::process::exit(1)
|
||||
},
|
||||
Some(Err(e)) => {
|
||||
let e = Error::from(e);
|
||||
trace_error(&e);
|
||||
::std::process::exit(1)
|
||||
}
|
||||
|
@ -164,7 +167,8 @@ pub fn list_impl(rt: &Runtime,
|
|||
})
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.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_err_trace()
|
||||
.unwrap_or(1)
|
||||
|
|
|
@ -41,6 +41,7 @@ extern crate filters;
|
|||
extern crate itertools;
|
||||
extern crate prettytable;
|
||||
extern crate kairos;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimagerror;
|
||||
extern crate libimagstore;
|
||||
|
|
|
@ -22,13 +22,13 @@ use std::str::FromStr;
|
|||
|
||||
use filters::filter::Filter;
|
||||
use chrono::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagtimetrack::timetracking::TimeTracking;
|
||||
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) {
|
||||
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,
|
||||
Err(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)
|
||||
},
|
||||
Some(s) => match s.map_err(TTE::from) {
|
||||
Some(s) => match s.map_err(Error::from) {
|
||||
Ok(dt) => dt,
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
|
@ -106,7 +106,7 @@ pub fn month(rt: &Runtime) -> i32 {
|
|||
.map_err_trace_exit_unwrap(1)
|
||||
.trace_unwrap()
|
||||
.filter(|e| filter.filter(e))
|
||||
.map(|e| -> Result<_, TTE> {
|
||||
.map(|e| -> Result<_, Error> {
|
||||
debug!("Processing {:?}", e.get_location());
|
||||
|
||||
let tag = e.get_timetrack_tag()?;
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use chrono::naive::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
@ -34,7 +34,7 @@ pub fn start(rt: &Runtime) -> i32 {
|
|||
|
||||
let start = match cmd.value_of("start-time") {
|
||||
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,
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
|
|
|
@ -21,13 +21,13 @@ use std::str::FromStr;
|
|||
|
||||
use filters::filter::Filter;
|
||||
use chrono::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagrt::runtime::Runtime;
|
||||
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::timetracking::TimeTracking;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
use libimagtimetrack::timetrackingstore::*;
|
||||
|
@ -42,7 +42,7 @@ pub fn stop(rt: &Runtime) -> i32 {
|
|||
|
||||
let stop_time = match cmd.value_of("stop-time") {
|
||||
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,
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
|
|
|
@ -22,10 +22,10 @@ use std::process::exit;
|
|||
use clap::ArgMatches;
|
||||
use chrono::naive::NaiveDate;
|
||||
use chrono::naive::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
@ -43,10 +43,10 @@ pub fn track(rt: &Runtime) -> i32 {
|
|||
match cmd.value_of(clap_name) {
|
||||
Some("now") => Some(::chrono::offset::Local::now().naive_local()),
|
||||
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),
|
||||
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)),
|
||||
Err(e_nd) => {
|
||||
error!("Cannot parse date {}:", errname);
|
||||
|
|
|
@ -22,13 +22,13 @@ use std::str::FromStr;
|
|||
|
||||
use filters::filter::Filter;
|
||||
use chrono::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagtimetrack::timetracking::TimeTracking;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
|
@ -50,7 +50,7 @@ pub fn week(rt: &Runtime) -> i32 {
|
|||
let start = match cmd
|
||||
.value_of("start")
|
||||
.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)
|
||||
|
@ -65,7 +65,7 @@ pub fn week(rt: &Runtime) -> i32 {
|
|||
let end = match cmd
|
||||
.value_of("end")
|
||||
.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)
|
||||
|
@ -104,7 +104,7 @@ pub fn week(rt: &Runtime) -> i32 {
|
|||
.map_err_trace_exit_unwrap(1)
|
||||
.trace_unwrap()
|
||||
.filter(|e| filter.filter(e))
|
||||
.map(|e| -> Result<_, TTE> {
|
||||
.map(|e| -> Result<_, Error> {
|
||||
debug!("Processing {:?}", e.get_location());
|
||||
|
||||
let tag = e.get_timetrack_tag()?;
|
||||
|
|
|
@ -22,13 +22,13 @@ use std::str::FromStr;
|
|||
|
||||
use filters::filter::Filter;
|
||||
use chrono::NaiveDateTime;
|
||||
use failure::Error;
|
||||
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagtimetrack::error::TimeTrackError as TTE;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagtimetrack::timetracking::TimeTracking;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
|
@ -49,7 +49,7 @@ pub fn year(rt: &Runtime) -> i32 {
|
|||
let start = match cmd
|
||||
.value_of("start")
|
||||
.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),
|
||||
|
@ -63,7 +63,7 @@ pub fn year(rt: &Runtime) -> i32 {
|
|||
let end = match cmd
|
||||
.value_of("end")
|
||||
.map(|s| {
|
||||
::chrono::naive::NaiveDateTime::from_str(s).map_err(TTE::from)
|
||||
::chrono::naive::NaiveDateTime::from_str(s).map_err(Error::from)
|
||||
})
|
||||
{
|
||||
None => {
|
||||
|
@ -104,7 +104,7 @@ pub fn year(rt: &Runtime) -> i32 {
|
|||
.map_err_trace_exit_unwrap(1)
|
||||
.trace_unwrap()
|
||||
.filter(|e| filter.filter(e))
|
||||
.map(|e| -> Result<_, TTE> {
|
||||
.map(|e| -> Result<_, Error> {
|
||||
debug!("Processing {:?}", e.get_location());
|
||||
|
||||
let tag = e.get_timetrack_tag()?;
|
||||
|
|
|
@ -24,8 +24,9 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
log = "0.4.0"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
is-match = "0.1"
|
||||
failure = "0.1"
|
||||
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -37,6 +37,7 @@ extern crate clap;
|
|||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
#[macro_use] extern crate is_match;
|
||||
extern crate failure;
|
||||
|
||||
#[macro_use] extern crate libimagrt;
|
||||
extern crate libimagerror;
|
||||
|
@ -45,6 +46,7 @@ extern crate libimagtodo;
|
|||
use std::process::{Command, Stdio};
|
||||
use std::io::stdin;
|
||||
use std::io::Write;
|
||||
use failure::Error;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
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.
|
||||
//
|
||||
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
|
||||
|
@ -136,7 +138,7 @@ fn list(rt: &Runtime) {
|
|||
},
|
||||
Err(e) => {
|
||||
if !no_identifier(&e) {
|
||||
trace_error(&e);
|
||||
trace_error(&Error::from(e));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ fn main() {
|
|||
let version = make_imag_version!();
|
||||
let rt = generate_runtime_setup("imag-wiki",
|
||||
&version,
|
||||
"Manage a personal Wiki",
|
||||
"Personal wiki",
|
||||
build_ui);
|
||||
|
||||
let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default");
|
||||
|
|
|
@ -20,6 +20,7 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
|
|||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
ansi_term = "0.11"
|
||||
error-chain = "0.12"
|
||||
log = "0.4"
|
||||
ansi_term = "0.11"
|
||||
failure = "0.1"
|
||||
failure_derive = "0.1"
|
||||
|
|
105
lib/core/libimagerror/src/errors.rs
Normal file
105
lib/core/libimagerror/src/errors.rs
Normal 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,
|
||||
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// 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
|
||||
/// closure `f`.
|
||||
|
@ -31,9 +31,10 @@ pub struct UnwrapWith<I, F>{
|
|||
f: F
|
||||
}
|
||||
|
||||
impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
|
||||
I: Iterator<Item = Result<T, E>>,
|
||||
F: FnMut(E)
|
||||
impl<I, F, T> Iterator for UnwrapWith<I, F>
|
||||
where
|
||||
I: Iterator<Item = Result<T, Error>>,
|
||||
F: FnMut(Error)
|
||||
{
|
||||
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> {
|
||||
loop {
|
||||
match self.iter.next() {
|
||||
Some(Err(e)) => {
|
||||
(self.f)(e);
|
||||
},
|
||||
Some(Err(e)) => { (self.f)(e); },
|
||||
Some(Ok(item)) => return Some(item),
|
||||
None => return None,
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
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
|
||||
pub struct UnwrapExit<I, T, E>(I, i32)
|
||||
where I: Iterator<Item = Result<T, E>>,
|
||||
E: ChainedError;
|
||||
pub struct UnwrapExit<I, T>(I, i32)
|
||||
where I: Iterator<Item = Result<T, Error>>;
|
||||
|
||||
impl<I, T, E> Iterator for UnwrapExit<I, T, E>
|
||||
where I: Iterator<Item = Result<T, E>>,
|
||||
E: ChainedError
|
||||
impl<I, T> Iterator for UnwrapExit<I, T>
|
||||
where I: Iterator<Item = Result<T, Error>>,
|
||||
{
|
||||
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>
|
||||
where I: DoubleEndedIterator<Item = Result<T, E>>,
|
||||
E: ChainedError
|
||||
impl<I, T> DoubleEndedIterator for UnwrapExit<I, T>
|
||||
where I: DoubleEndedIterator<Item = Result<T, Error>>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
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`.
|
||||
pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
|
||||
/// Creates an iterator that yields the item in each `Ok` item, while filtering out the `Err`
|
||||
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`
|
||||
/// 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,
|
||||
/// nothing will be passed to `::trace::trace_error`, no matter how many `Err` items might
|
||||
/// be present.
|
||||
#[inline]
|
||||
fn trace_unwrap<K>(self) -> UnwrapWith<Self, fn(E)> where E: ChainedError<ErrorKind = K> {
|
||||
fn trace_unwrap(self) -> UnwrapWith<Self, fn(Error)> {
|
||||
#[inline]
|
||||
fn trace_error<K, E: ChainedError<ErrorKind = K>>(err: E) {
|
||||
eprintln!("{}", err.display_chain());
|
||||
fn trace_error(err: Error) {
|
||||
err.iter_chain().for_each(|cause| {
|
||||
eprintln!("{}", cause);
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
/// be present.
|
||||
#[inline]
|
||||
fn trace_unwrap_exit(self, exitcode: i32) -> UnwrapExit<Self, T, E>
|
||||
where E: ChainedError
|
||||
{
|
||||
fn trace_unwrap_exit(self, exitcode: i32) -> UnwrapExit<Self, T> {
|
||||
UnwrapExit(self, exitcode)
|
||||
}
|
||||
|
||||
|
||||
/// 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
|
||||
/// 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.
|
||||
#[inline]
|
||||
fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F>
|
||||
where F: FnMut(E)
|
||||
where F: FnMut(Error)
|
||||
{
|
||||
UnwrapWith { iter: self, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T, E> TraceIterator<T, E> for I where
|
||||
I: Iterator<Item = Result<T, E>>
|
||||
impl<I, T> TraceIterator<T> for I where
|
||||
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)]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,11 +35,13 @@
|
|||
|
||||
#[macro_use] extern crate log;
|
||||
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 trace;
|
||||
pub mod io;
|
||||
pub mod iter;
|
||||
pub mod str;
|
||||
pub mod trace;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::process::exit;
|
|||
use std::fmt::Display;
|
||||
use std::fmt::Formatter;
|
||||
use std::fmt::Result as FmtResult;
|
||||
use error_chain::ChainedError;
|
||||
use failure::Error;
|
||||
use ansi_term::Colour::Red;
|
||||
|
||||
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>
|
||||
where T: ChainedError
|
||||
impl<'a> Display for ImagTrace<'a, Error>
|
||||
{
|
||||
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() {
|
||||
try!(writeln!(fmt, "{}", Red.paint("--- BACKTRACE ---")));
|
||||
try!(writeln!(fmt, "{:?}", backtrace));
|
||||
}
|
||||
let _ = writeln!(fmt, "{}", Red.paint("--- BACKTRACE ---"))?;
|
||||
let _ = writeln!(fmt, "{:?}", self.0.backtrace())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn trace_error<K, C: ChainedError<ErrorKind = K>>(e: &C) {
|
||||
pub fn trace_error(e: &Error) {
|
||||
eprintln!("{}", ImagTrace::new(e));
|
||||
}
|
||||
|
||||
pub fn trace_error_dbg<K, C: ChainedError<ErrorKind = K>>(e: &C) {
|
||||
debug!("{}", e.display_chain());
|
||||
pub fn trace_error_dbg(e: &Error) {
|
||||
debug!("{}", ImagTrace::new(e));
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
impl<U, K, E: ChainedError<ErrorKind = K>> MapErrTrace for Result<U, E> {
|
||||
impl<U> MapErrTrace for Result<U, Error> {
|
||||
type Output = U;
|
||||
|
||||
/// Simply call `trace_error()` on the Err (if there is one) and return the error.
|
||||
|
|
|
@ -25,10 +25,10 @@ toml = "0.4"
|
|||
xdg-basedir = "1.0"
|
||||
itertools = "0.7"
|
||||
ansi_term = "0.11"
|
||||
is-match = "0.1"
|
||||
toml-query = "0.7"
|
||||
error-chain = "0.12"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
atty = "0.2"
|
||||
failure = "0.1"
|
||||
failure_derive = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -21,20 +21,19 @@ use std::path::PathBuf;
|
|||
|
||||
use toml::Value;
|
||||
use clap::App;
|
||||
use failure::ResultExt;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use error::RuntimeError as RE;
|
||||
use error::RuntimeErrorKind as REK;
|
||||
use error::Result;
|
||||
use error::ResultExt;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
/// Get a new configuration object.
|
||||
///
|
||||
/// 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
|
||||
/// with all variants.
|
||||
///
|
||||
/// If that doesn't work either, an error is returned.
|
||||
pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
||||
pub fn fetch_config(searchpath: &PathBuf) -> Result<Option<Value>> {
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
@ -65,7 +64,7 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
|||
.unwrap_or(vec![]),
|
||||
];
|
||||
|
||||
Itertools::flatten(vals.iter())
|
||||
let config = Itertools::flatten(vals.iter())
|
||||
.filter(|path| path.exists() && path.is_file())
|
||||
.filter_map(|path| {
|
||||
let content = {
|
||||
|
@ -90,13 +89,14 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
|||
.unwrap_or_else(|| String::from("Line unknown, Column unknown"));
|
||||
|
||||
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);
|
||||
None
|
||||
})
|
||||
})
|
||||
.nth(0)
|
||||
.ok_or(RE::from_kind(REK::ConfigNoConfigFileFound))
|
||||
.nth(0);
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Override the configuration.
|
||||
|
@ -120,16 +120,16 @@ pub fn override_config(val: &mut Value, v: Vec<String>) -> Result<()> {
|
|||
.map(|(k, v)| {
|
||||
let value = val
|
||||
.read(&k)
|
||||
.chain_err(|| REK::ConfigTOMLParserError)?
|
||||
.ok_or(RE::from_kind(REK::ConfigOverrideKeyNotAvailable))?;
|
||||
.context(EM::TomlQueryError)?
|
||||
.ok_or_else(|| Error::from(err_msg("Confit parser error")))?;
|
||||
|
||||
into_value(value, 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 {
|
||||
let _ = try!(elem.chain_err(|| REK::ConfigOverrideError));
|
||||
let _ = elem.context(err_msg("Config override error"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -36,17 +36,16 @@
|
|||
)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate error_chain;
|
||||
extern crate itertools;
|
||||
#[cfg(unix)] extern crate xdg_basedir;
|
||||
extern crate env_logger;
|
||||
extern crate ansi_term;
|
||||
extern crate handlebars;
|
||||
#[macro_use] extern crate failure;
|
||||
|
||||
extern crate clap;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
#[macro_use] extern crate is_match;
|
||||
extern crate atty;
|
||||
|
||||
extern crate libimagstore;
|
||||
|
@ -54,7 +53,6 @@ extern crate libimagutil;
|
|||
extern crate libimagerror;
|
||||
extern crate libimaginteraction;
|
||||
|
||||
pub mod error;
|
||||
pub mod configuration;
|
||||
pub mod logger;
|
||||
pub mod io;
|
||||
|
|
|
@ -24,11 +24,12 @@ use std::sync::Arc;
|
|||
use std::sync::Mutex;
|
||||
use std::ops::Deref;
|
||||
|
||||
use error::RuntimeErrorKind as EK;
|
||||
use error::RuntimeError as RE;
|
||||
use error::ResultExt;
|
||||
use runtime::Runtime;
|
||||
|
||||
use failure::ResultExt;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
use clap::ArgMatches;
|
||||
use log::{Log, Level, Record, Metadata};
|
||||
use toml::Value;
|
||||
|
@ -36,10 +37,10 @@ use toml_query::read::TomlValueReadExt;
|
|||
use toml_query::read::TomlValueReadTypeExt;
|
||||
use handlebars::Handlebars;
|
||||
|
||||
type ModuleName = String;
|
||||
type Result<T> = ::std::result::Result<T, RE>;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
type ModuleName = String;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum LogDestination {
|
||||
Stderr,
|
||||
File(Arc<Mutex<::std::fs::File>>),
|
||||
|
@ -51,7 +52,6 @@ impl Default for LogDestination {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ModuleSettings {
|
||||
enabled: bool,
|
||||
level: Option<Level>,
|
||||
|
@ -89,32 +89,39 @@ impl ImagLogger {
|
|||
|
||||
{
|
||||
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)?;
|
||||
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)?;
|
||||
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)?;
|
||||
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)?;
|
||||
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 {
|
||||
global_loglevel : aggregate_global_loglevel(matches, config)?,
|
||||
global_destinations : aggregate_global_destinations(matches, config)?,
|
||||
module_settings : module_settings,
|
||||
module_settings : aggregate_module_settings(matches, config)?,
|
||||
handlebars : handlebars,
|
||||
})
|
||||
}
|
||||
|
@ -179,35 +186,28 @@ impl Log for ImagLogger {
|
|||
self.module_settings
|
||||
.get(record_target)
|
||||
.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 &&
|
||||
module_setting.level.unwrap_or(self.global_loglevel) >= record.level();
|
||||
|
||||
if set { // if we want to log from a setting standpoint
|
||||
// get the destinations for the module and log to all of them
|
||||
if set {
|
||||
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() {
|
||||
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(|| {
|
||||
if self.global_loglevel >= record.level() { // if logging is enabled for that level
|
||||
self.global_destinations
|
||||
.iter()
|
||||
.for_each(|d| { // log to all global destinations
|
||||
let _ = log_to_destination(&d); // ignore errors, because what else?
|
||||
});
|
||||
if self.global_loglevel >= record.level() {
|
||||
// Yes, we log
|
||||
for d in self.global_destinations.iter() {
|
||||
// If there's an error, we cannot do anything, can we?
|
||||
let _ = log_to_destination(&d);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ fn match_log_level_str(s: &str) -> Result<Level> {
|
|||
"info" => Ok(Level::Info),
|
||||
"warn" => Ok(Level::Warn),
|
||||
"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 {
|
||||
let cfg_loglevel = cfg
|
||||
.read_string("imag.logging.level")?
|
||||
.ok_or(RE::from_kind(EK::GlobalLogLevelConfigMissing))
|
||||
.read_string("imag.logging.level")
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.ok_or(err_msg("Global log level config missing"))
|
||||
.and_then(|s| match_log_level_str(&s))?;
|
||||
|
||||
if let Some(cli_loglevel) = get_arg_loglevel(matches)? {
|
||||
|
@ -273,7 +275,9 @@ fn translate_destination(raw: &str) -> Result<LogDestination> {
|
|||
.map(Mutex::new)
|
||||
.map(Arc::new)
|
||||
.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| {
|
||||
let dest = val.as_str()
|
||||
.ok_or_else(|| {
|
||||
let path = "imag.logging.modules.<mod>.destinations".to_owned();
|
||||
let path = "imag.logging.modules.<mod>.destinations";
|
||||
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)?;
|
||||
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>)
|
||||
-> Result<Vec<LogDestination>>
|
||||
{
|
||||
let config_log_dest_path = "imag.logging.destinations";
|
||||
|
||||
match config {
|
||||
Some(cfg) => cfg
|
||||
.read(&config_log_dest_path)?
|
||||
.ok_or_else(|| RE::from_kind(EK::GlobalDestinationConfigMissing))?
|
||||
.read("imag.logging.destinations")
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.ok_or_else(|| err_msg("Global log destination config missing"))?
|
||||
.as_array()
|
||||
.ok_or_else(|| {
|
||||
let path = config_log_dest_path.to_owned();
|
||||
let path = "imag.logging.destinations";
|
||||
let ty = "Array";
|
||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
||||
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||
})
|
||||
.and_then(translate_destinations),
|
||||
None => {
|
||||
|
@ -330,10 +336,12 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
|
|||
}
|
||||
|
||||
macro_rules! aggregate_global_format {
|
||||
($read_str:expr, $error_kind_if_missing:expr, $config:expr) => {
|
||||
try!($config.ok_or(RE::from_kind($error_kind_if_missing)))
|
||||
.read_string($read_str)?
|
||||
.ok_or_else(|| RE::from_kind($error_kind_if_missing))
|
||||
($read_str:expr, $error_msg_if_missing:expr, $config:expr) => {
|
||||
try!($config.ok_or_else(|| Error::from(err_msg($error_msg_if_missing))))
|
||||
.read_string($read_str)
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.ok_or_else(|| Error::from(err_msg($error_msg_if_missing)))
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -341,43 +349,43 @@ fn aggregate_global_format_trace(config: Option<&Value>)
|
|||
-> Result<String>
|
||||
{
|
||||
aggregate_global_format!("imag.logging.format.trace",
|
||||
EK::ConfigMissingLoggingFormatTrace,
|
||||
config)
|
||||
"Config missing: Logging format: Trace",
|
||||
config)
|
||||
}
|
||||
|
||||
fn aggregate_global_format_debug(config: Option<&Value>)
|
||||
-> Result<String>
|
||||
{
|
||||
aggregate_global_format!("imag.logging.format.debug",
|
||||
EK::ConfigMissingLoggingFormatDebug,
|
||||
config)
|
||||
"Config missing: Logging format: Debug",
|
||||
config)
|
||||
}
|
||||
|
||||
fn aggregate_global_format_info(config: Option<&Value>)
|
||||
-> Result<String>
|
||||
{
|
||||
aggregate_global_format!("imag.logging.format.info",
|
||||
EK::ConfigMissingLoggingFormatInfo,
|
||||
config)
|
||||
"Config missing: Logging format: Info",
|
||||
config)
|
||||
}
|
||||
|
||||
fn aggregate_global_format_warn(config: Option<&Value>)
|
||||
-> Result<String>
|
||||
{
|
||||
aggregate_global_format!("imag.logging.format.warn",
|
||||
EK::ConfigMissingLoggingFormatWarn,
|
||||
config)
|
||||
"Config missing: Logging format: Warn",
|
||||
config)
|
||||
}
|
||||
|
||||
fn aggregate_global_format_error(config: Option<&Value>)
|
||||
-> Result<String>
|
||||
{
|
||||
aggregate_global_format!("imag.logging.format.error",
|
||||
EK::ConfigMissingLoggingFormatError,
|
||||
config)
|
||||
"Config missing: Logging format: Error",
|
||||
config)
|
||||
}
|
||||
|
||||
fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
|
||||
fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
|
||||
-> Result<BTreeMap<ModuleName, ModuleSettings>>
|
||||
{
|
||||
// Helper macro to return the error from Some(Err(_)) and map everything else to an
|
||||
|
@ -393,44 +401,43 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
|
|||
};
|
||||
|
||||
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))) => {
|
||||
// translate the module settings from the table `t`
|
||||
let mut settings = BTreeMap::new();
|
||||
|
||||
for (module_name, v) in t {
|
||||
let destinations = inner_try! {
|
||||
v.read("destinations")?
|
||||
v.read("destinations")
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.map(|val| {
|
||||
val.as_array()
|
||||
.ok_or_else(|| {
|
||||
let path = "imag.logging.modules.<mod>.destinations".to_owned();
|
||||
let path = "imag.logging.modules.<mod>.destinations";
|
||||
let ty = "Array";
|
||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
||||
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||
})
|
||||
.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! {
|
||||
v.read_string("level")?.map(|s| match_log_level_str(&s))
|
||||
};
|
||||
|
||||
(false, level)
|
||||
let level = inner_try! {
|
||||
v.read_string("level")
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.map(|s| match_log_level_str(&s))
|
||||
};
|
||||
|
||||
let enabled = pre_enabled ||
|
||||
v.read("enabled")?
|
||||
.map(|v| v.as_bool().unwrap_or(false))
|
||||
.ok_or_else(|| {
|
||||
let path = "imag.logging.modules.<mod>.enabled".to_owned();
|
||||
let ty = "Boolean";
|
||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
||||
})?;
|
||||
let enabled = v.read("enabled")
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.map(|v| v.as_bool().unwrap_or(false))
|
||||
.ok_or_else(|| {
|
||||
let path = "imag.logging.modules.<mod>.enabled";
|
||||
let ty = "Boolean";
|
||||
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||
})?;
|
||||
|
||||
let module_settings = ModuleSettings {
|
||||
enabled: enabled,
|
||||
|
@ -445,15 +452,15 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
|
|||
Ok(settings)
|
||||
},
|
||||
Ok(Some(_)) => {
|
||||
let path = "imag.logging.modules".to_owned();
|
||||
let path = "imag.logging.modules";
|
||||
let ty = "Table";
|
||||
Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
|
||||
Err(Error::from(format_err!("Type error at {}, expected {}", path, ty)))
|
||||
},
|
||||
Ok(None) => {
|
||||
// No modules configured. This is okay!
|
||||
Ok(BTreeMap::new())
|
||||
},
|
||||
Err(e) => Err(e).map_err(From::from),
|
||||
Err(e) => Err(e).context(EM::TomlQueryError).map_err(Error::from),
|
||||
},
|
||||
None => {
|
||||
write!(stderr(), "No Configuration.").ok();
|
||||
|
|
|
@ -30,14 +30,16 @@ use toml::Value;
|
|||
use toml_query::read::TomlValueReadExt;
|
||||
|
||||
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 error::RuntimeError;
|
||||
use error::RuntimeErrorKind;
|
||||
use error::ResultExt;
|
||||
use logger::ImagLogger;
|
||||
use io::OutputProxy;
|
||||
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
use libimagerror::trace::*;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
||||
|
@ -62,7 +64,7 @@ impl<'a> Runtime<'a> {
|
|||
/// and builds the Runtime object with it.
|
||||
///
|
||||
/// 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
|
||||
{
|
||||
use libimagerror::trace::trace_error;
|
||||
|
@ -76,17 +78,15 @@ impl<'a> Runtime<'a> {
|
|||
|
||||
debug!("Config path = {:?}", configpath);
|
||||
|
||||
let config = match fetch_config(&configpath) {
|
||||
Err(e) => if !is_match!(e.kind(), &RuntimeErrorKind::ConfigNoConfigFileFound) {
|
||||
return Err(e).chain_err(|| RuntimeErrorKind::Instantiate);
|
||||
} else {
|
||||
eprintln!("No config file found.");
|
||||
eprintln!("Maybe try to use 'imag-init' to initialize imag?");
|
||||
eprintln!("Continuing without configuration file");
|
||||
None
|
||||
let config = match fetch_config(&configpath)? {
|
||||
None => {
|
||||
return Err(err_msg("No configuration file found"))
|
||||
.context(err_msg("Maybe try to use 'imag-init' to initialize imag?"))
|
||||
.context(err_msg("Continuing without configuration file"))
|
||||
.context(err_msg("Cannot instantiate runtime"))
|
||||
.map_err(Error::from);
|
||||
},
|
||||
|
||||
Ok(mut config) => {
|
||||
Some(mut config) => {
|
||||
if let Err(e) = override_config(&mut config, get_override_specs(&matches)) {
|
||||
error!("Could not apply config overrides");
|
||||
trace_error(&e);
|
||||
|
@ -102,16 +102,14 @@ impl<'a> Runtime<'a> {
|
|||
}
|
||||
|
||||
/// Builds the Runtime object using the given `config`.
|
||||
pub fn with_configuration<C>(cli_app: C, config: Option<Value>)
|
||||
-> Result<Runtime<'a>, RuntimeError>
|
||||
pub fn with_configuration<C>(cli_app: C, config: Option<Value>) -> Result<Runtime<'a>>
|
||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||
{
|
||||
let matches = cli_app.clone().matches();
|
||||
Runtime::_new(cli_app, matches, config)
|
||||
}
|
||||
|
||||
fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>)
|
||||
-> Result<Runtime<'a>, RuntimeError>
|
||||
fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>) -> Result<Runtime<'a>>
|
||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||
{
|
||||
if cli_app.enable_logging() {
|
||||
|
@ -146,7 +144,8 @@ impl<'a> Runtime<'a> {
|
|||
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
|
||||
pub fn editor(&self) -> Result<Option<Command>, RuntimeError> {
|
||||
pub fn editor(&self) -> Result<Option<Command>> {
|
||||
self.cli()
|
||||
.value_of("editor")
|
||||
.map(String::from)
|
||||
|
@ -391,7 +390,7 @@ impl<'a> Runtime<'a> {
|
|||
})
|
||||
})
|
||||
.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))
|
||||
.and_then(|s| {
|
||||
let mut split = s.split_whitespace();
|
||||
|
@ -401,7 +400,7 @@ impl<'a> Runtime<'a> {
|
|||
}
|
||||
let mut c = Command::new(command.unwrap()); // secured above
|
||||
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());
|
||||
Ok(Some(c))
|
||||
})
|
||||
|
@ -442,8 +441,6 @@ impl<'a> Runtime<'a> {
|
|||
/// # Return value
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
|
@ -457,7 +454,7 @@ impl<'a> Runtime<'a> {
|
|||
command: S,
|
||||
subcommand: S,
|
||||
args: &ArgMatches)
|
||||
-> Result<::std::process::ExitStatus, RuntimeError>
|
||||
-> Result<::std::process::ExitStatus>
|
||||
{
|
||||
use std::io::Write;
|
||||
use std::io::ErrorKind;
|
||||
|
@ -465,8 +462,7 @@ impl<'a> Runtime<'a> {
|
|||
let rtp_str = self.rtp()
|
||||
.to_str()
|
||||
.map(String::from)
|
||||
.ok_or(RuntimeErrorKind::IOError)
|
||||
.map_err(RuntimeError::from_kind)?;
|
||||
.ok_or_else(|| Error::from(EM::IO))?;
|
||||
|
||||
let command = format!("{}-{}", command.as_ref(), subcommand.as_ref());
|
||||
|
||||
|
@ -497,7 +493,8 @@ impl<'a> Runtime<'a> {
|
|||
},
|
||||
_ => e,
|
||||
})
|
||||
.map_err(RuntimeError::from)
|
||||
.context(EM::IO)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ walkdir = "2"
|
|||
is-match = "0.1"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
error-chain = "0.12"
|
||||
toml-query = "0.7"
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
failure = "0.1"
|
||||
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagutil = { version = "0.9.0", path = "../../../lib/etc/libimagutil" }
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
|
||||
use toml::Value;
|
||||
|
||||
use store::Result;
|
||||
use error::StoreError as SE;
|
||||
use error::StoreErrorKind as SEK;
|
||||
use failure::Fallible as Result;
|
||||
use failure::ResultExt;
|
||||
use failure::Error;
|
||||
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
/// 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.
|
||||
|
@ -31,7 +33,10 @@ pub fn config_implicit_store_create_allowed(config: &Option<Value>) -> Result<bo
|
|||
let key = "store.implicit-create";
|
||||
|
||||
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 {
|
||||
Ok(false)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,8 +22,7 @@ use std::io::{Seek, SeekFrom, Read};
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use error::{StoreError as SE, StoreErrorKind as SEK};
|
||||
use error::ResultExt;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use super::FileAbstraction;
|
||||
use super::FileAbstractionInstance;
|
||||
|
@ -34,6 +33,9 @@ use file_abstraction::iter::PathIterator;
|
|||
use file_abstraction::iter::PathIterBuilder;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
use failure::ResultExt;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FSFileAbstractionInstance(PathBuf);
|
||||
|
@ -43,34 +45,41 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
|
|||
/**
|
||||
* 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);
|
||||
|
||||
let mut file = open_file(&self.0)
|
||||
.chain_err(|| SEK::FileNotFound)?;
|
||||
let mut file = match open_file(&self.0) {
|
||||
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();
|
||||
|
||||
file.read_to_string(&mut s)
|
||||
.chain_err(|| SEK::IoError)
|
||||
.context(EM::IO)
|
||||
.map_err(Error::from)
|
||||
.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
|
||||
*/
|
||||
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
|
||||
fn write_file_content(&mut self, buf: &Entry) -> Result<()> {
|
||||
use std::io::Write;
|
||||
|
||||
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.set_len(buf.len() as u64).chain_err(|| SEK::FileNotWritten)?;
|
||||
file.write_all(&buf).chain_err(|| SEK::FileNotWritten)
|
||||
file.seek(SeekFrom::Start(0)).context(EM::FileNotCreated)?;
|
||||
file.set_len(buf.len() as u64).context(EM::FileNotWritten)?;
|
||||
file.write_all(&buf)
|
||||
.context(EM::FileNotWritten)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,19 +91,24 @@ pub struct FSFileAbstraction {}
|
|||
|
||||
impl FileAbstraction for FSFileAbstraction {
|
||||
|
||||
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
|
||||
remove_file(path).chain_err(|| SEK::FileNotRemoved)
|
||||
fn remove_file(&self, path: &PathBuf) -> Result<()> {
|
||||
remove_file(path)
|
||||
.context(EM::FileNotRemoved)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
||||
copy(from, to).chain_err(|| SEK::FileNotCopied).map(|_| ())
|
||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
|
||||
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() {
|
||||
Some(p) => if !p.exists() {
|
||||
debug!("Creating: {:?}", p);
|
||||
let _ = create_dir_all(&PathBuf::from(p))?;
|
||||
let _ = create_dir_all(&PathBuf::from(p)).context(EM::DirNotCreated)?;
|
||||
},
|
||||
None => {
|
||||
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);
|
||||
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);
|
||||
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())
|
||||
}
|
||||
|
||||
fn is_file(&self, path: &PathBuf) -> Result<bool, SE> {
|
||||
fn is_file(&self, path: &PathBuf) -> Result<bool> {
|
||||
Ok(path.is_file())
|
||||
}
|
||||
|
||||
|
@ -124,13 +142,13 @@ impl FileAbstraction for FSFileAbstraction {
|
|||
}
|
||||
|
||||
/// We return nothing from the FS here.
|
||||
fn drain(&self) -> Result<Drain, SE> {
|
||||
fn drain(&self) -> Result<Drain> {
|
||||
Ok(Drain::empty())
|
||||
}
|
||||
|
||||
/// FileAbstraction::fill implementation that consumes the Drain and writes everything to the
|
||||
/// filesystem
|
||||
fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
|
||||
fn fill(&mut self, mut d: Drain) -> Result<()> {
|
||||
d.iter()
|
||||
.fold(Ok(()), |acc, (path, element)| {
|
||||
acc.and_then(|_| self.new_instance(path).write_file_content(&element))
|
||||
|
@ -141,7 +159,7 @@ impl FileAbstraction for FSFileAbstraction {
|
|||
basepath: PathBuf,
|
||||
storepath: PathBuf,
|
||||
backend: Arc<FileAbstraction>)
|
||||
-> Result<PathIterator, SE>
|
||||
-> Result<PathIterator>
|
||||
{
|
||||
trace!("Building PathIterator object");
|
||||
Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend))
|
||||
|
@ -153,13 +171,15 @@ pub(crate) struct 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())
|
||||
.min_depth(1)
|
||||
.max_open(100)
|
||||
.into_iter()
|
||||
.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> {
|
||||
OpenOptions::new().write(true).read(true).open(p)
|
||||
fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<Option<File>> {
|
||||
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> {
|
||||
|
|
|
@ -18,15 +18,17 @@
|
|||
//
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use error::StoreError as SE;
|
||||
use error::StoreErrorKind as SEK;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Mutex;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::ops::Deref;
|
||||
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
|
||||
use super::FileAbstraction;
|
||||
use super::FileAbstractionInstance;
|
||||
use super::Drain;
|
||||
|
@ -62,21 +64,21 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
|
|||
/**
|
||||
* 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);
|
||||
|
||||
self.fs_abstraction
|
||||
.lock()
|
||||
.map_err(|_| SE::from_kind(SEK::LockError))
|
||||
.and_then(|mut mtx| {
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.map(|mut mtx| {
|
||||
mtx.get_mut()
|
||||
.get(&self.absent_path)
|
||||
.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 {
|
||||
InMemoryFileAbstractionInstance { ref absent_path, .. } => {
|
||||
let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
|
||||
|
@ -99,18 +101,19 @@ impl InMemoryFileAbstraction {
|
|||
&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
|
||||
.lock()
|
||||
.map_err(|_| SE::from_kind(SEK::LockError))
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.map(|mtx| mtx.deref().borrow().clone())
|
||||
.into()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl FileAbstraction for InMemoryFileAbstraction {
|
||||
|
||||
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
|
||||
fn remove_file(&self, path: &PathBuf) -> Result<()> {
|
||||
debug!("Removing: {:?}", path);
|
||||
self.backend()
|
||||
.lock()
|
||||
|
@ -118,43 +121,43 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
|||
.get_mut()
|
||||
.remove(path)
|
||||
.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);
|
||||
let mut mtx = self.backend().lock().expect("Locking Mutex failed");
|
||||
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);
|
||||
debug!("Copying: {:?} -> {:?} worked", from, to);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
||||
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
|
||||
debug!("Renaming: {:?} -> {:?}", from, to);
|
||||
let mut mtx = self.backend().lock().expect("Locking Mutex failed");
|
||||
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);
|
||||
debug!("Renaming: {:?} -> {:?} worked", from, to);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE> {
|
||||
fn create_dir_all(&self, _: &PathBuf) -> Result<()> {
|
||||
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 backend = mtx.get_mut();
|
||||
|
||||
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
|
||||
// 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
|
||||
|
@ -165,13 +168,15 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
|||
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)
|
||||
}
|
||||
|
||||
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);
|
||||
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();
|
||||
|
||||
for (path, element) in d.iter() {
|
||||
|
@ -182,17 +187,17 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
|||
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)");
|
||||
let keys : Vec<PathBuf> = self
|
||||
.backend()
|
||||
.lock()
|
||||
.map_err(|_| SE::from_kind(SEK::FileError))?
|
||||
.map_err(|_| EM::LockError)?
|
||||
.get_mut()
|
||||
.keys()
|
||||
.map(PathBuf::from)
|
||||
.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))
|
||||
}
|
||||
|
@ -201,7 +206,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
|||
pub(crate) struct InMemPathIterBuilder(Vec<PathBuf>);
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use error::Result;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
use storeid::StoreId;
|
||||
use file_abstraction::FileAbstraction;
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ use std::fmt::Debug;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use error::StoreError as SE;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
use store::Entry;
|
||||
use storeid::StoreId;
|
||||
|
||||
|
@ -38,20 +39,20 @@ use self::iter::PathIterator;
|
|||
|
||||
/// An abstraction trait over filesystem actions
|
||||
pub trait FileAbstraction : Debug {
|
||||
fn remove_file(&self, path: &PathBuf) -> Result<(), SE>;
|
||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
|
||||
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
|
||||
fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE>;
|
||||
fn remove_file(&self, path: &PathBuf) -> Result<()>;
|
||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
|
||||
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
|
||||
fn create_dir_all(&self, _: &PathBuf) -> Result<()>;
|
||||
|
||||
fn exists(&self, &PathBuf) -> Result<bool, SE>;
|
||||
fn is_file(&self, &PathBuf) -> Result<bool, SE>;
|
||||
fn exists(&self, &PathBuf) -> Result<bool>;
|
||||
fn is_file(&self, &PathBuf) -> Result<bool>;
|
||||
|
||||
fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>;
|
||||
|
||||
fn drain(&self) -> Result<Drain, SE>;
|
||||
fn fill<'a>(&'a mut self, d: Drain) -> Result<(), SE>;
|
||||
fn drain(&self) -> Result<Drain>;
|
||||
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
|
||||
|
@ -61,8 +62,8 @@ pub trait FileAbstractionInstance : Debug {
|
|||
///
|
||||
/// 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.
|
||||
fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE>;
|
||||
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE>;
|
||||
fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>>;
|
||||
fn write_file_content(&mut self, buf: &Entry) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct Drain(HashMap<PathBuf, Entry>);
|
||||
|
@ -119,7 +120,7 @@ version = "{}"
|
|||
Hello World"#, env!("CARGO_PKG_VERSION"))).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");
|
||||
}
|
||||
|
||||
|
@ -140,7 +141,7 @@ Hello World
|
|||
baz"#, env!("CARGO_PKG_VERSION"))).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");
|
||||
}
|
||||
|
||||
|
@ -163,7 +164,7 @@ baz
|
|||
"#, env!("CARGO_PKG_VERSION"))).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");
|
||||
}
|
||||
|
||||
|
|
|
@ -31,41 +31,34 @@ macro_rules! mk_iterator_mod {
|
|||
#[allow(unused_imports)]
|
||||
use store::FileLockEntry;
|
||||
use store::Store;
|
||||
use error::StoreError;
|
||||
use std::result::Result as RResult;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
pub struct $itername<'a, E>(Box<Iterator<Item = RResult<StoreId, E>> + 'a>, &'a Store)
|
||||
where E: From<StoreError>;
|
||||
pub struct $itername<'a>(Box<Iterator<Item = Result<StoreId>> + 'a>, &'a Store);
|
||||
|
||||
impl<'a, E> $itername<'a, E>
|
||||
where E: From<StoreError>
|
||||
impl<'a> $itername<'a>
|
||||
{
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Iterator for $itername<'a, E>
|
||||
where E: From<StoreError>
|
||||
impl<'a> Iterator for $itername<'a>
|
||||
{
|
||||
type Item = RResult<$yield, E>;
|
||||
type Item = Result<$yield>;
|
||||
|
||||
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>
|
||||
where E: From<StoreError>
|
||||
{
|
||||
fn $extfnname(self, store: &'a Store) -> $itername<'a, E>;
|
||||
pub trait $extname<'a> {
|
||||
fn $extfnname(self, store: &'a Store) -> $itername<'a>;
|
||||
}
|
||||
|
||||
impl<'a, I, E> $extname<'a, E> for I
|
||||
where I: Iterator<Item = RResult<StoreId, E>> + 'a,
|
||||
E: From<StoreError>
|
||||
impl<'a, I> $extname<'a> for I
|
||||
where I: Iterator<Item = Result<StoreId>> + 'a
|
||||
{
|
||||
fn $extfnname(self, store: &'a Store) -> $itername<'a, E> {
|
||||
fn $extfnname(self, store: &'a Store) -> $itername<'a> {
|
||||
$itername(Box::new(self), store)
|
||||
}
|
||||
}
|
||||
|
@ -151,8 +144,7 @@ use self::get::StoreGetIterator;
|
|||
use self::retrieve::StoreRetrieveIterator;
|
||||
use file_abstraction::iter::PathIterator;
|
||||
use store::Store;
|
||||
use error::StoreError;
|
||||
use error::Result;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
/// 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
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// Transform the iterator into a StoreGetIterator
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// Transform the iterator into a StoreRetrieveIterator
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ extern crate semver;
|
|||
extern crate walkdir;
|
||||
#[macro_use] extern crate is_match;
|
||||
extern crate serde_json;
|
||||
#[macro_use] extern crate error_chain;
|
||||
#[macro_use] extern crate failure;
|
||||
extern crate toml_query;
|
||||
|
||||
extern crate libimagerror;
|
||||
|
@ -53,7 +53,6 @@ extern crate libimagutil;
|
|||
#[macro_use] mod util;
|
||||
|
||||
pub mod storeid;
|
||||
pub mod error;
|
||||
pub mod iter;
|
||||
pub mod store;
|
||||
mod configuration;
|
||||
|
|
|
@ -31,12 +31,16 @@ use std::fmt::Formatter;
|
|||
use std::fmt::Debug;
|
||||
use std::fmt::Error as FMTError;
|
||||
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use toml::Value;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
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 iter::Entries;
|
||||
use file_abstraction::FileAbstractionInstance;
|
||||
|
@ -48,9 +52,6 @@ pub use file_abstraction::InMemoryFileAbstraction;
|
|||
|
||||
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)]
|
||||
enum StoreEntryStatus {
|
||||
|
@ -76,7 +77,7 @@ impl StoreEntry {
|
|||
{
|
||||
open_file(pb.clone())
|
||||
.and_then(|f| f.lock_exclusive())
|
||||
.chain_err(|| SEK::IoError)?;
|
||||
.with_context(|| EM::IO)?;
|
||||
}
|
||||
|
||||
Ok(StoreEntry {
|
||||
|
@ -94,15 +95,12 @@ impl StoreEntry {
|
|||
|
||||
fn get_entry(&mut self) -> Result<Entry> {
|
||||
if !self.is_borrowed() {
|
||||
self.file
|
||||
.get_file_content(self.id.clone())
|
||||
.or_else(|err| if is_match!(err.kind(), &SEK::FileNotFound) {
|
||||
Ok(Entry::new(self.id.clone()))
|
||||
} else {
|
||||
Err(err)
|
||||
})
|
||||
match self.file.get_file_content(self.id.clone())? {
|
||||
Some(file) => Ok(file),
|
||||
None => Ok(Entry::new(self.id.clone()))
|
||||
}
|
||||
} else {
|
||||
Err(SE::from_kind(SEK::EntryAlreadyBorrowed(self.id.clone())))
|
||||
Err(format_err!("EntryAlreadyBorrowed: {}", self.id))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,18 +182,19 @@ impl Store {
|
|||
debug!("Building new Store object");
|
||||
if !location.exists() {
|
||||
if !config_implicit_store_create_allowed(store_config)? {
|
||||
return Err(SE::from_kind(SEK::CreateStoreDirDenied))
|
||||
.chain_err(|| SEK::FileError)
|
||||
.chain_err(|| SEK::IoError);
|
||||
return Err(format_err!("CreateStoreDirDenied"))
|
||||
.context(EM::FileError)
|
||||
.context(EM::IO)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
backend
|
||||
.create_dir_all(&location)
|
||||
.chain_err(|| SEK::StorePathCreate(location.clone()))
|
||||
.context(format_err!("StorePathCreate: {}", location.display()))
|
||||
.map_dbg_err_str("Failed")?;
|
||||
} else if location.is_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 {
|
||||
|
@ -218,45 +217,34 @@ impl Store {
|
|||
///
|
||||
/// 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>> {
|
||||
let id = id.into_storeid()?.with_base(self.path().clone());
|
||||
|
||||
debug!("Creating id: '{}'", id);
|
||||
|
||||
let exists = self.entries
|
||||
let exists = id.exists()? || self.entries
|
||||
.read()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.map(|map| map.contains_key(&id))
|
||||
.and_then(|exists| if exists {
|
||||
Ok(exists)
|
||||
} else {
|
||||
let pb = id.clone().into_pathbuf().map_err(SE::from)?;
|
||||
self.backend.exists(&pb)
|
||||
})
|
||||
.chain_err(|| SEK::CreateCallError(id.clone()))?;
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.context(format_err!("CreateCallError: {}", id))?;
|
||||
|
||||
if exists {
|
||||
debug!("Entry exists: {:?}", id);
|
||||
return Err(SEK::EntryAlreadyExists(id).into());
|
||||
return Err(format_err!("EntryAlreadyExists: {}", id));
|
||||
}
|
||||
|
||||
{
|
||||
let mut hsmap = self
|
||||
.entries
|
||||
.write()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.chain_err(|| SEK::CreateCallError(id.clone()))?;
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.context(format_err!("CreateCallError: {}", id))?;
|
||||
|
||||
if hsmap.contains_key(&id) {
|
||||
debug!("Cannot create, internal cache already contains: '{}'", id);
|
||||
return Err(SE::from_kind(SEK::EntryAlreadyExists(id.clone())))
|
||||
.chain_err(|| SEK::CreateCallError(id.clone()));
|
||||
return Err(format_err!("EntryAlreadyExists: {}", id))
|
||||
.context(format_err!("CreateCallError: {}", id))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
hsmap.insert(id.clone(), {
|
||||
debug!("Creating: '{}'", id);
|
||||
|
@ -281,17 +269,13 @@ impl Store {
|
|||
///
|
||||
/// 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>> {
|
||||
let id = id.into_storeid()?.with_base(self.path().clone());
|
||||
debug!("Retrieving id: '{}'", id);
|
||||
let entry = self
|
||||
.entries
|
||||
.write()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.and_then(|mut es| {
|
||||
let new_se = StoreEntry::new(id.clone(), &self.backend)?;
|
||||
let se = es.entry(id.clone()).or_insert(new_se);
|
||||
|
@ -299,7 +283,7 @@ impl Store {
|
|||
se.status = StoreEntryStatus::Borrowed;
|
||||
entry
|
||||
})
|
||||
.chain_err(|| SEK::RetrieveCallError(id.clone()))?;
|
||||
.context(format_err!("RetrieveCallError: {}", id))?;
|
||||
|
||||
debug!("Constructing FileLockEntry: '{}'", id);
|
||||
Ok(FileLockEntry::new(self, entry))
|
||||
|
@ -320,24 +304,21 @@ impl Store {
|
|||
|
||||
debug!("Getting id: '{}'", id);
|
||||
|
||||
let exists = self.entries
|
||||
let exists = id.exists()? || self.entries
|
||||
.read()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.map(|map| map.contains_key(&id))
|
||||
.and_then(|exists| if exists {
|
||||
Ok(exists)
|
||||
} else {
|
||||
let pb = id.clone().into_pathbuf().map_err(SE::from)?;
|
||||
self.backend.exists(&pb)
|
||||
})
|
||||
.chain_err(|| SEK::GetCallError(id.clone()))?;
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.context(format_err!("GetCallError: {}", id))?;
|
||||
|
||||
if !exists {
|
||||
debug!("Does not exist in internal cache or filesystem: {:?}", id);
|
||||
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
|
||||
|
@ -346,15 +327,11 @@ impl Store {
|
|||
///
|
||||
/// 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<()> {
|
||||
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.
|
||||
|
@ -365,10 +342,11 @@ impl Store {
|
|||
/// it is not public.
|
||||
///
|
||||
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(|| {
|
||||
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.");
|
||||
|
@ -401,7 +379,8 @@ impl Store {
|
|||
pub fn flush_cache(&self) -> Result<()> {
|
||||
// We borrow this early so that between the aggregation of the flushables and the actual
|
||||
// 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![];
|
||||
|
||||
for (storeid, se) in hsmap.deref() {
|
||||
|
@ -421,37 +400,34 @@ impl Store {
|
|||
|
||||
/// The number of elements in the internal cache
|
||||
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())
|
||||
}
|
||||
|
||||
/// The size of the internal cache
|
||||
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())
|
||||
}
|
||||
|
||||
/// 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
|
||||
///
|
||||
/// 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> {
|
||||
let id = id.into_storeid()?.with_base(self.path().clone());
|
||||
debug!("Retrieving copy of '{}'", id);
|
||||
let entries = self.entries.write()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.chain_err(|| SEK::RetrieveCopyCallError(id.clone()))?;
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.context(format_err!("RetrieveCopyCallError: {}", id))?;
|
||||
|
||||
// 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) {
|
||||
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()
|
||||
|
@ -463,27 +439,29 @@ impl Store {
|
|||
///
|
||||
/// 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<()> {
|
||||
let id = id.into_storeid()?.with_base(self.path().clone());
|
||||
|
||||
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 mut entries = self
|
||||
.entries
|
||||
.write()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.chain_err(|| SEK::DeleteCallError(id.clone()))?;
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.context(format_err!("DeleteCallError: {}", id))?;
|
||||
|
||||
let do_remove = match entries.get(&id) {
|
||||
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
|
||||
} else { // Entry is in the cache
|
||||
// Remove Entry from the cache
|
||||
|
@ -496,8 +474,9 @@ impl Store {
|
|||
|
||||
if !self.backend.exists(&pb)? {
|
||||
debug!("Seems like {:?} is not even on the FS", pb);
|
||||
return Err(SE::from_kind(SEK::FileNotFound))
|
||||
.chain_err(|| SEK::DeleteCallError(id))
|
||||
return Err(EM::FileNotFound)
|
||||
.context(format_err!("DeleteCallError: {}", id))
|
||||
.map_err(Error::from)
|
||||
} // else { continue }
|
||||
|
||||
false
|
||||
|
@ -513,8 +492,8 @@ impl Store {
|
|||
let _ = self
|
||||
.backend
|
||||
.remove_file(&pb)
|
||||
.chain_err(|| SEK::FileError)
|
||||
.chain_err(|| SEK::DeleteCallError(id))?;
|
||||
.context(EM::FileError)
|
||||
.context(format_err!("DeleteCallError: {}", id))?;
|
||||
|
||||
debug!("Deleted");
|
||||
Ok(())
|
||||
|
@ -540,12 +519,13 @@ impl Store {
|
|||
let hsmap = self
|
||||
.entries
|
||||
.write()
|
||||
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||
.chain_err(|| SEK::MoveCallError(entry.get_location().clone(), new_id.clone()))?;
|
||||
.map_err(|_| Error::from(EM::LockError))
|
||||
.context(format_err!("MoveCallError: {} -> {}", entry.get_location(), new_id))?;
|
||||
|
||||
if hsmap.contains_key(&new_id) {
|
||||
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone())))
|
||||
.chain_err(|| SEK::MoveCallError(entry.get_location().clone(), new_id.clone()))
|
||||
return Err(format_err!("Entry exists already: {}", new_id.clone()))
|
||||
.context(format_err!("MoveCallError: {} -> {}", entry.get_location(), new_id))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
let old_id = entry.get_location().clone();
|
||||
|
@ -560,8 +540,9 @@ impl Store {
|
|||
} else {
|
||||
Ok(())
|
||||
})
|
||||
.chain_err(|| SEK::FileError)
|
||||
.chain_err(|| SEK::MoveCallError(old_id, new_id))
|
||||
.context(EM::FileError)
|
||||
.context(format_err!("MoveCallError: {} -> {}", old_id, new_id))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Move an entry without loading
|
||||
|
@ -604,10 +585,11 @@ impl Store {
|
|||
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) {
|
||||
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");
|
||||
|
||||
|
@ -615,7 +597,7 @@ impl Store {
|
|||
// if we have one, but it is borrowed, we really should not rename it, as this might
|
||||
// lead to strange errors
|
||||
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");
|
||||
|
@ -624,14 +606,18 @@ impl Store {
|
|||
let new_id_pb = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
|
||||
|
||||
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.");
|
||||
|
||||
let _ = self
|
||||
.backend
|
||||
.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");
|
||||
|
||||
|
@ -792,7 +778,7 @@ impl Entry {
|
|||
pub fn from_reader<S: IntoStoreId>(loc: S, file: &mut Read) -> Result<Entry> {
|
||||
let text = {
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)?;
|
||||
file.read_to_string(&mut s).context(EM::IO)?;
|
||||
s
|
||||
};
|
||||
Self::from_str(loc, &text[..])
|
||||
|
@ -828,7 +814,9 @@ impl Entry {
|
|||
/// disk).
|
||||
pub fn to_str(&self) -> Result<String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -872,12 +860,12 @@ impl Entry {
|
|||
/// Currently, this only verifies the header. This might change in the future.
|
||||
pub fn verify(&self) -> Result<()> {
|
||||
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)? {
|
||||
Err(SE::from_kind(SEK::MissingVersionInfo))
|
||||
Err(format_err!("MissingVersionInfo"))
|
||||
} else if !has_only_tables(&self.header)? {
|
||||
debug!("Could not verify that it only has tables in its base table");
|
||||
Err(SE::from_kind(SEK::NonTableInBaseTable))
|
||||
Err(format_err!("NonTableInBaseTable"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -899,21 +887,26 @@ fn has_only_tables(t: &Value) -> Result<bool> {
|
|||
debug!("Verifying that table has only tables");
|
||||
match *t {
|
||||
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> {
|
||||
t.read("imag")?
|
||||
.ok_or_else(|| SE::from_kind(SEK::ConfigKeyMissingError("imag")))
|
||||
t.read("imag")
|
||||
.map_err(Error::from)
|
||||
.context(EM::TomlQueryError)?
|
||||
.ok_or_else(|| format_err!("ConfigKeyMissingError('imag')"))
|
||||
.map(Value::is_table)
|
||||
}
|
||||
|
||||
fn has_imag_version_in_main_section(t: &Value) -> Result<bool> {
|
||||
t.read_string("imag.version")?
|
||||
.ok_or_else(|| SE::from_kind(SEK::ConfigKeyMissingError("imag.version")))
|
||||
t.read_string("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(|s| ::semver::Version::parse(&s).is_ok())
|
||||
.map(|s: String| ::semver::Version::parse(&s).is_ok())
|
||||
}
|
||||
|
||||
|
||||
|
@ -1095,14 +1088,12 @@ mod store_tests {
|
|||
|
||||
#[test]
|
||||
fn test_store_create_twice() {
|
||||
use error::StoreErrorKind as SEK;
|
||||
|
||||
let store = get_store();
|
||||
|
||||
for n in 1..100 {
|
||||
let s = format!("test-{}", n % 50);
|
||||
store.create(PathBuf::from(s.clone()))
|
||||
.map_err(|e| assert!(is_match!(e.kind(), &SEK::EntryAlreadyExists(_)) && n >= 50))
|
||||
.ok()
|
||||
.map(|entry| {
|
||||
assert!(entry.verify().is_ok());
|
||||
|
@ -1190,8 +1181,8 @@ mod store_tests {
|
|||
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());
|
||||
}
|
||||
|
||||
|
@ -1203,16 +1194,8 @@ mod store_tests {
|
|||
assert!(store.entries.read().unwrap().get(&id_mv_with_base).is_some());
|
||||
}
|
||||
|
||||
{
|
||||
let pb = id_with_base.into_pathbuf().unwrap();
|
||||
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.clone()) { Ok(None) => true, _ => false },
|
||||
"Moved id ({:?}) is still there", id);
|
||||
assert!(match store.get(id_mv.clone()) { Ok(Some(_)) => true, _ => false },
|
||||
"New id ({:?}) is not in store...", id_mv);
|
||||
}
|
||||
|
|
|
@ -26,10 +26,11 @@ use std::fmt::Error as FmtError;
|
|||
use std::result::Result as RResult;
|
||||
use std::path::Components;
|
||||
|
||||
use error::StoreErrorKind as SEK;
|
||||
use error::StoreError as SE;
|
||||
use error::ResultExt;
|
||||
use store::Result;
|
||||
use failure::ResultExt;
|
||||
use failure::Fallible as Result;
|
||||
use failure::err_msg;
|
||||
use failure::Error;
|
||||
|
||||
use store::Store;
|
||||
|
||||
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
|
||||
/// 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>
|
||||
where D: Deref<Target = Path>
|
||||
{
|
||||
let p = full_path
|
||||
.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))
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ impl StoreId {
|
|||
debug!("Trying to get a new baseless id from: {:?}", id);
|
||||
if 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 {
|
||||
debug!("Building Storeid object baseless");
|
||||
Ok(StoreId {
|
||||
|
@ -103,7 +103,9 @@ impl StoreId {
|
|||
/// specified.
|
||||
pub fn into_pathbuf(mut self) -> Result<PathBuf> {
|
||||
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);
|
||||
Ok(base)
|
||||
}
|
||||
|
@ -125,7 +127,8 @@ impl StoreId {
|
|||
.unwrap_or_else(|| self.id.clone())
|
||||
.to_str()
|
||||
.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
|
||||
|
@ -232,7 +235,7 @@ macro_rules! module_entry_path_mod {
|
|||
use std::path::PathBuf;
|
||||
|
||||
use $crate::storeid::StoreId;
|
||||
use $crate::store::Result;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
/// A Struct giving you the ability to choose store entries assigned
|
||||
/// to it.
|
||||
|
@ -313,8 +316,6 @@ impl<'a> Iterator for StoreIdIteratorWithStore<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
use error::StoreError;
|
||||
|
||||
impl<'a> StoreIdIteratorWithStore<'a> {
|
||||
|
||||
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
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -336,7 +337,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
|
|||
///
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -344,7 +345,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
|
|||
///
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -352,7 +353,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
|
|||
///
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -364,7 +365,6 @@ mod test {
|
|||
|
||||
use storeid::StoreId;
|
||||
use storeid::IntoStoreId;
|
||||
use error::StoreErrorKind as SEK;
|
||||
|
||||
module_entry_path_mod!("test");
|
||||
|
||||
|
@ -444,8 +444,6 @@ mod test {
|
|||
|
||||
let pb = id.unwrap().into_pathbuf();
|
||||
assert!(pb.is_err());
|
||||
|
||||
assert!(is_match!(pb.unwrap_err().kind(), &SEK::StoreIdHasNoBaseError(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use toml::Value;
|
||||
use failure::Fallible as Result;
|
||||
use failure::ResultExt;
|
||||
|
||||
use store::Result;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
#[cfg(feature = "early-panic")]
|
||||
#[macro_export]
|
||||
|
@ -40,6 +42,7 @@ macro_rules! if_cfg_panic {
|
|||
}
|
||||
|
||||
pub fn entry_buffer_to_header_content(buf: &str) -> Result<(Value, String)> {
|
||||
|
||||
debug!("Building entry from string");
|
||||
let mut header = 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;
|
||||
// do not further process the line
|
||||
} else if !header_consumed {
|
||||
let _ = writeln!(header, "{}", line)?;
|
||||
let _ = writeln!(header, "{}", line).context(EM::FormatError)?;
|
||||
} else if iter.peek().is_some() {
|
||||
let _ = writeln!(content, "{}", line)?;
|
||||
let _ = writeln!(content, "{}", line).context(EM::FormatError)?;
|
||||
} 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)]
|
||||
|
|
|
@ -22,7 +22,7 @@ maintenance = { status = "actively-developed" }
|
|||
[dependencies]
|
||||
url = "1.5"
|
||||
regex = "1"
|
||||
error-chain = "0.12"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
|
||||
use regex::Regex;
|
||||
|
||||
use error::Result;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use module_path::ModuleEntryPath;
|
||||
|
||||
use libimagstore::store::Store;
|
||||
|
@ -53,22 +54,22 @@ impl<'a> BookmarkCollectionStore<'a> for Store {
|
|||
fn new(&'a self, name: &str) -> Result<FileLockEntry<'a>> {
|
||||
ModuleEntryPath::new(name)
|
||||
.into_storeid()
|
||||
.and_then(|id| self.create(id).map_err(From::from))
|
||||
.map_err(From::from)
|
||||
.and_then(|id| self.create(id).map_err(Error::from))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
fn get(&'a self, name: &str) -> Result<Option<FileLockEntry<'a>>> {
|
||||
ModuleEntryPath::new(name)
|
||||
.into_storeid()
|
||||
.and_then(|id| self.get(id).map_err(From::from))
|
||||
.map_err(From::from)
|
||||
.and_then(|id| self.get(id).map_err(Error::from))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
fn delete(&'a self, name: &str) -> Result<()> {
|
||||
ModuleEntryPath::new(name)
|
||||
.into_storeid()
|
||||
.and_then(|id| self.delete(id).map_err(From::from))
|
||||
.map_err(From::from)
|
||||
.and_then(|id| self.delete(id).map_err(Error::from))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -84,47 +85,35 @@ pub trait BookmarkCollection : Sized + InternalLinker + ExternalLinker {
|
|||
impl BookmarkCollection for Entry {
|
||||
|
||||
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>> {
|
||||
use libimagentrylink::external::is_external_link_storeid;
|
||||
|
||||
self.get_internal_links()
|
||||
.map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
|
||||
.map_err(From::from)
|
||||
self.get_internal_links().map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
|
||||
}
|
||||
|
||||
fn add_link(&mut self, store: &Store, l: Link) -> Result<()> {
|
||||
use link::IntoUrl;
|
||||
|
||||
l.into_url()
|
||||
.and_then(|url| self.add_external_link(store, url).map_err(From::from))
|
||||
.map_err(From::from)
|
||||
l.into_url().and_then(|url| self.add_external_link(store, url))
|
||||
}
|
||||
|
||||
fn get_links_matching<'a>(&self, store: &'a Store, r: Regex) -> Result<LinksMatchingRegexIter<'a>> {
|
||||
use self::iter::IntoLinksMatchingRegexIter;
|
||||
|
||||
self.get_external_links(store)
|
||||
.map(|iter| iter.matching_regex(r))
|
||||
.map_err(From::from)
|
||||
self.get_external_links(store).map(|iter| iter.matching_regex(r))
|
||||
}
|
||||
|
||||
fn remove_link(&mut self, store: &Store, l: Link) -> Result<()> {
|
||||
use link::IntoUrl;
|
||||
|
||||
l.into_url()
|
||||
.and_then(|url| self.remove_external_link(store, url).map_err(From::from))
|
||||
.map_err(From::from)
|
||||
l.into_url().and_then(|url| self.remove_external_link(store, url))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub mod iter {
|
||||
use link::Link;
|
||||
use error::Result;
|
||||
use error::BookmarkError as BE;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
|
||||
pub struct LinkIter<I>(I)
|
||||
where I: Iterator<Item = Link>;
|
||||
|
@ -167,7 +156,7 @@ pub mod iter {
|
|||
loop {
|
||||
let n = match self.0.next() {
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
extern crate url;
|
||||
extern crate regex;
|
||||
#[macro_use] extern crate error_chain;
|
||||
extern crate failure;
|
||||
|
||||
#[macro_use] extern crate libimagstore;
|
||||
extern crate libimagerror;
|
||||
|
@ -46,5 +46,4 @@ extern crate libimagentrylink;
|
|||
module_entry_path_mod!("bookmark");
|
||||
|
||||
pub mod collection;
|
||||
pub mod error;
|
||||
pub mod link;
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
|
||||
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;
|
||||
|
||||
|
@ -66,10 +69,7 @@ pub trait IntoUrl {
|
|||
impl IntoUrl for Link {
|
||||
|
||||
fn into_url(self) -> Result<Url> {
|
||||
use error::BookmarkErrorKind as BEK;
|
||||
use error::ResultExt;
|
||||
|
||||
Url::parse(&self[..]).chain_err(|| BEK::LinkParsingError)
|
||||
Url::parse(&self[..]).context(err_msg("Link parsing error")).map_err(Error::from)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
|
|||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[dependencies]
|
||||
error-chain = "0.12"
|
||||
failure = "0.1"
|
||||
log = "0.4"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "update-errorchain" }
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
vobject = { git = "https://github.com/matthiasbeyer/rust-vobject", branch = "master" }
|
||||
uuid = "0.7"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
use toml::to_string as toml_to_string;
|
||||
use toml::from_str as toml_from_str;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
use libimagentryutil::isa::Is;
|
||||
use libimagentryutil::isa::IsKindHeaderPathProvider;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use deser::DeserVcard;
|
||||
use error::Result;
|
||||
use error::ContactError as CE;
|
||||
use error::ContactErrorKind as CEK;
|
||||
|
||||
/// Trait to be implemented on ::libimagstore::store::Entry
|
||||
pub trait Contact {
|
||||
|
@ -48,14 +48,14 @@ provide_kindflag_path!(pub IsContact, "contact.is_contact");
|
|||
impl Contact for Entry {
|
||||
|
||||
fn is_contact(&self) -> Result<bool> {
|
||||
self.is::<IsContact>().map_err(From::from)
|
||||
self.is::<IsContact>()
|
||||
}
|
||||
|
||||
fn deser(&self) -> Result<DeserVcard> {
|
||||
let data = self
|
||||
.get_header()
|
||||
.read("contact.data")?
|
||||
.ok_or_else(|| CE::from_kind(CEK::HeaderDataMissing("contact.data")))?;
|
||||
.ok_or_else(|| Error::from(EM::EntryHeaderFieldMissing("contact.data")))?;
|
||||
|
||||
// ugly hack
|
||||
let data_str = toml_to_string(&data)?;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -20,11 +20,11 @@
|
|||
use libimagstore::storeid::StoreIdIterator;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use contact::Contact;
|
||||
use error::ContactError as CE;
|
||||
use error::ContactErrorKind as CEK;
|
||||
use error::Result;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
|
||||
pub struct ContactIter<'a>(StoreIdIterator, &'a Store);
|
||||
|
||||
|
@ -44,11 +44,12 @@ impl<'a> Iterator for ContactIter<'a> {
|
|||
loop {
|
||||
match self.0.next() {
|
||||
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) {
|
||||
Err(e) => return Some(Err(e)),
|
||||
Ok(None) => return Some(Err(CE::from_kind(CEK::EntryNotFound(sid)))),
|
||||
Ok(Some(entry)) => match entry.is_contact().map_err(From::from) {
|
||||
Ok(None) => return
|
||||
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(false) => continue,
|
||||
Err(e) => return Some(Err(e)),
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#![recursion_limit="128"]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate error_chain;
|
||||
#[macro_use] extern crate failure;
|
||||
extern crate vobject;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
|
@ -51,7 +51,6 @@ extern crate libimagerror;
|
|||
module_entry_path_mod!("contact");
|
||||
|
||||
pub mod contact;
|
||||
pub mod error;
|
||||
pub mod iter;
|
||||
pub mod store;
|
||||
pub mod deser;
|
||||
|
|
|
@ -24,6 +24,8 @@ use toml::to_string as toml_to_string;
|
|||
use toml::from_str as toml_from_str;
|
||||
use toml_query::insert::TomlValueInsertExt;
|
||||
use vobject::vcard::Vcard;
|
||||
use failure::Error;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreId;
|
||||
|
@ -35,9 +37,6 @@ use libimagentryutil::isa::Is;
|
|||
use contact::IsContact;
|
||||
use deser::DeserVcard;
|
||||
use module_path::ModuleEntryPath;
|
||||
use error::ContactError as CE;
|
||||
use error::ContactErrorKind as CEK;
|
||||
use error::Result;
|
||||
use util;
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
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 serialized = DeserVcard::from(vcard);
|
||||
|
|
|
@ -22,7 +22,7 @@ use std::fmt::Debug;
|
|||
use std::fs::File;
|
||||
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> {
|
||||
let mut cont = String::new();
|
||||
|
|
|
@ -25,7 +25,7 @@ log = "0.4.0"
|
|||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
itertools = "0.7"
|
||||
error-chain = "0.12"
|
||||
failure = "0.1"
|
||||
filters = "0.3"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
|
|
|
@ -29,13 +29,12 @@ use chrono::Datelike;
|
|||
use itertools::Itertools;
|
||||
use chrono::naive::NaiveDateTime;
|
||||
use chrono::Timelike;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
|
||||
use entry::IsDiaryEntry;
|
||||
use diaryid::DiaryId;
|
||||
use diaryid::FromStoreId;
|
||||
use error::DiaryErrorKind as DEK;
|
||||
use error::ResultExt;
|
||||
use error::Result;
|
||||
use iter::DiaryEntryIterator;
|
||||
use iter::DiaryNameIterator;
|
||||
|
||||
|
@ -67,7 +66,7 @@ impl Diary for Store {
|
|||
let ndt = dt.naive_local();
|
||||
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>()?;
|
||||
Ok(entry)
|
||||
}
|
||||
|
@ -87,7 +86,7 @@ impl Diary for Store {
|
|||
ndt.minute(),
|
||||
ndt.second());
|
||||
|
||||
let mut entry = self.retrieve(id).chain_err(|| DEK::StoreReadError)?;
|
||||
let mut entry = self.retrieve(id)?;
|
||||
let _ = entry.set_isflag::<IsDiaryEntry>()?;
|
||||
Ok(entry)
|
||||
}
|
||||
|
@ -97,15 +96,12 @@ impl Diary for Store {
|
|||
debug!("Building iterator for module 'diary' with diary name = '{}'", diary_name);
|
||||
Store::entries(self)
|
||||
.map(|iter| DiaryEntryIterator::new(String::from(diary_name), iter.without_store()))
|
||||
.chain_err(|| DEK::StoreReadError)
|
||||
}
|
||||
|
||||
/// get the id of the youngest entry
|
||||
///
|
||||
/// TODO: We collect internally here. We shouldn't do that. Solution unclear.
|
||||
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> {
|
||||
use error::DiaryError as DE;
|
||||
|
||||
match Diary::entries(self, diary_name) {
|
||||
Err(e) => Some(Err(e)),
|
||||
Ok(entries) => {
|
||||
|
@ -114,7 +110,7 @@ impl Diary for Store {
|
|||
for entry in entries {
|
||||
let entry = match entry {
|
||||
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);
|
||||
|
@ -156,7 +152,7 @@ impl Diary for Store {
|
|||
fn diary_names(&self) -> Result<DiaryNameIterator> {
|
||||
self.entries()
|
||||
.map(|it| DiaryNameIterator::new(it.without_store()))
|
||||
.map_err(::error::DiaryError::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,20 +19,20 @@
|
|||
|
||||
use std::convert::Into;
|
||||
use std::fmt::{Display, Formatter, Error as FmtError};
|
||||
use std::result::Result as RResult;
|
||||
|
||||
use chrono::naive::NaiveDateTime;
|
||||
use chrono::naive::NaiveTime;
|
||||
use chrono::naive::NaiveDate;
|
||||
use chrono::Datelike;
|
||||
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::IntoStoreId;
|
||||
use libimagstore::store::Result as StoreResult;
|
||||
|
||||
use error::DiaryError as DE;
|
||||
use error::DiaryErrorKind as DEK;
|
||||
use error::ResultExt;
|
||||
|
||||
use module_path::ModuleEntryPath;
|
||||
|
||||
|
@ -149,7 +149,7 @@ impl DiaryId {
|
|||
|
||||
impl IntoStoreId for DiaryId {
|
||||
|
||||
fn into_storeid(self) -> StoreResult<StoreId> {
|
||||
fn into_storeid(self) -> Result<StoreId> {
|
||||
let s : String = self.into();
|
||||
ModuleEntryPath::new(s).into_storeid()
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ impl Into<String> 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}",
|
||||
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 {
|
||||
|
||||
fn from_storeid(&StoreId) -> Result<Self, DE>;
|
||||
|
||||
fn from_storeid(&StoreId) -> Result<Self>;
|
||||
}
|
||||
|
||||
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 {
|
||||
Component::Normal(s) => Some(s),
|
||||
_ => None,
|
||||
}.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 {
|
||||
|
||||
fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> {
|
||||
fn from_storeid(s: &StoreId) -> Result<DiaryId> {
|
||||
use std::str::FromStr;
|
||||
|
||||
use std::path::Components;
|
||||
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()
|
||||
.ok_or(DE::from_kind(DEK::IdParseError))
|
||||
.ok_or_else(|| Error::from(err_msg("ID parse error")))
|
||||
.and_then(component_to_str)
|
||||
}
|
||||
|
||||
|
@ -228,21 +226,33 @@ impl FromStoreId for DiaryId {
|
|||
|
||||
match (hour, minute, second) {
|
||||
(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)
|
||||
.and_then(|s| s.parse::<u32>()
|
||||
.chain_err(|| DEK::IdParseError));
|
||||
let day: Result<u32> = next_component(&mut cmps)
|
||||
.and_then(|s| {
|
||||
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)
|
||||
.and_then(|s| s.parse::<u32>()
|
||||
.chain_err(|| DEK::IdParseError));
|
||||
let month: Result<u32> = next_component(&mut cmps)
|
||||
.and_then(|s| {
|
||||
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)
|
||||
.and_then(|s| s.parse::<i32>()
|
||||
.chain_err(|| DEK::IdParseError));
|
||||
let year: Result<i32> = next_component(&mut cmps)
|
||||
.and_then(|s| {
|
||||
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);
|
||||
|
||||
|
|
|
@ -21,9 +21,10 @@ use libimagstore::store::Entry;
|
|||
use libimagentryutil::isa::Is;
|
||||
use libimagentryutil::isa::IsKindHeaderPathProvider;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
|
||||
use diaryid::DiaryId;
|
||||
use diaryid::FromStoreId;
|
||||
use error::Result;
|
||||
|
||||
provide_kindflag_path!(pub IsDiaryEntry, "diary.is_diary_entry");
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -26,10 +26,9 @@ use libimagstore::storeid::StoreIdIterator;
|
|||
use libimagstore::storeid::StoreId;
|
||||
|
||||
use is_in_diary::IsInDiary;
|
||||
use error::DiaryErrorKind as DEK;
|
||||
use error::DiaryError as DE;
|
||||
use error::ResultExt;
|
||||
use error::Result;
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
/// A iterator for iterating over diary entries
|
||||
pub struct DiaryEntryIterator {
|
||||
|
@ -109,7 +108,7 @@ impl Iterator for DiaryEntryIterator {
|
|||
loop {
|
||||
match self.iter.next() {
|
||||
None => return None,
|
||||
Some(Err(e)) => return Some(Err(e).map_err(DE::from)),
|
||||
Some(Err(e)) => return Some(Err(e)),
|
||||
Some(Ok(s)) => {
|
||||
debug!("Next element: {:?}", s);
|
||||
if Filter::filter(self, &s) {
|
||||
|
@ -143,16 +142,15 @@ impl Iterator for DiaryNameIterator {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(next) = self.0.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"]) {
|
||||
return Some(next
|
||||
.to_str()
|
||||
.chain_err(|| DEK::DiaryNameFindingError)
|
||||
.and_then(|s| {
|
||||
s.split("diary/")
|
||||
.nth(1)
|
||||
.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")))
|
||||
}));
|
||||
},
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ extern crate chrono;
|
|||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate itertools;
|
||||
#[macro_use] extern crate error_chain;
|
||||
extern crate failure;
|
||||
extern crate filters;
|
||||
|
||||
#[macro_use] extern crate libimagstore;
|
||||
|
@ -53,7 +53,6 @@ extern crate libimagrt;
|
|||
module_entry_path_mod!("diary");
|
||||
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod diaryid;
|
||||
pub mod diary;
|
||||
pub mod is_in_diary;
|
||||
|
|
|
@ -22,11 +22,13 @@
|
|||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use failure::ResultExt;
|
||||
use failure::err_msg;
|
||||
use failure::Error;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
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 entry::DiaryEntry;
|
||||
|
||||
|
@ -51,7 +53,7 @@ impl 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
|
||||
{
|
||||
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
|
||||
/// 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>,
|
||||
E: Deref<Target = Entry>,
|
||||
W: Write
|
||||
{
|
||||
let mut entries = entries
|
||||
.map(|e| e.deref().diary_id().map(|id| (id, e)).chain_err(|| VEK::ViewError))
|
||||
.collect::<ViewResult<Vec<_>>>()?;
|
||||
.map(|e| {
|
||||
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, _)| {
|
||||
[id.year() as u32, id.month(), id.day(), id.hour(), id.minute(), id.second()]
|
||||
|
|
|
@ -23,9 +23,9 @@ maintenance = { status = "actively-developed" }
|
|||
chrono = "0.4"
|
||||
log = "0.4"
|
||||
toml = "0.4"
|
||||
toml-query = "0.7"
|
||||
error-chain = "0.12"
|
||||
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "master" }
|
||||
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||
kairos = { git = "https://github.com/matthiasbeyer/kairos", branch = "failure" }
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -23,10 +23,10 @@ use toml_query::insert::TomlValueInsertExt;
|
|||
use chrono::NaiveDateTime;
|
||||
use chrono::Local;
|
||||
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 util::IsHabitCheck;
|
||||
use util::get_string_header_from_entry;
|
||||
|
@ -148,7 +148,7 @@ impl HabitTemplate for Entry {
|
|||
match parse(&r)? {
|
||||
Parsed::TimeType(tt) => Ok(tt),
|
||||
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()?
|
||||
.get_moment()
|
||||
.map(Clone::clone)
|
||||
.ok_or_else(|| {
|
||||
let kind : HEK = "until-date seems to have non-date value".to_owned().into();
|
||||
HE::from_kind(kind)
|
||||
})
|
||||
.ok_or_else(|| Error::from(err_msg("until-date seems to have non-date value")))
|
||||
});
|
||||
|
||||
debug!("Until-Date is {:?}", basedate);
|
||||
|
@ -192,7 +189,7 @@ impl HabitTemplate for Entry {
|
|||
}
|
||||
}
|
||||
} 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))
|
||||
.into_storeid()
|
||||
.map_err(HE::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
pub mod builder {
|
||||
|
@ -280,9 +277,10 @@ pub mod builder {
|
|||
use libimagentryutil::isa::Is;
|
||||
use libimagutil::debug_result::DebugResult;
|
||||
|
||||
use error::HabitError as HE;
|
||||
use error::HabitErrorKind as HEK;
|
||||
use error::*;
|
||||
use failure::Error;
|
||||
use failure::Fallible as Result;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagutil::date::date_to_string;
|
||||
use habit::IsHabitTemplate;
|
||||
|
||||
|
@ -324,8 +322,8 @@ pub mod builder {
|
|||
|
||||
pub fn build<'a>(self, store: &'a Store) -> Result<FileLockEntry<'a>> {
|
||||
#[inline]
|
||||
fn mkerr(s: &'static str) -> HE {
|
||||
HE::from_kind(HEK::HabitBuilderMissing(s))
|
||||
fn mkerr(s: &'static str) -> Error {
|
||||
Error::from(format_err!("Habit builder missing: {}", s))
|
||||
}
|
||||
|
||||
let name = self.name
|
||||
|
@ -336,21 +334,21 @@ pub mod builder {
|
|||
.ok_or_else(|| mkerr("date"))
|
||||
.map_dbg_str("Success: Date present")?;
|
||||
|
||||
let recur = self.recurspec
|
||||
let recur : String = self.recurspec
|
||||
.ok_or_else(|| mkerr("recurspec"))
|
||||
.map_dbg_str("Success: Recurr spec present")?;
|
||||
|
||||
if let Some(until) = self.untildate {
|
||||
debug!("Success: Until-Date present");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = ::kairos::parser::parse(&recur) {
|
||||
if let Err(e) = ::kairos::parser::parse(&recur).map_err(Error::from) {
|
||||
debug!("Kairos failed: {:?}", e);
|
||||
return Err(e).map_err(From::from);
|
||||
return Err(e)
|
||||
}
|
||||
let date = date_to_string(&dateobj);
|
||||
debug!("Success: Date valid");
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
use chrono::NaiveDate;
|
||||
use toml::Value;
|
||||
use toml_query::set::TomlValueSetExt;
|
||||
use failure::Fallible as Result;
|
||||
|
||||
use error::*;
|
||||
use util::*;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
// 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::StoreIdIteratorWithStore;
|
||||
use libimagstore::storeid::StoreId;
|
||||
|
||||
use util::IsHabitCheck;
|
||||
use error::Result;
|
||||
use error::HabitError as HE;
|
||||
|
||||
pub struct HabitTemplateStoreIdIterator(StoreIdIterator);
|
||||
|
||||
|
@ -36,7 +37,7 @@ impl Iterator for HabitTemplateStoreIdIterator {
|
|||
Ok(n) => if n.is_habit_template() {
|
||||
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
|
||||
|
@ -72,7 +73,7 @@ impl Iterator for HabitInstanceStoreIdIterator {
|
|||
Ok(n) => if n.is_habit_instance() {
|
||||
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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue