Merge pull request #1037 from matthiasbeyer/libimagerror/based-on-error-chain
Libimagerror/based on error chain
This commit is contained in:
commit
e6d96c9f83
168 changed files with 2077 additions and 2252 deletions
|
@ -18,6 +18,7 @@ clap = ">=2.17"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
toml = "^0.4"
|
toml = "^0.4"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore", features = ["verify"] }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore", features = ["verify"] }
|
||||||
libimagrt = { version = "0.4.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.4.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -38,6 +38,7 @@ use libimagutil::debug_result::*;
|
||||||
|
|
||||||
use error::StoreError;
|
use error::StoreError;
|
||||||
use error::StoreErrorKind;
|
use error::StoreErrorKind;
|
||||||
|
use error::ResultExt;
|
||||||
use util::build_toml_header;
|
use util::build_toml_header;
|
||||||
|
|
||||||
type Result<T> = RResult<T, StoreError>;
|
type Result<T> = RResult<T, StoreError>;
|
||||||
|
@ -110,7 +111,7 @@ fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> R
|
||||||
fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
|
fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
|
||||||
let content = matches
|
let content = matches
|
||||||
.value_of("from-raw")
|
.value_of("from-raw")
|
||||||
.ok_or(StoreError::new(StoreErrorKind::NoCommandlineCall, None))
|
.ok_or(StoreError::from_kind(StoreErrorKind::NoCommandlineCall))
|
||||||
.map(string_from_raw_src);
|
.map(string_from_raw_src);
|
||||||
|
|
||||||
if content.is_err() {
|
if content.is_err() {
|
||||||
|
@ -133,7 +134,7 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Res
|
||||||
r
|
r
|
||||||
})
|
})
|
||||||
.map_dbg_err(|e| format!("Error storing entry: {:?}", e))
|
.map_dbg_err(|e| format!("Error storing entry: {:?}", e))
|
||||||
.map_err(|serr| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(serr))))
|
.chain_err(|| StoreErrorKind::BackendError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_with_content_and_header(rt: &Runtime,
|
fn create_with_content_and_header(rt: &Runtime,
|
||||||
|
@ -157,7 +158,7 @@ fn create_with_content_and_header(rt: &Runtime,
|
||||||
debug!("New header set");
|
debug!("New header set");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err(|e| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(e))))
|
.chain_err(|| StoreErrorKind::BackendError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string_from_raw_src(raw_src: &str) -> String {
|
fn string_from_raw_src(raw_src: &str) -> String {
|
||||||
|
|
|
@ -17,13 +17,22 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(StoreError, StoreErrorKind,
|
types {
|
||||||
BackendError => "Backend Error",
|
StoreError, StoreErrorKind, ResultExt, Result;
|
||||||
NoCommandlineCall => "No commandline call"
|
}
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::StoreError;
|
errors {
|
||||||
pub use self::error::StoreErrorKind;
|
BackendError {
|
||||||
|
description("Backend Error")
|
||||||
|
display("Backend Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
NoCommandlineCall {
|
||||||
|
description("No commandline call")
|
||||||
|
display("No commandline call")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,14 +37,16 @@ extern crate clap;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
#[cfg(test)] extern crate toml_query;
|
#[cfg(test)] extern crate toml_query;
|
||||||
#[macro_use] extern crate version;
|
#[macro_use] extern crate version;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use clap::ArgMatches;
|
||||||
use libimagdiary::diary::Diary;
|
use libimagdiary::diary::Diary;
|
||||||
use libimagdiary::diaryid::DiaryId;
|
use libimagdiary::diaryid::DiaryId;
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
use libimagdiary::error::DiaryErrorKind as DEK;
|
||||||
use libimagdiary::error::MapErrInto;
|
use libimagdiary::error::ResultExt;
|
||||||
use libimagentryedit::edit::Edit;
|
use libimagentryedit::edit::Edit;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::trace_error_exit;
|
use libimagerror::trace::trace_error_exit;
|
||||||
|
@ -46,7 +46,7 @@ pub fn create(rt: &Runtime) {
|
||||||
} else {
|
} else {
|
||||||
debug!("Editing new diary entry");
|
debug!("Editing new diary entry");
|
||||||
entry.edit_content(rt)
|
entry.edit_content(rt)
|
||||||
.map_err_into(DEK::DiaryEditError)
|
.chain_err(|| DEK::DiaryEditError)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
|
@ -63,7 +63,7 @@ fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLock
|
||||||
diary.new_entry_today(diaryname)
|
diary.new_entry_today(diaryname)
|
||||||
} else {
|
} else {
|
||||||
let id = create_id_from_clispec(&create, &diaryname);
|
let id = create_id_from_clispec(&create, &diaryname);
|
||||||
diary.retrieve(id).map_err_into(DEK::StoreReadError)
|
diary.retrieve(id).chain_err(|| DEK::StoreReadError)
|
||||||
};
|
};
|
||||||
|
|
||||||
match entry {
|
match entry {
|
||||||
|
|
|
@ -24,11 +24,11 @@ use chrono::naive::NaiveDateTime;
|
||||||
use libimagdiary::diary::Diary;
|
use libimagdiary::diary::Diary;
|
||||||
use libimagdiary::diaryid::DiaryId;
|
use libimagdiary::diaryid::DiaryId;
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
use libimagdiary::error::DiaryErrorKind as DEK;
|
||||||
use libimagdiary::error::MapErrInto;
|
use libimagdiary::error::DiaryError as DE;
|
||||||
|
use libimagdiary::error::ResultExt;
|
||||||
use libimagentryedit::edit::Edit;
|
use libimagentryedit::edit::Edit;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
use libimagerror::trace::MapErrTrace;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
use libimagtimeui::datetime::DateTime;
|
use libimagtimeui::datetime::DateTime;
|
||||||
use libimagtimeui::parse::Parse;
|
use libimagtimeui::parse::Parse;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
use libimagutil::warn_exit::warn_exit;
|
||||||
|
@ -60,8 +60,8 @@ pub fn edit(rt: &Runtime) {
|
||||||
})
|
})
|
||||||
.and_then(|id| rt.store().get(id))
|
.and_then(|id| rt.store().get(id))
|
||||||
.map(|opte| match opte {
|
.map(|opte| match opte {
|
||||||
Some(mut e) => e.edit_content(rt).map_err_into(DEK::IOError),
|
Some(mut e) => e.edit_content(rt).chain_err(|| DEK::IOError),
|
||||||
None => Err(DEK::EntryNotInDiary.into_error()),
|
None => Err(DE::from_kind(DEK::EntryNotInDiary)),
|
||||||
})
|
})
|
||||||
.map_err_trace()
|
.map_err_trace()
|
||||||
.ok();
|
.ok();
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
use libimagdiary::diary::Diary;
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
use libimagdiary::error::DiaryErrorKind as DEK;
|
||||||
use libimagdiary::error::MapErrInto;
|
use libimagdiary::error::ResultExt;
|
||||||
use libimagentrylist::listers::core::CoreLister;
|
use libimagentrylist::listers::core::CoreLister;
|
||||||
use libimagentrylist::lister::Lister;
|
use libimagentrylist::lister::Lister;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
|
@ -57,7 +57,7 @@ pub fn list(rt: &Runtime) {
|
||||||
|
|
||||||
CoreLister::new(&entry_to_location_listing_string)
|
CoreLister::new(&entry_to_location_listing_string)
|
||||||
.list(es)
|
.list(es)
|
||||||
.map_err_into(DEK::IOError)
|
.chain_err(|| DEK::IOError)
|
||||||
})
|
})
|
||||||
.map_dbg_str("Ok")
|
.map_dbg_str("Ok")
|
||||||
.map_err_trace()
|
.map_err_trace()
|
||||||
|
|
|
@ -66,13 +66,13 @@ fn import_mail(rt: &Runtime) {
|
||||||
|
|
||||||
fn list(rt: &Runtime) {
|
fn list(rt: &Runtime) {
|
||||||
use libimagmail::error::MailErrorKind as MEK;
|
use libimagmail::error::MailErrorKind as MEK;
|
||||||
use libimagmail::error::MapErrInto;
|
use libimagmail::error::ResultExt;
|
||||||
|
|
||||||
let store = rt.store();
|
let store = rt.store();
|
||||||
|
|
||||||
let iter = match store.retrieve_for_module("ref") {
|
let iter = match store.retrieve_for_module("ref") {
|
||||||
Ok(iter) => iter.filter_map(|id| {
|
Ok(iter) => iter.filter_map(|id| {
|
||||||
match store.get(id).map_err_into(MEK::RefHandlingError).map_err_trace() {
|
match store.get(id).chain_err(|| MEK::RefHandlingError).map_err_trace() {
|
||||||
Ok(Some(fle)) => Mail::from_fle(fle).map_err_trace().ok(),
|
Ok(Some(fle)) => Mail::from_fle(fle).map_err_trace().ok(),
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Err(e) => trace_error_exit(&e, 1),
|
Err(e) => trace_error_exit(&e, 1),
|
||||||
|
|
|
@ -72,15 +72,15 @@ Now the modules that are not yet started:
|
||||||
|
|
||||||
## Libraries
|
## Libraries
|
||||||
|
|
||||||
- [ ] Ensure all libraries are implemented as extension traits rather than
|
- [x] Rewrite libimagerror to be based on `chain-error` crate. This basically
|
||||||
wrapping store types
|
|
||||||
- [ ] Rewrite logger to allow config/env-var based module white/blacklisting and
|
|
||||||
writing log to file
|
|
||||||
- [ ] Rewrite libimagerror to be based on `chain-error` crate. This basically
|
|
||||||
removes our error infrastructure, though existing traits and convenience
|
removes our error infrastructure, though existing traits and convenience
|
||||||
functionality should be kept (for example the `MapErrInto` or the `IntoError`
|
functionality should be kept (for example the `MapErrInto` or the `IntoError`
|
||||||
traits), as much as possible). If the switch to `chain-error` would require
|
traits), as much as possible). If the switch to `chain-error` would require
|
||||||
too much code to be rewritten, reconsider.
|
too much code to be rewritten, reconsider.
|
||||||
|
- [ ] Ensure all libraries are implemented as extension traits rather than
|
||||||
|
wrapping store types
|
||||||
|
- [ ] Rewrite logger to allow config/env-var based module white/blacklisting and
|
||||||
|
writing log to file
|
||||||
|
|
||||||
## User Interface
|
## User Interface
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ This section contains the changelog from the last release to the next release.
|
||||||
subdirectories were introduced for different types of crates
|
subdirectories were introduced for different types of crates
|
||||||
* The documentation got a major overhaul and was partly rewritten
|
* The documentation got a major overhaul and was partly rewritten
|
||||||
* The logger is now configurable via the config file.
|
* The logger is now configurable via the config file.
|
||||||
|
* The error handling of the whole codebase is based on the `error_chain`
|
||||||
|
now. `libimagerror` only contains convenience functionality, no
|
||||||
|
error-generating macros or such things anymore.
|
||||||
* New
|
* New
|
||||||
* `libimagentrygps` was introduced
|
* `libimagentrygps` was introduced
|
||||||
* Fixed bugs
|
* Fixed bugs
|
||||||
|
|
|
@ -1,440 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! generate_error_imports {
|
|
||||||
() => {
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::Error as FmtError;
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
|
|
||||||
use $crate::into::IntoError;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! generate_error_module {
|
|
||||||
( $exprs:item ) => {
|
|
||||||
pub mod error {
|
|
||||||
generate_error_imports!();
|
|
||||||
$exprs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! generate_custom_error_types {
|
|
||||||
{
|
|
||||||
$name: ident,
|
|
||||||
$kindname: ident,
|
|
||||||
$customMemberTypeName: ident,
|
|
||||||
$($kind:ident => $string:expr),*
|
|
||||||
} => {
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub enum $kindname {
|
|
||||||
$( $kind ),*
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for $kindname {
|
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
let s = match *self {
|
|
||||||
$( $kindname::$kind => $string ),*
|
|
||||||
};
|
|
||||||
try!(write!(fmt, "{}", s));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoError for $kindname {
|
|
||||||
type Target = $name;
|
|
||||||
|
|
||||||
fn into_error(self) -> Self::Target {
|
|
||||||
$name::new(self, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
|
|
||||||
$name::new(self, Some(cause))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct $name {
|
|
||||||
err_type: $kindname,
|
|
||||||
cause: Option<Box<Error>>,
|
|
||||||
custom_data: Option<$customMemberTypeName>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
|
|
||||||
pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
|
|
||||||
$name {
|
|
||||||
err_type: errtype,
|
|
||||||
cause: cause,
|
|
||||||
custom_data: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn err_type(&self) -> $kindname {
|
|
||||||
self.err_type
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_custom_data(mut self, custom: $customMemberTypeName) -> $name {
|
|
||||||
self.custom_data = Some(custom);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<$name> for $kindname {
|
|
||||||
|
|
||||||
fn into(self) -> $name {
|
|
||||||
$name::new(self, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for $name {
|
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
try!(write!(fmt, "[{}]", self.err_type));
|
|
||||||
match self.custom_data {
|
|
||||||
Some(ref c) => write!(fmt, "{}", c),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for $name {
|
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match self.err_type {
|
|
||||||
$( $kindname::$kind => $string ),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&Error> {
|
|
||||||
self.cause.as_ref().map(|e| &**e)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! generate_result_helper {
|
|
||||||
(
|
|
||||||
$name: ident,
|
|
||||||
$kindname: ident
|
|
||||||
) => {
|
|
||||||
/// Trait to replace
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// foo.map_err(Box::new).map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(e))
|
|
||||||
/// // or:
|
|
||||||
/// foo.map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(Box::new(e)))
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// with much nicer
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// foo.map_err_into(SomeType::SomeErrorKind)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub trait MapErrInto<T> {
|
|
||||||
fn map_err_into(self, error_kind: $kindname) -> Result<T, $name>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: Error + 'static> MapErrInto<T> for Result<T, E> {
|
|
||||||
|
|
||||||
fn map_err_into(self, error_kind: $kindname) -> Result<T, $name> {
|
|
||||||
self.map_err(Box::new)
|
|
||||||
.map_err(|e| error_kind.into_error_with_cause(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! generate_option_helper {
|
|
||||||
(
|
|
||||||
$name: ident,
|
|
||||||
$kindname: ident
|
|
||||||
) => {
|
|
||||||
/// Trait to replace
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// foo.ok_or(SomeType::SomeErrorKind.into_error())
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// with
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// foo.ok_or_errkind(SomeType::SomeErrorKind)
|
|
||||||
/// ```
|
|
||||||
pub trait OkOrErr<T> {
|
|
||||||
fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> OkOrErr<T> for Option<T> {
|
|
||||||
|
|
||||||
fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name> {
|
|
||||||
self.ok_or(kind.into_error())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! generate_error_types {
|
|
||||||
(
|
|
||||||
$name: ident,
|
|
||||||
$kindname: ident,
|
|
||||||
$($kind:ident => $string:expr),*
|
|
||||||
) => {
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
|
|
||||||
pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
|
|
||||||
|
|
||||||
impl Display for SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {
|
|
||||||
fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_custom_error_types!($name, $kindname,
|
|
||||||
SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
|
|
||||||
$($kind => $string),*);
|
|
||||||
|
|
||||||
generate_result_helper!($name, $kindname);
|
|
||||||
generate_option_helper!($name, $kindname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod test {
|
|
||||||
|
|
||||||
generate_error_module!(
|
|
||||||
generate_error_types!(TestError, TestErrorKind,
|
|
||||||
TestErrorKindA => "testerrorkind a",
|
|
||||||
TestErrorKindB => "testerrorkind B");
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
|
|
||||||
pub struct CustomData {
|
|
||||||
pub test: i32,
|
|
||||||
pub othr: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for CustomData {
|
|
||||||
fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_error_imports!();
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
generate_custom_error_types!(CustomTestError, CustomTestErrorKind,
|
|
||||||
CustomData,
|
|
||||||
CustomErrorKindA => "customerrorkind a",
|
|
||||||
CustomErrorKindB => "customerrorkind B");
|
|
||||||
|
|
||||||
// Allow dead code here.
|
|
||||||
// We wrote this to show that custom test types can be implemented.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl CustomTestError {
|
|
||||||
pub fn test(&self) -> i32 {
|
|
||||||
match self.custom_data {
|
|
||||||
Some(t) => t.test,
|
|
||||||
None => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bar(&self) -> i64 {
|
|
||||||
match self.custom_data {
|
|
||||||
Some(t) => t.othr,
|
|
||||||
None => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_a() {
|
|
||||||
use self::error::{TestError, TestErrorKind};
|
|
||||||
|
|
||||||
let kind = TestErrorKind::TestErrorKindA;
|
|
||||||
assert_eq!(String::from("testerrorkind a"), format!("{}", kind));
|
|
||||||
|
|
||||||
let e = TestError::new(kind, None);
|
|
||||||
assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_b() {
|
|
||||||
use self::error::{TestError, TestErrorKind};
|
|
||||||
|
|
||||||
let kind = TestErrorKind::TestErrorKindB;
|
|
||||||
assert_eq!(String::from("testerrorkind B"), format!("{}", kind));
|
|
||||||
|
|
||||||
let e = TestError::new(kind, None);
|
|
||||||
assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ab() {
|
|
||||||
use std::error::Error;
|
|
||||||
use self::error::{TestError, TestErrorKind};
|
|
||||||
|
|
||||||
let kinda = TestErrorKind::TestErrorKindA;
|
|
||||||
let kindb = TestErrorKind::TestErrorKindB;
|
|
||||||
assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
|
|
||||||
assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));
|
|
||||||
|
|
||||||
let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
|
|
||||||
assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
|
|
||||||
assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
|
|
||||||
assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod anothererrormod {
|
|
||||||
generate_error_imports!();
|
|
||||||
generate_error_types!(TestError, TestErrorKind,
|
|
||||||
TestErrorKindA => "testerrorkind a",
|
|
||||||
TestErrorKindB => "testerrorkind B");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_other_a() {
|
|
||||||
use self::anothererrormod::{TestError, TestErrorKind};
|
|
||||||
|
|
||||||
let kind = TestErrorKind::TestErrorKindA;
|
|
||||||
assert_eq!(String::from("testerrorkind a"), format!("{}", kind));
|
|
||||||
|
|
||||||
let e = TestError::new(kind, None);
|
|
||||||
assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_other_b() {
|
|
||||||
use self::anothererrormod::{TestError, TestErrorKind};
|
|
||||||
|
|
||||||
let kind = TestErrorKind::TestErrorKindB;
|
|
||||||
assert_eq!(String::from("testerrorkind B"), format!("{}", kind));
|
|
||||||
|
|
||||||
let e = TestError::new(kind, None);
|
|
||||||
assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_other_ab() {
|
|
||||||
use std::error::Error;
|
|
||||||
use self::anothererrormod::{TestError, TestErrorKind};
|
|
||||||
|
|
||||||
let kinda = TestErrorKind::TestErrorKindA;
|
|
||||||
let kindb = TestErrorKind::TestErrorKindB;
|
|
||||||
assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
|
|
||||||
assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));
|
|
||||||
|
|
||||||
let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
|
|
||||||
assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
|
|
||||||
assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
|
|
||||||
assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_error_kind_mapping() {
|
|
||||||
use std::io::{Error, ErrorKind};
|
|
||||||
use self::error::MapErrInto;
|
|
||||||
use self::error::TestErrorKind;
|
|
||||||
|
|
||||||
let err : Result<(), _> = Err(Error::new(ErrorKind::Other, ""));
|
|
||||||
let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA);
|
|
||||||
|
|
||||||
assert!(err.is_err());
|
|
||||||
let err = err.unwrap_err();
|
|
||||||
|
|
||||||
match err.err_type() {
|
|
||||||
TestErrorKind::TestErrorKindA => assert!(true),
|
|
||||||
_ => assert!(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_error_kind_double_mapping() {
|
|
||||||
use std::io::{Error, ErrorKind};
|
|
||||||
use self::error::MapErrInto;
|
|
||||||
use self::error::TestErrorKind;
|
|
||||||
|
|
||||||
let err : Result<(), _> = Err(Error::new(ErrorKind::Other, ""));
|
|
||||||
let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA)
|
|
||||||
.map_err_into(TestErrorKind::TestErrorKindB);
|
|
||||||
|
|
||||||
assert!(err.is_err());
|
|
||||||
let err = err.unwrap_err();
|
|
||||||
match err.err_type() {
|
|
||||||
TestErrorKind::TestErrorKindB => assert!(true),
|
|
||||||
_ => assert!(false),
|
|
||||||
}
|
|
||||||
|
|
||||||
// not sure how to test that the inner error is of TestErrorKindA, actually...
|
|
||||||
match err.cause() {
|
|
||||||
Some(_) => assert!(true),
|
|
||||||
None => assert!(false),
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_error_option_good() {
|
|
||||||
use self::error::OkOrErr;
|
|
||||||
use self::error::TestErrorKind;
|
|
||||||
|
|
||||||
let something = Some(1);
|
|
||||||
match something.ok_or_errkind(TestErrorKind::TestErrorKindA) {
|
|
||||||
Ok(1) => assert!(true),
|
|
||||||
_ => assert!(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_error_option_bad() {
|
|
||||||
use self::error::OkOrErr;
|
|
||||||
use self::error::TestErrorKind;
|
|
||||||
|
|
||||||
let something : Option<i32> = None;
|
|
||||||
match something.ok_or_errkind(TestErrorKind::TestErrorKindA) {
|
|
||||||
Ok(_) => assert!(false),
|
|
||||||
Err(_) => assert!(true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::error::Error;
|
|
||||||
|
|
||||||
/// Trait to help converting Error kinds into Error instances
|
|
||||||
pub trait IntoError {
|
|
||||||
type Target: Error;
|
|
||||||
|
|
||||||
/// Convert the type into an error with no cause
|
|
||||||
fn into_error(self) -> Self::Target;
|
|
||||||
|
|
||||||
/// Convert the type into an error with cause
|
|
||||||
fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,7 +36,5 @@
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
|
|
||||||
pub mod into;
|
|
||||||
pub mod error_gen;
|
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
|
|
|
@ -23,6 +23,7 @@ itertools = "0.5"
|
||||||
ansi_term = "0.9"
|
ansi_term = "0.9"
|
||||||
is-match = "0.1"
|
is-match = "0.1"
|
||||||
toml-query = "0.3.0"
|
toml-query = "0.3.0"
|
||||||
|
error-chain = "0.10"
|
||||||
handlebars = "0.29.0"
|
handlebars = "0.29.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
|
@ -18,29 +18,45 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::result::Result as RResult;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(ConfigError, ConfigErrorKind,
|
types {
|
||||||
TOMLParserError => "TOML Parsing error",
|
ConfigError, ConfigErrorKind, ResultExt, Result;
|
||||||
NoConfigFileFound => "No config file found",
|
}
|
||||||
|
|
||||||
ConfigOverrideError => "Config override error",
|
errors {
|
||||||
ConfigOverrideKeyNotAvailable => "Key not available",
|
TOMLParserError {
|
||||||
ConfigOverrideTypeNotMatching => "Configuration Type not matching"
|
description("TOML Parsing error")
|
||||||
|
display("TOML Parsing error")
|
||||||
|
}
|
||||||
|
|
||||||
);
|
NoConfigFileFound {
|
||||||
);
|
description("No config file found")
|
||||||
|
display("No config file found")
|
||||||
|
}
|
||||||
|
|
||||||
pub use self::error::{ConfigError, ConfigErrorKind, MapErrInto};
|
ConfigOverrideError {
|
||||||
use libimagerror::into::IntoError;
|
description("Config override error")
|
||||||
|
display("Config override error")
|
||||||
|
}
|
||||||
|
|
||||||
/// Result type of this module. Either `T` or `ConfigError`
|
ConfigOverrideKeyNotAvailable {
|
||||||
pub type Result<T> = RResult<T, ConfigError>;
|
description("Key not available")
|
||||||
|
display("Key not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigOverrideTypeNotMatching {
|
||||||
|
description("Configuration Type not matching")
|
||||||
|
display("Configuration Type not matching")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use self::ConfigErrorKind as CEK;
|
||||||
|
use self::ConfigError as CE;
|
||||||
|
|
||||||
/// `Configuration` object
|
/// `Configuration` object
|
||||||
///
|
///
|
||||||
|
@ -130,9 +146,6 @@ impl Configuration {
|
||||||
pub fn override_config(&mut self, v: Vec<String>) -> Result<()> {
|
pub fn override_config(&mut self, v: Vec<String>) -> Result<()> {
|
||||||
use libimagutil::key_value_split::*;
|
use libimagutil::key_value_split::*;
|
||||||
use libimagutil::iter::*;
|
use libimagutil::iter::*;
|
||||||
use self::error::ConfigErrorKind as CEK;
|
|
||||||
use self::error::MapErrInto;
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
||||||
|
@ -148,21 +161,20 @@ impl Configuration {
|
||||||
.map(|(k, v)| self
|
.map(|(k, v)| self
|
||||||
.config
|
.config
|
||||||
.read(&k[..])
|
.read(&k[..])
|
||||||
.map_err_into(CEK::TOMLParserError)
|
.chain_err(|| CEK::TOMLParserError)
|
||||||
.map(|toml| match toml {
|
.map(|toml| match toml {
|
||||||
Some(value) => match into_value(value, v) {
|
Some(value) => match into_value(value, v) {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
info!("Successfully overridden: {} = {}", k, v);
|
info!("Successfully overridden: {} = {}", k, v);
|
||||||
Ok(v)
|
Ok(v)
|
||||||
},
|
},
|
||||||
None => Err(CEK::ConfigOverrideTypeNotMatching.into_error()),
|
None => Err(CE::from_kind(CEK::ConfigOverrideTypeNotMatching)),
|
||||||
},
|
},
|
||||||
None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
|
None => Err(CE::from_kind(CEK::ConfigOverrideKeyNotAvailable)),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.fold_result(|i| i)
|
.fold_result(|i| i)
|
||||||
.map_err(Box::new)
|
.chain_err(|| CEK::ConfigOverrideError)
|
||||||
.map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,13 +294,13 @@ fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
||||||
.unwrap_or_else(|| String::from("Line unknown, Column unknown"));
|
.unwrap_or_else(|| String::from("Line unknown, Column unknown"));
|
||||||
|
|
||||||
let _ = write!(stderr(), "Config file parser error at {}", line_col);
|
let _ = write!(stderr(), "Config file parser error at {}", line_col);
|
||||||
trace_error(&ConfigErrorKind::TOMLParserError.into_error_with_cause(Box::new(e)));
|
trace_error(&e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.ok_or(ConfigErrorKind::NoConfigFileFound.into())
|
.ok_or(CE::from_kind(ConfigErrorKind::NoConfigFileFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InternalConfiguration {
|
pub trait InternalConfiguration {
|
||||||
|
|
|
@ -17,33 +17,92 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_imports!();
|
error_chain! {
|
||||||
use std::io::Error as IOError;
|
types {
|
||||||
|
RuntimeError, RuntimeErrorKind, ResultExt, Result;
|
||||||
generate_error_types!(RuntimeError, RuntimeErrorKind,
|
|
||||||
Instantiate => "Could not instantiate",
|
|
||||||
IOError => "IO Error",
|
|
||||||
IOLogFileOpenError => "IO Error: Could not open logfile",
|
|
||||||
ProcessExitFailure => "Process exited with failure",
|
|
||||||
ConfigReadError => "Error while reading the configuration",
|
|
||||||
ConfigTypeError => "Error while reading the configuration: Type Error",
|
|
||||||
GlobalLogLevelConfigMissing => "Global config 'imag.logging.level' missing",
|
|
||||||
GlobalDestinationConfigMissing => "Global config 'imag.logging.destinations' missing",
|
|
||||||
InvalidLogLevelSpec => "Invalid log level specification: Only 'trace', 'debug', 'info', 'warn', 'error' are allowed",
|
|
||||||
TomlReadError => "Error while reading in TOML document",
|
|
||||||
TemplateStringRegistrationError => "Error while registering logging template string",
|
|
||||||
ConfigMissingLoggingFormatTrace => "Missing config for logging format for trace logging",
|
|
||||||
ConfigMissingLoggingFormatDebug => "Missing config for logging format for debug logging",
|
|
||||||
ConfigMissingLoggingFormatInfo => "Missing config for logging format for info logging",
|
|
||||||
ConfigMissingLoggingFormatWarn => "Missing config for logging format for warn logging",
|
|
||||||
ConfigMissingLoggingFormatError => "Missing config for logging format for error logging"
|
|
||||||
);
|
|
||||||
|
|
||||||
impl From<IOError> for RuntimeError {
|
|
||||||
|
|
||||||
fn from(ioe: IOError) -> RuntimeError {
|
|
||||||
RuntimeErrorKind::IOError.into_error_with_cause(Box::new(ioe))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigReadError {
|
||||||
|
description("Error while reading the configuration")
|
||||||
|
display("Error while reading the configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigTypeError {
|
||||||
|
description("Error while reading the configuration: Type Error")
|
||||||
|
display("Error while reading the configuration: Type Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
TomlReadError {
|
||||||
|
description("Error while reading in TOML document")
|
||||||
|
display("Error while reading in TOML document")
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateStringRegistrationError {
|
||||||
|
description("Error while registering logging template string")
|
||||||
|
display("Error while registering logging template string")
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -34,6 +36,7 @@
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
#[cfg(unix)] extern crate xdg_basedir;
|
#[cfg(unix)] extern crate xdg_basedir;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
@ -47,7 +50,7 @@ extern crate toml_query;
|
||||||
|
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod configuration;
|
pub mod configuration;
|
||||||
|
|
|
@ -23,12 +23,10 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use configuration::Configuration;
|
use configuration::Configuration;
|
||||||
use error::RuntimeErrorKind as EK;
|
use error::RuntimeErrorKind as EK;
|
||||||
use error::RuntimeError;
|
use error::RuntimeError as RE;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use runtime::Runtime;
|
use runtime::Runtime;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use log::{Log, LogLevel, LogRecord, LogMetadata};
|
use log::{Log, LogLevel, LogRecord, LogMetadata};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
@ -36,7 +34,7 @@ use toml_query::read::TomlValueReadExt;
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
|
|
||||||
type ModuleName = String;
|
type ModuleName = String;
|
||||||
type Result<T> = ::std::result::Result<T, RuntimeError>;
|
type Result<T> = ::std::result::Result<T, RE>;
|
||||||
|
|
||||||
enum LogDestination {
|
enum LogDestination {
|
||||||
Stderr,
|
Stderr,
|
||||||
|
@ -96,27 +94,27 @@ impl ImagLogger {
|
||||||
{
|
{
|
||||||
let fmt = try!(aggregate_global_format_trace(matches, config));
|
let fmt = try!(aggregate_global_format_trace(matches, config));
|
||||||
try!(handlebars.register_template_string("TRACE", fmt) // name must be uppercase
|
try!(handlebars.register_template_string("TRACE", fmt) // name must be uppercase
|
||||||
.map_err_into(EK::TemplateStringRegistrationError));
|
.chain_err(|| EK::TemplateStringRegistrationError));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let fmt = try!(aggregate_global_format_debug(matches, config));
|
let fmt = try!(aggregate_global_format_debug(matches, config));
|
||||||
try!(handlebars.register_template_string("DEBUG", fmt) // name must be uppercase
|
try!(handlebars.register_template_string("DEBUG", fmt) // name must be uppercase
|
||||||
.map_err_into(EK::TemplateStringRegistrationError));
|
.chain_err(|| EK::TemplateStringRegistrationError));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let fmt = try!(aggregate_global_format_info(matches, config));
|
let fmt = try!(aggregate_global_format_info(matches, config));
|
||||||
try!(handlebars.register_template_string("INFO", fmt) // name must be uppercase
|
try!(handlebars.register_template_string("INFO", fmt) // name must be uppercase
|
||||||
.map_err_into(EK::TemplateStringRegistrationError));
|
.chain_err(|| EK::TemplateStringRegistrationError));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let fmt = try!(aggregate_global_format_warn(matches, config));
|
let fmt = try!(aggregate_global_format_warn(matches, config));
|
||||||
try!(handlebars.register_template_string("WARN", fmt) // name must be uppercase
|
try!(handlebars.register_template_string("WARN", fmt) // name must be uppercase
|
||||||
.map_err_into(EK::TemplateStringRegistrationError));
|
.chain_err(|| EK::TemplateStringRegistrationError));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let fmt = try!(aggregate_global_format_error(matches, config));
|
let fmt = try!(aggregate_global_format_error(matches, config));
|
||||||
try!(handlebars.register_template_string("ERROR", fmt) // name must be uppercase
|
try!(handlebars.register_template_string("ERROR", fmt) // name must be uppercase
|
||||||
.map_err_into(EK::TemplateStringRegistrationError));
|
.chain_err(|| EK::TemplateStringRegistrationError));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ImagLogger {
|
Ok(ImagLogger {
|
||||||
|
@ -194,7 +192,7 @@ fn match_log_level_str(s: &str) -> Result<LogLevel> {
|
||||||
"info" => Ok(LogLevel::Info),
|
"info" => Ok(LogLevel::Info),
|
||||||
"warn" => Ok(LogLevel::Warn),
|
"warn" => Ok(LogLevel::Warn),
|
||||||
"error" => Ok(LogLevel::Error),
|
"error" => Ok(LogLevel::Error),
|
||||||
_ => return Err(EK::InvalidLogLevelSpec.into_error()),
|
_ => return Err(RE::from_kind(EK::InvalidLogLevelSpec)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,11 +202,11 @@ fn aggregate_global_loglevel(matches: &ArgMatches, config: Option<&Configuration
|
||||||
match config {
|
match config {
|
||||||
Some(cfg) => match cfg
|
Some(cfg) => match cfg
|
||||||
.read("imag.logging.level")
|
.read("imag.logging.level")
|
||||||
.map_err_into(EK::ConfigReadError)
|
.chain_err(|| EK::ConfigReadError)
|
||||||
{
|
{
|
||||||
Ok(Some(&Value::String(ref s))) => match_log_level_str(s),
|
Ok(Some(&Value::String(ref s))) => match_log_level_str(s),
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Ok(None) => Err(EK::GlobalLogLevelConfigMissing.into_error()),
|
Ok(None) => Err(RE::from_kind(EK::GlobalLogLevelConfigMissing)),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -235,7 +233,7 @@ fn translate_destination(raw: &str) -> Result<LogDestination> {
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(other)
|
.open(other)
|
||||||
.map(LogDestination::File)
|
.map(LogDestination::File)
|
||||||
.map_err_into(EK::IOLogFileOpenError)
|
.chain_err(|| EK::IOLogFileOpenError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,7 +245,7 @@ fn translate_destinations(raw: &Vec<Value>) -> Result<Vec<LogDestination>> {
|
||||||
acc.and_then(|mut v| {
|
acc.and_then(|mut v| {
|
||||||
let dest = match *val {
|
let dest = match *val {
|
||||||
Value::String(ref s) => try!(translate_destination(s)),
|
Value::String(ref s) => try!(translate_destination(s)),
|
||||||
_ => return Err(EK::ConfigTypeError.into_error()),
|
_ => return Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
};
|
};
|
||||||
v.push(dest);
|
v.push(dest);
|
||||||
Ok(v)
|
Ok(v)
|
||||||
|
@ -262,11 +260,11 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Configura
|
||||||
match config {
|
match config {
|
||||||
Some(cfg) => match cfg
|
Some(cfg) => match cfg
|
||||||
.read("imag.logging.destinations")
|
.read("imag.logging.destinations")
|
||||||
.map_err_into(EK::ConfigReadError)
|
.chain_err(|| EK::ConfigReadError)
|
||||||
{
|
{
|
||||||
Ok(Some(&Value::Array(ref a))) => translate_destinations(a),
|
Ok(Some(&Value::Array(ref a))) => translate_destinations(a),
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Ok(None) => Err(EK::GlobalDestinationConfigMissing.into_error()),
|
Ok(None) => Err(RE::from_kind(EK::GlobalDestinationConfigMissing)),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -300,16 +298,16 @@ fn aggregate_global_format(
|
||||||
match config {
|
match config {
|
||||||
Some(cfg) => match cfg
|
Some(cfg) => match cfg
|
||||||
.read(read_str)
|
.read(read_str)
|
||||||
.map_err_into(EK::ConfigReadError)
|
.chain_err(|| EK::ConfigReadError)
|
||||||
{
|
{
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
|
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Ok(None) => Err(error_kind_if_missing.into_error()),
|
Ok(None) => Err(RE::from_kind(error_kind_if_missing)),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
},
|
},
|
||||||
None => match matches.value_of(cli_match_name).map(String::from) {
|
None => match matches.value_of(cli_match_name).map(String::from) {
|
||||||
Some(s) => Ok(s),
|
Some(s) => Ok(s),
|
||||||
None => Err(error_kind_if_missing.into_error())
|
None => Err(RE::from_kind(error_kind_if_missing))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,7 +368,7 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Configuratio
|
||||||
match config {
|
match config {
|
||||||
Some(cfg) => match cfg
|
Some(cfg) => match cfg
|
||||||
.read("imag.logging.modules")
|
.read("imag.logging.modules")
|
||||||
.map_err_into(EK::ConfigReadError)
|
.chain_err(|| EK::ConfigReadError)
|
||||||
{
|
{
|
||||||
Ok(Some(&Value::Table(ref t))) => {
|
Ok(Some(&Value::Table(ref t))) => {
|
||||||
// translate the module settings from the table `t`
|
// translate the module settings from the table `t`
|
||||||
|
@ -380,22 +378,22 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Configuratio
|
||||||
let destinations = try!(match v.read("destinations") {
|
let destinations = try!(match v.read("destinations") {
|
||||||
Ok(Some(&Value::Array(ref a))) => translate_destinations(a).map(Some),
|
Ok(Some(&Value::Array(ref a))) => translate_destinations(a).map(Some),
|
||||||
Ok(None) => Ok(None),
|
Ok(None) => Ok(None),
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Err(e) => Err(e).map_err_into(EK::TomlReadError),
|
Err(e) => Err(e).chain_err(|| EK::TomlReadError),
|
||||||
});
|
});
|
||||||
|
|
||||||
let level = try!(match v.read("level") {
|
let level = try!(match v.read("level") {
|
||||||
Ok(Some(&Value::String(ref s))) => match_log_level_str(s).map(Some),
|
Ok(Some(&Value::String(ref s))) => match_log_level_str(s).map(Some),
|
||||||
Ok(None) => Ok(None),
|
Ok(None) => Ok(None),
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Err(e) => Err(e).map_err_into(EK::TomlReadError),
|
Err(e) => Err(e).chain_err(|| EK::TomlReadError),
|
||||||
});
|
});
|
||||||
|
|
||||||
let enabled = try!(match v.read("enabled") {
|
let enabled = try!(match v.read("enabled") {
|
||||||
Ok(Some(&Value::Boolean(b))) => Ok(b),
|
Ok(Some(&Value::Boolean(b))) => Ok(b),
|
||||||
Ok(None) => Ok(false),
|
Ok(None) => Ok(false),
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Err(e) => Err(e).map_err_into(EK::TomlReadError),
|
Err(e) => Err(e).chain_err(|| EK::TomlReadError),
|
||||||
});
|
});
|
||||||
|
|
||||||
let module_settings = ModuleSettings {
|
let module_settings = ModuleSettings {
|
||||||
|
@ -410,7 +408,7 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Configuratio
|
||||||
|
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
},
|
},
|
||||||
Ok(Some(_)) => Err(EK::ConfigTypeError.into_error()),
|
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError)),
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// No modules configured. This is okay!
|
// No modules configured. This is okay!
|
||||||
Ok(BTreeMap::new())
|
Ok(BTreeMap::new())
|
||||||
|
|
|
@ -30,7 +30,7 @@ use log;
|
||||||
use configuration::{Configuration, InternalConfiguration};
|
use configuration::{Configuration, InternalConfiguration};
|
||||||
use error::RuntimeError;
|
use error::RuntimeError;
|
||||||
use error::RuntimeErrorKind;
|
use error::RuntimeErrorKind;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use logger::ImagLogger;
|
use logger::ImagLogger;
|
||||||
|
|
||||||
use libimagerror::trace::*;
|
use libimagerror::trace::*;
|
||||||
|
@ -60,9 +60,8 @@ impl<'a> Runtime<'a> {
|
||||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||||
{
|
{
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use configuration::error::ConfigErrorKind;
|
use configuration::ConfigErrorKind;
|
||||||
|
|
||||||
let matches = cli_app.clone().matches();
|
let matches = cli_app.clone().matches();
|
||||||
|
|
||||||
|
@ -74,8 +73,8 @@ impl<'a> Runtime<'a> {
|
||||||
debug!("Config path = {:?}", configpath);
|
debug!("Config path = {:?}", configpath);
|
||||||
|
|
||||||
let config = match Configuration::new(&configpath) {
|
let config = match Configuration::new(&configpath) {
|
||||||
Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
|
Err(e) => if !is_match!(e.kind(), &ConfigErrorKind::NoConfigFileFound) {
|
||||||
return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
|
return Err(e).chain_err(|| RuntimeErrorKind::Instantiate);
|
||||||
} else {
|
} else {
|
||||||
println!("No config file found.");
|
println!("No config file found.");
|
||||||
println!("Continuing without configuration file");
|
println!("Continuing without configuration file");
|
||||||
|
@ -165,7 +164,7 @@ impl<'a> Runtime<'a> {
|
||||||
store: store,
|
store: store,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err_into(RuntimeErrorKind::Instantiate)
|
.chain_err(|| RuntimeErrorKind::Instantiate)
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -485,11 +484,11 @@ impl<'a> Runtime<'a> {
|
||||||
let mapper = JsonMapper::new();
|
let mapper = JsonMapper::new();
|
||||||
|
|
||||||
StdIoFileAbstraction::new(&mut input, output, mapper)
|
StdIoFileAbstraction::new(&mut input, output, mapper)
|
||||||
.map_err_into(RuntimeErrorKind::Instantiate)
|
.chain_err(|| RuntimeErrorKind::Instantiate)
|
||||||
.and_then(|backend| {
|
.and_then(|backend| {
|
||||||
self.store
|
self.store
|
||||||
.reset_backend(Box::new(backend))
|
.reset_backend(Box::new(backend))
|
||||||
.map_err_into(RuntimeErrorKind::Instantiate)
|
.chain_err(|| RuntimeErrorKind::Instantiate)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,11 +503,11 @@ impl<'a> Runtime<'a> {
|
||||||
let mapper = JsonMapper::new();
|
let mapper = JsonMapper::new();
|
||||||
|
|
||||||
StdoutFileAbstraction::new(output, mapper)
|
StdoutFileAbstraction::new(output, mapper)
|
||||||
.map_err_into(RuntimeErrorKind::Instantiate)
|
.chain_err(|| RuntimeErrorKind::Instantiate)
|
||||||
.and_then(|backend| {
|
.and_then(|backend| {
|
||||||
self.store
|
self.store
|
||||||
.reset_backend(Box::new(backend))
|
.reset_backend(Box::new(backend))
|
||||||
.map_err_into(RuntimeErrorKind::Instantiate)
|
.chain_err(|| RuntimeErrorKind::Instantiate)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ is-match = "0.1"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
libimagutil = { version = "0.4.0", path = "../../../lib/etc/libimagutil" }
|
libimagutil = { version = "0.4.0", path = "../../../lib/etc/libimagutil" }
|
||||||
|
|
|
@ -19,9 +19,8 @@
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use store::Result;
|
use store::Result;
|
||||||
|
use error::StoreError as SE;
|
||||||
|
|
||||||
/// Check whether the configuration is valid for the store
|
/// Check whether the configuration is valid for the store
|
||||||
pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
|
pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
|
||||||
|
@ -35,7 +34,7 @@ pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
|
||||||
Some(Value::Table(_)) => Ok(()),
|
Some(Value::Table(_)) => Ok(()),
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Store config is no table");
|
warn!("Store config is no table");
|
||||||
Err(SEK::ConfigTypeError.into_error())
|
Err(SE::from_kind(SEK::ConfigTypeError))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,99 +17,283 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_imports!();
|
error_chain! {
|
||||||
use std::convert::From;
|
types {
|
||||||
|
StoreError, StoreErrorKind, ResultExt, Result;
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
|
|
||||||
pub struct CustomErrorData {}
|
|
||||||
|
|
||||||
impl Display for CustomErrorData {
|
|
||||||
fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
Ok(()) // Do nothing here, we don't need to print smth
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
|
foreign_links {
|
||||||
ConfigurationError => "Store Configuration Error",
|
Io(::std::io::Error);
|
||||||
ConfigTypeError => "Store configuration type error",
|
TomlDeserError(::toml::de::Error);
|
||||||
ConfigKeyMissingError => "Configuration Key missing",
|
}
|
||||||
|
|
||||||
VersionError => "Incompatible store versions detected",
|
errors {
|
||||||
|
|
||||||
CreateStoreDirDenied => "Creating store directory implicitely denied",
|
ConfigurationError {
|
||||||
FileError => "File Error",
|
description("Store Configuration Error")
|
||||||
IoError => "IO Error",
|
display("Store Configuration Error")
|
||||||
IdLocked => "ID locked",
|
}
|
||||||
IdNotFound => "ID not found",
|
|
||||||
OutOfMemory => "Out of Memory",
|
|
||||||
FileNotFound => "File corresponding to ID not found",
|
|
||||||
FileNotCreated => "File corresponding to ID could not be created",
|
|
||||||
FileNotWritten => "File corresponding to ID could not be written to",
|
|
||||||
FileNotSeeked => "File corresponding to ID could not be seeked",
|
|
||||||
FileNotRemoved => "File corresponding to ID could not be removed",
|
|
||||||
FileNotRenamed => "File corresponding to ID could not be renamed",
|
|
||||||
FileNotCopied => "File could not be copied",
|
|
||||||
DirNotCreated => "Directory/Directories could not be created",
|
|
||||||
StorePathExists => "Store path exists",
|
|
||||||
StorePathCreate => "Store path create",
|
|
||||||
LockError => "Error locking datastructure",
|
|
||||||
LockPoisoned => "The internal Store Lock has been poisoned",
|
|
||||||
EntryAlreadyBorrowed => "Entry is already borrowed",
|
|
||||||
EntryAlreadyExists => "Entry already exists",
|
|
||||||
MalformedEntry => "Entry has invalid formatting, missing header",
|
|
||||||
HeaderPathSyntaxError => "Syntax error in accessor string",
|
|
||||||
HeaderPathTypeFailure => "Header has wrong type for path",
|
|
||||||
HeaderKeyNotFound => "Header Key not found",
|
|
||||||
HeaderTypeFailure => "Header type is wrong",
|
|
||||||
StorePathLacksVersion => "The supplied store path has no version part",
|
|
||||||
GlobError => "glob() error",
|
|
||||||
EncodingError => "Encoding error",
|
|
||||||
StorePathError => "Store Path error",
|
|
||||||
EntryRenameError => "Entry rename error",
|
|
||||||
StoreIdHandlingError => "StoreId handling error",
|
|
||||||
StoreIdLocalPartAbsoluteError => "StoreId 'id' part is absolute (starts with '/') which is not allowed",
|
|
||||||
StoreIdBuildFromFullPathError => "Building StoreId from full file path failed",
|
|
||||||
StoreIdHasNoBaseError => "StoreId has no 'base' part",
|
|
||||||
|
|
||||||
CreateCallError => "Error when calling create()",
|
ConfigTypeError {
|
||||||
RetrieveCallError => "Error when calling retrieve()",
|
description("Store configuration type error")
|
||||||
GetCallError => "Error when calling get()",
|
display("Store configuration type error")
|
||||||
GetAllVersionsCallError => "Error when calling get_all_versions()",
|
}
|
||||||
RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
|
|
||||||
UpdateCallError => "Error when calling update()",
|
|
||||||
RetrieveCopyCallError => "Error when calling retrieve_copy()",
|
|
||||||
DeleteCallError => "Error when calling delete()",
|
|
||||||
MoveCallError => "Error when calling move()",
|
|
||||||
MoveByIdCallError => "Error when calling move_by_id()"
|
|
||||||
);
|
|
||||||
|
|
||||||
generate_result_helper!(StoreError, StoreErrorKind);
|
ConfigKeyMissingError {
|
||||||
generate_option_helper!(StoreError, StoreErrorKind);
|
description("Configuration Key missing")
|
||||||
|
display("Configuration Key missing")
|
||||||
|
}
|
||||||
|
|
||||||
generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
|
VersionError {
|
||||||
TOMLParserErrors => "Several TOML-Parser-Errors",
|
description("Incompatible store versions detected")
|
||||||
MissingMainSection => "Missing main section",
|
display("Incompatible store versions detected")
|
||||||
MissingVersionInfo => "Missing version information in main section",
|
}
|
||||||
NonTableInBaseTable => "A non-table was found in the base table",
|
|
||||||
HeaderInconsistency => "The header is inconsistent"
|
|
||||||
);
|
|
||||||
|
|
||||||
impl From<ParserError> for StoreError {
|
CreateStoreDirDenied {
|
||||||
fn from(ps: ParserError) -> StoreError {
|
description("Creating store directory implicitely denied")
|
||||||
StoreError {
|
display("Creating store directory implicitely denied")
|
||||||
err_type: StoreErrorKind::MalformedEntry,
|
}
|
||||||
cause: Some(Box::new(ps)),
|
|
||||||
custom_data: None,
|
FileError {
|
||||||
}
|
description("File Error")
|
||||||
}
|
display("File Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<::std::io::Error> for StoreError {
|
IoError {
|
||||||
fn from(ps: ::std::io::Error) -> StoreError {
|
description("IO Error")
|
||||||
StoreError {
|
display("IO Error")
|
||||||
err_type: StoreErrorKind::IoError,
|
}
|
||||||
cause: Some(Box::new(ps)),
|
|
||||||
custom_data: None,
|
IdLocked {
|
||||||
|
description("ID locked")
|
||||||
|
display("ID locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
IdNotFound {
|
||||||
|
description("ID not found")
|
||||||
|
display("ID not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
OutOfMemory {
|
||||||
|
description("Out of Memory")
|
||||||
|
display("Out of Memory")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
description("Store path exists")
|
||||||
|
display("Store path exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
StorePathCreate {
|
||||||
|
description("Store path create")
|
||||||
|
display("Store path create")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
description("Entry is already borrowed")
|
||||||
|
display("Entry is already borrowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryAlreadyExists {
|
||||||
|
description("Entry already exists")
|
||||||
|
display("Entry already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
MalformedEntry {
|
||||||
|
description("Entry has invalid formatting, missing header")
|
||||||
|
display("Entry has invalid formatting, missing header")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderPathSyntaxError {
|
||||||
|
description("Syntax error in accessor string")
|
||||||
|
display("Syntax error in accessor string")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderPathTypeFailure {
|
||||||
|
description("Header has wrong type for path")
|
||||||
|
display("Header has wrong type for path")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderKeyNotFound {
|
||||||
|
description("Header Key not found")
|
||||||
|
display("Header Key not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeFailure {
|
||||||
|
description("Header type is wrong")
|
||||||
|
display("Header type is wrong")
|
||||||
|
}
|
||||||
|
|
||||||
|
StorePathLacksVersion {
|
||||||
|
description("The supplied store path has no version part")
|
||||||
|
display("The supplied store path has no version part")
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobError {
|
||||||
|
description("glob() error")
|
||||||
|
display("glob() error")
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodingError {
|
||||||
|
description("Encoding error")
|
||||||
|
display("Encoding error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StorePathError {
|
||||||
|
description("Store Path error")
|
||||||
|
display("Store Path error")
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryRenameError {
|
||||||
|
description("Entry rename error")
|
||||||
|
display("Entry rename error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreIdHandlingError {
|
||||||
|
description("StoreId handling error")
|
||||||
|
display("StoreId handling error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreIdLocalPartAbsoluteError {
|
||||||
|
description("StoreId 'id' part is absolute (starts with '/') which is not allowed")
|
||||||
|
display("StoreId 'id' part is absolute (starts with '/') which is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreIdBuildFromFullPathError {
|
||||||
|
description("Building StoreId from full file path failed")
|
||||||
|
display("Building StoreId from full file path failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreIdHasNoBaseError {
|
||||||
|
description("StoreId has no 'base' part")
|
||||||
|
display("StoreId has no 'base' part")
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateCallError {
|
||||||
|
description("Error when calling create()")
|
||||||
|
display("Error when calling create()")
|
||||||
|
}
|
||||||
|
|
||||||
|
RetrieveCallError {
|
||||||
|
description("Error when calling retrieve()")
|
||||||
|
display("Error when calling retrieve()")
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCallError {
|
||||||
|
description("Error when calling get()")
|
||||||
|
display("Error when calling get()")
|
||||||
|
}
|
||||||
|
|
||||||
|
GetAllVersionsCallError {
|
||||||
|
description("Error when calling get_all_versions()")
|
||||||
|
display("Error when calling get_all_versions()")
|
||||||
|
}
|
||||||
|
|
||||||
|
RetrieveForModuleCallError {
|
||||||
|
description("Error when calling retrieve_for_module()")
|
||||||
|
display("Error when calling retrieve_for_module()")
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateCallError {
|
||||||
|
description("Error when calling update()")
|
||||||
|
display("Error when calling update()")
|
||||||
|
}
|
||||||
|
|
||||||
|
RetrieveCopyCallError {
|
||||||
|
description("Error when calling retrieve_copy()")
|
||||||
|
display("Error when calling retrieve_copy()")
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteCallError {
|
||||||
|
description("Error when calling delete()")
|
||||||
|
display("Error when calling delete()")
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveCallError {
|
||||||
|
description("Error when calling move()")
|
||||||
|
display("Error when calling move()")
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveByIdCallError {
|
||||||
|
description("Error when calling move_by_id()")
|
||||||
|
display("Error when calling move_by_id()")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser-related errors
|
||||||
|
|
||||||
|
TOMLParserErrors {
|
||||||
|
description("Several TOML-Parser-Errors")
|
||||||
|
display("Several TOML-Parser-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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
|
||||||
use std::io::{Seek, SeekFrom, Read};
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};
|
use error::{StoreError as SE, StoreErrorKind as SEK};
|
||||||
|
use error::ResultExt;
|
||||||
|
|
||||||
use super::FileAbstraction;
|
use super::FileAbstraction;
|
||||||
use super::FileAbstractionInstance;
|
use super::FileAbstractionInstance;
|
||||||
|
@ -47,22 +48,22 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
|
||||||
// We seek to the beginning of the file since we expect each
|
// We seek to the beginning of the file since we expect each
|
||||||
// access to the file to be in a different context
|
// access to the file to be in a different context
|
||||||
try!(f.seek(SeekFrom::Start(0))
|
try!(f.seek(SeekFrom::Start(0))
|
||||||
.map_err_into(SEK::FileNotSeeked));
|
.chain_err(|| SEK::FileNotSeeked));
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
f.read_to_string(&mut s)
|
f.read_to_string(&mut s)
|
||||||
.map_err_into(SEK::IoError)
|
.chain_err(|| SEK::IoError)
|
||||||
.map(|_| s)
|
.map(|_| s)
|
||||||
.and_then(|s| Entry::from_str(id, &s))
|
.and_then(|s| Entry::from_str(id, &s))
|
||||||
},
|
},
|
||||||
FSFileAbstractionInstance::Absent(ref p) =>
|
FSFileAbstractionInstance::Absent(ref p) =>
|
||||||
(try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
|
(try!(open_file(p).chain_err(|| SEK::FileNotFound)), p.clone()),
|
||||||
};
|
};
|
||||||
*self = FSFileAbstractionInstance::File(file, path);
|
*self = FSFileAbstractionInstance::File(file, path);
|
||||||
if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
|
if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
f.read_to_string(&mut s)
|
f.read_to_string(&mut s)
|
||||||
.map_err_into(SEK::IoError)
|
.chain_err(|| SEK::IoError)
|
||||||
.map(|_| s)
|
.map(|_| s)
|
||||||
.and_then(|s| Entry::from_str(id, &s))
|
.and_then(|s| Entry::from_str(id, &s))
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,18 +84,18 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
|
||||||
// We seek to the beginning of the file since we expect each
|
// We seek to the beginning of the file since we expect each
|
||||||
// access to the file to be in a different context
|
// access to the file to be in a different context
|
||||||
try!(f.seek(SeekFrom::Start(0))
|
try!(f.seek(SeekFrom::Start(0))
|
||||||
.map_err_into(SEK::FileNotCreated));
|
.chain_err(|| SEK::FileNotCreated));
|
||||||
|
|
||||||
try!(f.set_len(buf.len() as u64).map_err_into(SEK::FileNotWritten));
|
try!(f.set_len(buf.len() as u64).chain_err(|| SEK::FileNotWritten));
|
||||||
|
|
||||||
f.write_all(&buf).map_err_into(SEK::FileNotWritten)
|
f.write_all(&buf).chain_err(|| SEK::FileNotWritten)
|
||||||
},
|
},
|
||||||
FSFileAbstractionInstance::Absent(ref p) =>
|
FSFileAbstractionInstance::Absent(ref p) =>
|
||||||
(try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
|
(try!(create_file(p).chain_err(|| SEK::FileNotCreated)), p.clone()),
|
||||||
};
|
};
|
||||||
*self = FSFileAbstractionInstance::File(file, path);
|
*self = FSFileAbstractionInstance::File(file, path);
|
||||||
if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
|
if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
|
||||||
return f.write_all(&buf).map_err_into(SEK::FileNotWritten);
|
return f.write_all(&buf).chain_err(|| SEK::FileNotWritten);
|
||||||
}
|
}
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
@ -117,19 +118,19 @@ impl FSFileAbstraction {
|
||||||
impl FileAbstraction for FSFileAbstraction {
|
impl FileAbstraction for FSFileAbstraction {
|
||||||
|
|
||||||
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
|
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
|
||||||
remove_file(path).map_err_into(SEK::FileNotRemoved)
|
remove_file(path).chain_err(|| SEK::FileNotRemoved)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
||||||
copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
|
copy(from, to).chain_err(|| SEK::FileNotCopied).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
||||||
rename(from, to).map_err_into(SEK::FileNotRenamed)
|
rename(from, to).chain_err(|| SEK::FileNotRenamed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
|
fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
|
||||||
create_dir_all(path).map_err_into(SEK::DirNotCreated)
|
create_dir_all(path).chain_err(|| SEK::DirNotCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
|
fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
|
||||||
|
|
|
@ -17,17 +17,16 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use error::StoreError as SE;
|
use error::StoreError as SE;
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use super::FileAbstraction;
|
use super::FileAbstraction;
|
||||||
use super::FileAbstractionInstance;
|
use super::FileAbstractionInstance;
|
||||||
use super::Drain;
|
use super::Drain;
|
||||||
|
@ -64,16 +63,15 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
|
||||||
fn get_file_content(&mut self, _: StoreId) -> Result<Entry, SE> {
|
fn get_file_content(&mut self, _: StoreId) -> Result<Entry, SE> {
|
||||||
debug!("Getting lazy file: {:?}", self);
|
debug!("Getting lazy file: {:?}", self);
|
||||||
|
|
||||||
match self.fs_abstraction.lock() {
|
self.fs_abstraction
|
||||||
Ok(mut mtx) => {
|
.lock()
|
||||||
|
.map_err(|_| SE::from_kind(SEK::LockError))
|
||||||
|
.and_then(|mut mtx| {
|
||||||
mtx.get_mut()
|
mtx.get_mut()
|
||||||
.get(&self.absent_path)
|
.get(&self.absent_path)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(SEK::FileNotFound.into_error())
|
.ok_or(SE::from_kind(SEK::FileNotFound))
|
||||||
}
|
})
|
||||||
|
|
||||||
Err(_) => Err(SEK::LockError.into_error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
|
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
|
||||||
|
@ -108,7 +106,7 @@ impl InMemoryFileAbstraction {
|
||||||
fn backend_cloned<'a>(&'a self) -> Result<HashMap<PathBuf, Entry>, SE> {
|
fn backend_cloned<'a>(&'a self) -> Result<HashMap<PathBuf, Entry>, SE> {
|
||||||
self.virtual_filesystem
|
self.virtual_filesystem
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|_| SEK::LockError.into_error())
|
.map_err(|_| SE::from_kind(SEK::LockError))
|
||||||
.map(|mtx| mtx.deref().borrow().clone())
|
.map(|mtx| mtx.deref().borrow().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +122,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
||||||
.get_mut()
|
.get_mut()
|
||||||
.remove(path)
|
.remove(path)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.ok_or(SEK::FileNotFound.into_error())
|
.ok_or(SE::from_kind(SEK::FileNotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
|
||||||
|
@ -132,7 +130,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
||||||
let mut mtx = self.backend().lock().expect("Locking Mutex failed");
|
let mut mtx = self.backend().lock().expect("Locking Mutex failed");
|
||||||
let backend = mtx.get_mut();
|
let backend = mtx.get_mut();
|
||||||
|
|
||||||
let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
|
let a = try!(backend.get(from).cloned().ok_or(SE::from_kind(SEK::FileNotFound)));
|
||||||
backend.insert(to.clone(), a);
|
backend.insert(to.clone(), a);
|
||||||
debug!("Copying: {:?} -> {:?} worked", from, to);
|
debug!("Copying: {:?} -> {:?} worked", from, to);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -143,7 +141,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
||||||
let mut mtx = self.backend().lock().expect("Locking Mutex failed");
|
let mut mtx = self.backend().lock().expect("Locking Mutex failed");
|
||||||
let backend = mtx.get_mut();
|
let backend = mtx.get_mut();
|
||||||
|
|
||||||
let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
|
let a = try!(backend.get(from).cloned().ok_or(SE::from_kind(SEK::FileNotFound)));
|
||||||
backend.insert(to.clone(), a);
|
backend.insert(to.clone(), a);
|
||||||
debug!("Renaming: {:?} -> {:?} worked", from, to);
|
debug!("Renaming: {:?} -> {:?} worked", from, to);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -163,7 +161,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
||||||
|
|
||||||
fn fill<'a>(&'a mut self, mut d: Drain) -> Result<(), SE> {
|
fn fill<'a>(&'a mut self, mut d: Drain) -> Result<(), SE> {
|
||||||
debug!("Draining into : {:?}", self);
|
debug!("Draining into : {:?}", self);
|
||||||
let mut mtx = try!(self.backend().lock().map_err(|_| SEK::LockError.into_error()));
|
let mut mtx = try!(self.backend().lock().map_err(|_| SEK::LockError));
|
||||||
let backend = mtx.get_mut();
|
let backend = mtx.get_mut();
|
||||||
|
|
||||||
for (path, element) in d.iter() {
|
for (path, element) in d.iter() {
|
||||||
|
|
|
@ -25,14 +25,13 @@ use serde_json;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
use error::MapErrInto;
|
use error::StoreError as SE;
|
||||||
|
use error::ResultExt;
|
||||||
use super::Mapper;
|
use super::Mapper;
|
||||||
use store::Result;
|
use store::Result;
|
||||||
use store::Entry;
|
use store::Entry;
|
||||||
use storeid::StoreId;
|
use storeid::StoreId;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
struct BackendEntry {
|
struct BackendEntry {
|
||||||
header: serde_json::Value,
|
header: serde_json::Value,
|
||||||
|
@ -43,7 +42,7 @@ impl BackendEntry {
|
||||||
|
|
||||||
fn to_string(self) -> Result<String> {
|
fn to_string(self) -> Result<String> {
|
||||||
toml::to_string(&self.header)
|
toml::to_string(&self.header)
|
||||||
.map_err_into(SEK::IoError)
|
.chain_err(|| SEK::IoError)
|
||||||
.map(|hdr| {
|
.map(|hdr| {
|
||||||
format!("---\n{header}---\n{content}",
|
format!("---\n{header}---\n{content}",
|
||||||
header = hdr,
|
header = hdr,
|
||||||
|
@ -74,16 +73,16 @@ impl Mapper for JsonMapper {
|
||||||
let mut document = {
|
let mut document = {
|
||||||
debug!("Reading Document");
|
debug!("Reading Document");
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
try!(r.read_to_string(&mut s).map_err_into(SEK::IoError));
|
try!(r.read_to_string(&mut s).chain_err(|| SEK::IoError));
|
||||||
debug!("Document = {:?}", s);
|
debug!("Document = {:?}", s);
|
||||||
debug!("Parsing Document");
|
debug!("Parsing Document");
|
||||||
let doc : Document = try!(serde_json::from_str(&s).map_err_into(SEK::IoError));
|
let doc : Document = try!(serde_json::from_str(&s).chain_err(|| SEK::IoError));
|
||||||
debug!("Document = {:?}", doc);
|
debug!("Document = {:?}", doc);
|
||||||
doc
|
doc
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = try!(::semver::Version::parse(&document.version)
|
let _ = try!(::semver::Version::parse(&document.version)
|
||||||
.map_err_into(SEK::VersionError)
|
.chain_err(|| SEK::VersionError)
|
||||||
.and_then(|doc_vers| {
|
.and_then(|doc_vers| {
|
||||||
// safe because cargo does not compile if crate version is not valid
|
// safe because cargo does not compile if crate version is not valid
|
||||||
let crate_version = ::semver::Version::parse(version!()).unwrap();
|
let crate_version = ::semver::Version::parse(version!()).unwrap();
|
||||||
|
@ -93,7 +92,7 @@ impl Mapper for JsonMapper {
|
||||||
crate_vers = crate_version);
|
crate_vers = crate_version);
|
||||||
|
|
||||||
if doc_vers > crate_version {
|
if doc_vers > crate_version {
|
||||||
Err(SEK::VersionError.into_error())
|
Err(SE::from_kind(SEK::VersionError))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -150,9 +149,9 @@ impl Mapper for JsonMapper {
|
||||||
};
|
};
|
||||||
|
|
||||||
serde_json::to_string(&doc)
|
serde_json::to_string(&doc)
|
||||||
.map_err_into(SEK::IoError)
|
.chain_err(|| SEK::IoError)
|
||||||
.and_then(|json| out.write(&json.into_bytes()).map_err_into(SEK::IoError))
|
.and_then(|json| out.write(&json.into_bytes()).chain_err(|| SEK::IoError))
|
||||||
.and_then(|_| out.flush().map_err_into(SEK::IoError))
|
.and_then(|_| out.flush().chain_err(|| SEK::IoError))
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,6 @@ use std::fmt::Debug;
|
||||||
use std::fmt::Error as FmtError;
|
use std::fmt::Error as FmtError;
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
use error::StoreError as SE;
|
use error::StoreError as SE;
|
||||||
use super::FileAbstraction;
|
use super::FileAbstraction;
|
||||||
|
@ -57,11 +55,11 @@ impl<W, M> StdIoFileAbstraction<W, M>
|
||||||
pub fn new<R: Read>(in_stream: &mut R, out_stream: Rc<RefCell<W>>, mapper: M) -> Result<StdIoFileAbstraction<W, M>, SE> {
|
pub fn new<R: Read>(in_stream: &mut R, out_stream: Rc<RefCell<W>>, mapper: M) -> Result<StdIoFileAbstraction<W, M>, SE> {
|
||||||
StdoutFileAbstraction::new(out_stream, mapper)
|
StdoutFileAbstraction::new(out_stream, mapper)
|
||||||
.and_then(|out| {
|
.and_then(|out| {
|
||||||
let fill_res = match out.backend().lock() {
|
let _ = try!(out
|
||||||
Err(_) => Err(SEK::LockError.into_error()),
|
.backend()
|
||||||
Ok(mut mtx) => out.mapper().read_to_fs(in_stream, mtx.get_mut())
|
.lock()
|
||||||
};
|
.map_err(|_| SE::from_kind(SEK::LockError))
|
||||||
let _ = try!(fill_res);
|
.map(|mut mtx| out.mapper().read_to_fs(in_stream, mtx.get_mut())));
|
||||||
|
|
||||||
Ok(StdIoFileAbstraction(out))
|
Ok(StdIoFileAbstraction(out))
|
||||||
})
|
})
|
||||||
|
|
|
@ -31,7 +31,6 @@ use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
use libimagerror::trace::*;
|
use libimagerror::trace::*;
|
||||||
|
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
|
@ -74,7 +73,7 @@ impl<W, M> StdoutFileAbstraction<W, M>
|
||||||
self.mem
|
self.mem
|
||||||
.backend()
|
.backend()
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|_| SEK::LockError.into_error())
|
.map_err(|_| SE::from_kind(SEK::LockError))
|
||||||
.map(|mtx| mtx.deref().borrow().clone())
|
.map(|mtx| mtx.deref().borrow().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +100,7 @@ impl<W, M> Drop for StdoutFileAbstraction<W, M>
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
let fill_res = match self.mem.backend().lock() {
|
let fill_res = match self.mem.backend().lock() {
|
||||||
Err(_) => Err(SEK::LockError.into_error()),
|
Err(_) => Err(SE::from_kind(SEK::LockError)),
|
||||||
Ok(mut mtx) => {
|
Ok(mut mtx) => {
|
||||||
self.mapper.fs_to_write(mtx.get_mut(), self.out.borrow_mut().deref_mut())
|
self.mapper.fs_to_write(mtx.get_mut(), self.out.borrow_mut().deref_mut())
|
||||||
},
|
},
|
||||||
|
@ -142,7 +141,7 @@ impl<W: Write, M: Mapper> FileAbstraction for StdoutFileAbstraction<W, M> {
|
||||||
|
|
||||||
fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
|
fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
|
||||||
debug!("Draining into : {:?}", self);
|
debug!("Draining into : {:?}", self);
|
||||||
let mut mtx = try!(self.backend().lock().map_err(|_| SEK::IoError.into_error()));
|
let mut mtx = try!(self.backend().lock().map_err(|_| SE::from_kind(SEK::IoError)));
|
||||||
let backend = mtx.get_mut();
|
let backend = mtx.get_mut();
|
||||||
|
|
||||||
for (path, element) in d.iter() {
|
for (path, element) in d.iter() {
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -45,8 +47,9 @@ extern crate walkdir;
|
||||||
#[macro_use] extern crate is_match;
|
#[macro_use] extern crate is_match;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
#[macro_use] extern crate serde_derive;
|
#[macro_use] extern crate serde_derive;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
|
|
||||||
#[macro_use] mod util;
|
#[macro_use] mod util;
|
||||||
|
|
|
@ -38,8 +38,8 @@ use glob::glob;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use walkdir::Iter as WalkDirIter;
|
use walkdir::Iter as WalkDirIter;
|
||||||
|
|
||||||
use error::{StoreError as SE, StoreErrorKind as SEK, ParserError, ParserErrorKind};
|
use error::{StoreError as SE, StoreErrorKind as SEK};
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use storeid::{IntoStoreId, StoreId, StoreIdIterator};
|
use storeid::{IntoStoreId, StoreId, StoreIdIterator};
|
||||||
use file_abstraction::FileAbstractionInstance;
|
use file_abstraction::FileAbstractionInstance;
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ pub use file_abstraction::FileAbstraction;
|
||||||
pub use file_abstraction::FSFileAbstraction;
|
pub use file_abstraction::FSFileAbstraction;
|
||||||
pub use file_abstraction::InMemoryFileAbstraction;
|
pub use file_abstraction::InMemoryFileAbstraction;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
use libimagutil::debug_result::*;
|
use libimagutil::debug_result::*;
|
||||||
|
|
||||||
|
@ -147,8 +146,8 @@ impl StoreEntry {
|
||||||
#[cfg(feature = "fs-lock")]
|
#[cfg(feature = "fs-lock")]
|
||||||
{
|
{
|
||||||
try!(open_file(pb.clone())
|
try!(open_file(pb.clone())
|
||||||
.and_then(|f| f.lock_exclusive().map_err_into(SEK::FileError))
|
.and_then(|f| f.lock_exclusive().chain_err(|| SEK::FileError))
|
||||||
.map_err_into(SEK::IoError));
|
.chain_err(|| SEK::IoError));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(StoreEntry {
|
Ok(StoreEntry {
|
||||||
|
@ -168,13 +167,13 @@ impl StoreEntry {
|
||||||
if !self.is_borrowed() {
|
if !self.is_borrowed() {
|
||||||
self.file
|
self.file
|
||||||
.get_file_content(self.id.clone())
|
.get_file_content(self.id.clone())
|
||||||
.or_else(|err| if err.err_type() == SEK::FileNotFound {
|
.or_else(|err| if is_match!(err.kind(), &SEK::FileNotFound) {
|
||||||
Ok(Entry::new(self.id.clone()))
|
Ok(Entry::new(self.id.clone()))
|
||||||
} else {
|
} else {
|
||||||
Err(err)
|
Err(err)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(SE::new(SEK::EntryAlreadyBorrowed, None))
|
Err(SE::from_kind(SEK::EntryAlreadyBorrowed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +181,7 @@ impl StoreEntry {
|
||||||
if self.is_borrowed() {
|
if self.is_borrowed() {
|
||||||
assert_eq!(self.id, entry.location);
|
assert_eq!(self.id, entry.location);
|
||||||
self.file.write_file_content(entry)
|
self.file.write_file_content(entry)
|
||||||
.map_err_into(SEK::FileError)
|
.chain_err(|| SEK::FileError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -195,9 +194,9 @@ impl Drop for StoreEntry {
|
||||||
|
|
||||||
fn drop(self) {
|
fn drop(self) {
|
||||||
self.get_entry()
|
self.get_entry()
|
||||||
.and_then(|entry| open_file(entry.get_location().clone()).map_err_into(SEK::IoError))
|
.and_then(|entry| open_file(entry.get_location().clone()).chain_err(|| SEK::IoError))
|
||||||
.and_then(|f| f.unlock().map_err_into(SEK::FileError))
|
.and_then(|f| f.unlock().chain_err(|| SEK::FileError))
|
||||||
.map_err_into(SEK::IoError)
|
.chain_err(|| SEK::IoError)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -266,7 +265,7 @@ impl Store {
|
||||||
use configuration::*;
|
use configuration::*;
|
||||||
|
|
||||||
debug!("Validating Store configuration");
|
debug!("Validating Store configuration");
|
||||||
let _ = try!(config_is_valid(&store_config).map_err_into(SEK::ConfigurationError));
|
let _ = try!(config_is_valid(&store_config).chain_err(|| SEK::ConfigurationError));
|
||||||
|
|
||||||
debug!("Building new Store object");
|
debug!("Building new Store object");
|
||||||
if !location.exists() {
|
if !location.exists() {
|
||||||
|
@ -274,17 +273,17 @@ impl Store {
|
||||||
warn!("Implicitely creating store directory is denied");
|
warn!("Implicitely creating store directory is denied");
|
||||||
warn!(" -> Either because configuration does not allow it");
|
warn!(" -> Either because configuration does not allow it");
|
||||||
warn!(" -> or because there is no configuration");
|
warn!(" -> or because there is no configuration");
|
||||||
return Err(SEK::CreateStoreDirDenied.into_error())
|
return Err(SE::from_kind(SEK::CreateStoreDirDenied))
|
||||||
.map_err_into(SEK::FileError)
|
.chain_err(|| SEK::FileError)
|
||||||
.map_err_into(SEK::IoError);
|
.chain_err(|| SEK::IoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(backend.create_dir_all(&location)
|
try!(backend.create_dir_all(&location)
|
||||||
.map_err_into(SEK::StorePathCreate)
|
.chain_err(|| SEK::StorePathCreate)
|
||||||
.map_dbg_err_str("Failed"));
|
.map_dbg_err_str("Failed"));
|
||||||
} else if location.is_file() {
|
} else if location.is_file() {
|
||||||
debug!("Store path exists as file");
|
debug!("Store path exists as file");
|
||||||
return Err(SEK::StorePathExists.into_error());
|
return Err(SE::from_kind(SEK::StorePathExists));
|
||||||
}
|
}
|
||||||
|
|
||||||
let store = Store {
|
let store = Store {
|
||||||
|
@ -408,13 +407,13 @@ impl Store {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut hsmap = match self.entries.write() {
|
let mut hsmap = match self.entries.write() {
|
||||||
Err(_) => return Err(SEK::LockPoisoned.into_error()).map_err_into(SEK::CreateCallError),
|
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)).chain_err(|| SEK::CreateCallError),
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
};
|
};
|
||||||
|
|
||||||
if hsmap.contains_key(&id) {
|
if hsmap.contains_key(&id) {
|
||||||
debug!("Cannot create, internal cache already contains: '{}'", id);
|
debug!("Cannot create, internal cache already contains: '{}'", id);
|
||||||
return Err(SEK::EntryAlreadyExists.into_error()).map_err_into(SEK::CreateCallError);
|
return Err(SE::from_kind(SEK::EntryAlreadyExists)).chain_err(|| SEK::CreateCallError);
|
||||||
}
|
}
|
||||||
hsmap.insert(id.clone(), {
|
hsmap.insert(id.clone(), {
|
||||||
debug!("Creating: '{}'", id);
|
debug!("Creating: '{}'", id);
|
||||||
|
@ -449,7 +448,7 @@ impl Store {
|
||||||
let entry = try!({
|
let entry = try!({
|
||||||
self.entries
|
self.entries
|
||||||
.write()
|
.write()
|
||||||
.map_err(|_| SE::new(SEK::LockPoisoned, None))
|
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||||
.and_then(|mut es| {
|
.and_then(|mut es| {
|
||||||
let new_se = try!(StoreEntry::new(id.clone(), &self.backend));
|
let new_se = try!(StoreEntry::new(id.clone(), &self.backend));
|
||||||
let se = es.entry(id.clone()).or_insert(new_se);
|
let se = es.entry(id.clone()).or_insert(new_se);
|
||||||
|
@ -457,7 +456,7 @@ impl Store {
|
||||||
se.status = StoreEntryStatus::Borrowed;
|
se.status = StoreEntryStatus::Borrowed;
|
||||||
entry
|
entry
|
||||||
})
|
})
|
||||||
.map_err_into(SEK::RetrieveCallError)
|
.chain_err(|| SEK::RetrieveCallError)
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("Constructing FileLockEntry: '{}'", id);
|
debug!("Constructing FileLockEntry: '{}'", id);
|
||||||
|
@ -482,8 +481,8 @@ impl Store {
|
||||||
let exists = try!(id.exists()) || try!(self.entries
|
let exists = try!(id.exists()) || try!(self.entries
|
||||||
.read()
|
.read()
|
||||||
.map(|map| map.contains_key(&id))
|
.map(|map| map.contains_key(&id))
|
||||||
.map_err(|_| SE::new(SEK::LockPoisoned, None))
|
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||||
.map_err_into(SEK::GetCallError)
|
.chain_err(|| SEK::GetCallError)
|
||||||
);
|
);
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
|
@ -491,7 +490,7 @@ impl Store {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.retrieve(id).map(Some).map_err_into(SEK::GetCallError)
|
self.retrieve(id).map(Some).chain_err(|| SEK::GetCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all StoreIds for one module name
|
/// Iterate over all StoreIds for one module name
|
||||||
|
@ -512,15 +511,15 @@ impl Store {
|
||||||
debug!("Retrieving for module: '{}'", mod_name);
|
debug!("Retrieving for module: '{}'", mod_name);
|
||||||
|
|
||||||
path.to_str()
|
path.to_str()
|
||||||
.ok_or(SE::new(SEK::EncodingError, None))
|
.ok_or(SE::from_kind(SEK::EncodingError))
|
||||||
.and_then(|path| {
|
.and_then(|path| {
|
||||||
let path = [ path, "/**/*" ].join("");
|
let path = [ path, "/**/*" ].join("");
|
||||||
debug!("glob()ing with '{}'", path);
|
debug!("glob()ing with '{}'", path);
|
||||||
glob(&path[..]).map_err_into(SEK::GlobError)
|
glob(&path[..]).chain_err(|| SEK::GlobError)
|
||||||
})
|
})
|
||||||
.map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into())
|
.map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into())
|
||||||
.map_err_into(SEK::GlobError)
|
.chain_err(|| SEK::GlobError)
|
||||||
.map_err_into(SEK::RetrieveForModuleCallError)
|
.chain_err(|| SEK::RetrieveForModuleCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk the store tree for the module
|
/// Walk the store tree for the module
|
||||||
|
@ -538,7 +537,7 @@ impl Store {
|
||||||
///
|
///
|
||||||
pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> {
|
pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> {
|
||||||
debug!("Updating FileLockEntry at '{}'", entry.get_location());
|
debug!("Updating FileLockEntry at '{}'", entry.get_location());
|
||||||
self._update(entry, false).map_err_into(SEK::UpdateCallError)
|
self._update(entry, false).chain_err(|| SEK::UpdateCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal method to write to the filesystem store.
|
/// Internal method to write to the filesystem store.
|
||||||
|
@ -560,11 +559,11 @@ impl Store {
|
||||||
///
|
///
|
||||||
fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
|
fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
|
||||||
let mut hsmap = match self.entries.write() {
|
let mut hsmap = match self.entries.write() {
|
||||||
Err(_) => return Err(SE::new(SEK::LockPoisoned, None)),
|
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
};
|
};
|
||||||
|
|
||||||
let se = try!(hsmap.get_mut(&entry.location).ok_or(SE::new(SEK::IdNotFound, None)));
|
let se = try!(hsmap.get_mut(&entry.location).ok_or(SE::from_kind(SEK::IdNotFound)));
|
||||||
|
|
||||||
assert!(se.is_borrowed(), "Tried to update a non borrowed entry.");
|
assert!(se.is_borrowed(), "Tried to update a non borrowed entry.");
|
||||||
|
|
||||||
|
@ -597,15 +596,15 @@ impl Store {
|
||||||
debug!("Retrieving copy of '{}'", id);
|
debug!("Retrieving copy of '{}'", id);
|
||||||
let entries = match self.entries.write() {
|
let entries = match self.entries.write() {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(SE::new(SEK::LockPoisoned, None))
|
return Err(SE::from_kind(SEK::LockPoisoned))
|
||||||
.map_err_into(SEK::RetrieveCopyCallError);
|
.chain_err(|| SEK::RetrieveCopyCallError);
|
||||||
},
|
},
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
};
|
};
|
||||||
|
|
||||||
// if the entry is currently modified by the user, we cannot drop it
|
// if the entry is currently modified by the user, we cannot drop it
|
||||||
if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) {
|
if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) {
|
||||||
return Err(SE::new(SEK::IdLocked, None)).map_err_into(SEK::RetrieveCopyCallError);
|
return Err(SE::from_kind(SEK::IdLocked)).chain_err(|| SEK::RetrieveCopyCallError);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(StoreEntry::new(id, &self.backend)).get_entry()
|
try!(StoreEntry::new(id, &self.backend)).get_entry()
|
||||||
|
@ -629,18 +628,18 @@ impl Store {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut entries = match self.entries.write() {
|
let mut entries = match self.entries.write() {
|
||||||
Err(_) => return Err(SE::new(SEK::LockPoisoned, None))
|
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned))
|
||||||
.map_err_into(SEK::DeleteCallError),
|
.chain_err(|| SEK::DeleteCallError),
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
};
|
};
|
||||||
|
|
||||||
// if the entry is currently modified by the user, we cannot drop it
|
// if the entry is currently modified by the user, we cannot drop it
|
||||||
match entries.get(&id) {
|
match entries.get(&id) {
|
||||||
None => {
|
None => {
|
||||||
return Err(SEK::FileNotFound.into_error()).map_err_into(SEK::DeleteCallError)
|
return Err(SE::from_kind(SEK::FileNotFound)).chain_err(|| SEK::DeleteCallError)
|
||||||
},
|
},
|
||||||
Some(e) => if e.is_borrowed() {
|
Some(e) => if e.is_borrowed() {
|
||||||
return Err(SE::new(SEK::IdLocked, None)).map_err_into(SEK::DeleteCallError)
|
return Err(SE::from_kind(SEK::IdLocked)).chain_err(|| SEK::DeleteCallError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,8 +647,9 @@ impl Store {
|
||||||
entries.remove(&id);
|
entries.remove(&id);
|
||||||
let pb = try!(id.clone().with_base(self.path().clone()).into_pathbuf());
|
let pb = try!(id.clone().with_base(self.path().clone()).into_pathbuf());
|
||||||
if let Err(e) = self.backend.remove_file(&pb) {
|
if let Err(e) = self.backend.remove_file(&pb) {
|
||||||
return Err(SEK::FileError.into_error_with_cause(Box::new(e)))
|
return Err(e)
|
||||||
.map_err_into(SEK::DeleteCallError);
|
.chain_err(|| SEK::FileError)
|
||||||
|
.chain_err(|| SEK::DeleteCallError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,12 +677,12 @@ impl Store {
|
||||||
let hsmap = try!(
|
let hsmap = try!(
|
||||||
self.entries
|
self.entries
|
||||||
.write()
|
.write()
|
||||||
.map_err(|_| SEK::LockPoisoned.into_error())
|
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
|
||||||
.map_err_into(SEK::MoveCallError)
|
.chain_err(|| SEK::MoveCallError)
|
||||||
);
|
);
|
||||||
|
|
||||||
if hsmap.contains_key(&new_id) {
|
if hsmap.contains_key(&new_id) {
|
||||||
return Err(SEK::EntryAlreadyExists.into_error()).map_err_into(SEK::MoveCallError)
|
return Err(SE::from_kind(SEK::EntryAlreadyExists)).chain_err(|| SEK::MoveCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_id = entry.get_location().clone();
|
let old_id = entry.get_location().clone();
|
||||||
|
@ -698,8 +698,8 @@ impl Store {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err_into(SEK::FileError)
|
.chain_err(|| SEK::FileError)
|
||||||
.map_err_into(SEK::MoveCallError)
|
.chain_err(|| SEK::MoveCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move an entry without loading
|
/// Move an entry without loading
|
||||||
|
@ -743,26 +743,26 @@ impl Store {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut hsmap = match self.entries.write() {
|
let mut hsmap = match self.entries.write() {
|
||||||
Err(_) => return Err(SE::new(SEK::LockPoisoned, None)),
|
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
};
|
};
|
||||||
|
|
||||||
if hsmap.contains_key(&new_id) {
|
if hsmap.contains_key(&new_id) {
|
||||||
return Err(SEK::EntryAlreadyExists.into_error());
|
return Err(SE::from_kind(SEK::EntryAlreadyExists));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we do not have an entry here, we fail in `FileAbstraction::rename()` below.
|
// if we do not have an entry here, we fail in `FileAbstraction::rename()` below.
|
||||||
// if we have one, but it is borrowed, we really should not rename it, as this might
|
// if we have one, but it is borrowed, we really should not rename it, as this might
|
||||||
// lead to strange errors
|
// lead to strange errors
|
||||||
if hsmap.get(&old_id).map(|e| e.is_borrowed()).unwrap_or(false) {
|
if hsmap.get(&old_id).map(|e| e.is_borrowed()).unwrap_or(false) {
|
||||||
return Err(SEK::EntryAlreadyBorrowed.into_error());
|
return Err(SE::from_kind(SEK::EntryAlreadyBorrowed));
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_id_pb = try!(old_id.clone().with_base(self.path().clone()).into_pathbuf());
|
let old_id_pb = try!(old_id.clone().with_base(self.path().clone()).into_pathbuf());
|
||||||
let new_id_pb = try!(new_id.clone().with_base(self.path().clone()).into_pathbuf());
|
let new_id_pb = try!(new_id.clone().with_base(self.path().clone()).into_pathbuf());
|
||||||
|
|
||||||
match self.backend.rename(&old_id_pb, &new_id_pb) {
|
match self.backend.rename(&old_id_pb, &new_id_pb) {
|
||||||
Err(e) => return Err(SEK::EntryRenameError.into_error_with_cause(Box::new(e))),
|
Err(e) => return Err(e).chain_err(|| SEK::EntryRenameError),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
debug!("Rename worked on filesystem");
|
debug!("Rename worked on filesystem");
|
||||||
|
|
||||||
|
@ -1035,7 +1035,7 @@ mod glob_store_iter {
|
||||||
use storeid::StoreIdIterator;
|
use storeid::StoreIdIterator;
|
||||||
|
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
|
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
|
|
||||||
|
@ -1088,7 +1088,7 @@ mod glob_store_iter {
|
||||||
fn next(&mut self) -> Option<StoreId> {
|
fn next(&mut self) -> Option<StoreId> {
|
||||||
while let Some(o) = self.paths.next() {
|
while let Some(o) = self.paths.next() {
|
||||||
debug!("GlobStoreIdIterator::next() => {:?}", o);
|
debug!("GlobStoreIdIterator::next() => {:?}", o);
|
||||||
match o.map_err_into(SEK::StoreIdHandlingError) {
|
match o.chain_err(|| SEK::StoreIdHandlingError) {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
if path.exists() && path.is_file() {
|
if path.exists() && path.is_file() {
|
||||||
return match StoreId::from_full_path(&self.store_path, path) {
|
return match StoreId::from_full_path(&self.store_path, path) {
|
||||||
|
@ -1121,7 +1121,7 @@ mod glob_store_iter {
|
||||||
/// top-level Value::Table, but not on intermediate tables.
|
/// top-level Value::Table, but not on intermediate tables.
|
||||||
pub trait Header {
|
pub trait Header {
|
||||||
fn verify(&self) -> Result<()>;
|
fn verify(&self) -> Result<()>;
|
||||||
fn parse(s: &str) -> RResult<Value, ParserError>;
|
fn parse(s: &str) -> Result<Value>;
|
||||||
fn default_header() -> Value;
|
fn default_header() -> Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,15 +1130,15 @@ impl Header for Value {
|
||||||
fn verify(&self) -> Result<()> {
|
fn verify(&self) -> Result<()> {
|
||||||
match *self {
|
match *self {
|
||||||
Value::Table(ref t) => verify_header(&t),
|
Value::Table(ref t) => verify_header(&t),
|
||||||
_ => Err(SE::new(SEK::HeaderTypeFailure, None)),
|
_ => Err(SE::from_kind(SEK::HeaderTypeFailure)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(s: &str) -> RResult<Value, ParserError> {
|
fn parse(s: &str) -> Result<Value> {
|
||||||
use toml::de::from_str;
|
use toml::de::from_str;
|
||||||
|
|
||||||
from_str(s)
|
from_str(s)
|
||||||
.map_err(|_| ParserErrorKind::TOMLParserErrors.into())
|
.chain_err(|| SEK::TOMLParserErrors)
|
||||||
.and_then(verify_header_consistency)
|
.and_then(verify_header_consistency)
|
||||||
.map(Value::Table)
|
.map(Value::Table)
|
||||||
}
|
}
|
||||||
|
@ -1160,21 +1160,18 @@ impl Header for Value {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_header_consistency(t: Table) -> RResult<Table, ParserError> {
|
fn verify_header_consistency(t: Table) -> Result<Table> {
|
||||||
verify_header(&t)
|
verify_header(&t).chain_err(|| SEK::HeaderInconsistency).map(|_| t)
|
||||||
.map_err(Box::new)
|
|
||||||
.map_err(|e| ParserErrorKind::HeaderInconsistency.into_error_with_cause(e))
|
|
||||||
.map(|_| t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_header(t: &Table) -> Result<()> {
|
fn verify_header(t: &Table) -> Result<()> {
|
||||||
if !has_main_section(t) {
|
if !has_main_section(t) {
|
||||||
Err(SE::from(ParserErrorKind::MissingMainSection.into_error()))
|
Err(SE::from_kind(SEK::MissingMainSection))
|
||||||
} else if !has_imag_version_in_main_section(t) {
|
} else if !has_imag_version_in_main_section(t) {
|
||||||
Err(SE::from(ParserErrorKind::MissingVersionInfo.into_error()))
|
Err(SE::from_kind(SEK::MissingVersionInfo))
|
||||||
} else if !has_only_tables(t) {
|
} else if !has_only_tables(t) {
|
||||||
debug!("Could not verify that it only has tables in its base table");
|
debug!("Could not verify that it only has tables in its base table");
|
||||||
Err(SE::from(ParserErrorKind::NonTableInBaseTable.into_error()))
|
Err(SE::from_kind(SEK::NonTableInBaseTable))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1518,7 +1515,7 @@ mod store_tests {
|
||||||
for n in 1..100 {
|
for n in 1..100 {
|
||||||
let s = format!("test-{}", n % 50);
|
let s = format!("test-{}", n % 50);
|
||||||
store.create(PathBuf::from(s.clone()))
|
store.create(PathBuf::from(s.clone()))
|
||||||
.map_err(|e| assert!(is_match!(e.err_type(), SEK::CreateCallError) && n >= 50))
|
.map_err(|e| assert!(is_match!(e.kind(), &SEK::CreateCallError) && n >= 50))
|
||||||
.ok()
|
.ok()
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
assert!(entry.verify().is_ok());
|
assert!(entry.verify().is_ok());
|
||||||
|
|
|
@ -26,10 +26,9 @@ use std::fmt::Error as FmtError;
|
||||||
use std::result::Result as RResult;
|
use std::result::Result as RResult;
|
||||||
use std::path::Components;
|
use std::path::Components;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
use error::MapErrInto;
|
use error::StoreError as SE;
|
||||||
|
use error::ResultExt;
|
||||||
use store::Result;
|
use store::Result;
|
||||||
|
|
||||||
/// The Index into the Store
|
/// The Index into the Store
|
||||||
|
@ -61,7 +60,7 @@ impl StoreId {
|
||||||
where D: Deref<Target = Path>
|
where D: Deref<Target = Path>
|
||||||
{
|
{
|
||||||
let p = try!(
|
let p = try!(
|
||||||
full_path.strip_prefix(store_part).map_err_into(SEK::StoreIdBuildFromFullPathError)
|
full_path.strip_prefix(store_part).chain_err(|| SEK::StoreIdBuildFromFullPathError)
|
||||||
);
|
);
|
||||||
StoreId::new(Some(store_part.clone()), PathBuf::from(p))
|
StoreId::new(Some(store_part.clone()), PathBuf::from(p))
|
||||||
}
|
}
|
||||||
|
@ -69,7 +68,7 @@ impl StoreId {
|
||||||
pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
|
pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
|
||||||
debug!("Trying to get a new baseless id from: {:?}", id);
|
debug!("Trying to get a new baseless id from: {:?}", id);
|
||||||
if id.is_absolute() {
|
if id.is_absolute() {
|
||||||
Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
|
Err(SE::from_kind(SEK::StoreIdLocalPartAbsoluteError))
|
||||||
} else {
|
} else {
|
||||||
Ok(StoreId {
|
Ok(StoreId {
|
||||||
base: None,
|
base: None,
|
||||||
|
@ -91,7 +90,7 @@ impl StoreId {
|
||||||
/// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
|
/// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
|
||||||
/// specified.
|
/// specified.
|
||||||
pub fn into_pathbuf(self) -> Result<PathBuf> {
|
pub fn into_pathbuf(self) -> Result<PathBuf> {
|
||||||
let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError.into_error()));
|
let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError));
|
||||||
base.push(self.id);
|
base.push(self.id);
|
||||||
Ok(base)
|
Ok(base)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +107,7 @@ impl StoreId {
|
||||||
.unwrap_or_else(|| self.id.clone())
|
.unwrap_or_else(|| self.id.clone())
|
||||||
.to_str()
|
.to_str()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.ok_or(SEK::StoreIdHandlingError.into_error())
|
.ok_or(SE::from_kind(SEK::StoreIdHandlingError))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the components of the `id` part of the StoreId object.
|
/// Returns the components of the `id` part of the StoreId object.
|
||||||
|
@ -347,7 +346,7 @@ mod test {
|
||||||
let pb = id.unwrap().into_pathbuf();
|
let pb = id.unwrap().into_pathbuf();
|
||||||
assert!(pb.is_err());
|
assert!(pb.is_err());
|
||||||
|
|
||||||
assert_eq!(pb.unwrap_err().err_type(), SEK::StoreIdHasNoBaseError);
|
assert!(is_match!(pb.unwrap_err().kind(), &SEK::StoreIdHasNoBaseError));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -20,11 +20,10 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use store::Result;
|
use store::Result;
|
||||||
use store::Header;
|
use store::Header;
|
||||||
use error::StoreErrorKind as SEK;
|
use error::StoreErrorKind as SEK;
|
||||||
|
use error::StoreError as SE;
|
||||||
|
|
||||||
#[cfg(feature = "early-panic")]
|
#[cfg(feature = "early-panic")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -54,12 +53,12 @@ pub fn entry_buffer_to_header_content(buf: &str) -> Result<(Value, String)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let matches = match RE.captures(buf) {
|
let matches = match RE.captures(buf) {
|
||||||
None => return Err(SEK::MalformedEntry.into_error()),
|
None => return Err(SE::from_kind(SEK::MalformedEntry)),
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
};
|
};
|
||||||
|
|
||||||
let header = match matches.name("header") {
|
let header = match matches.name("header") {
|
||||||
None => return Err(SEK::MalformedEntry.into_error()),
|
None => return Err(SE::from_kind(SEK::MalformedEntry)),
|
||||||
Some(s) => s
|
Some(s) => s
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ homepage = "http://imag-pim.org"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
url = "1.2"
|
url = "1.2"
|
||||||
regex = "0.1"
|
regex = "0.1"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -29,8 +29,9 @@ use std::ops::DerefMut;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use error::BookmarkErrorKind as BEK;
|
use error::BookmarkErrorKind as BEK;
|
||||||
use error::MapErrInto;
|
use error::BookmarkError as BE;
|
||||||
use result::Result;
|
use error::ResultExt;
|
||||||
|
use error::Result;
|
||||||
use module_path::ModuleEntryPath;
|
use module_path::ModuleEntryPath;
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
@ -40,7 +41,6 @@ use libimagentrylink::external::ExternalLinker;
|
||||||
use libimagentrylink::external::iter::UrlIter;
|
use libimagentrylink::external::iter::UrlIter;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::internal::InternalLinker;
|
||||||
use libimagentrylink::internal::Link as StoreLink;
|
use libimagentrylink::internal::Link as StoreLink;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use link::Link;
|
use link::Link;
|
||||||
|
|
||||||
|
@ -81,17 +81,17 @@ impl<'a> BookmarkCollection<'a> {
|
||||||
store: store,
|
store: store,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err_into(BEK::StoreReadError)
|
.chain_err(|| BEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
|
pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
|
||||||
ModuleEntryPath::new(name)
|
ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| store.get(id))
|
.and_then(|id| store.get(id))
|
||||||
.map_err_into(BEK::StoreReadError)
|
.chain_err(|| BEK::StoreReadError)
|
||||||
.and_then(|fle| {
|
.and_then(|fle| {
|
||||||
match fle {
|
match fle {
|
||||||
None => Err(BEK::CollectionNotFound.into_error()),
|
None => Err(BE::from_kind(BEK::CollectionNotFound)),
|
||||||
Some(e) => Ok(BookmarkCollection {
|
Some(e) => Ok(BookmarkCollection {
|
||||||
fle: e,
|
fle: e,
|
||||||
store: store,
|
store: store,
|
||||||
|
@ -104,11 +104,11 @@ impl<'a> BookmarkCollection<'a> {
|
||||||
ModuleEntryPath::new(name)
|
ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| store.delete(id))
|
.and_then(|id| store.delete(id))
|
||||||
.map_err_into(BEK::StoreReadError)
|
.chain_err(|| BEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn links(&self) -> Result<UrlIter> {
|
pub fn links(&self) -> Result<UrlIter> {
|
||||||
self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
|
self.fle.get_external_links(&self.store).chain_err(|| BEK::LinkError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
|
pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
|
||||||
|
@ -117,22 +117,22 @@ impl<'a> BookmarkCollection<'a> {
|
||||||
self.fle
|
self.fle
|
||||||
.get_internal_links()
|
.get_internal_links()
|
||||||
.map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
|
.map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
|
||||||
.map_err_into(BEK::StoreReadError)
|
.chain_err(|| BEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_link(&mut self, l: Link) -> Result<()> {
|
pub fn add_link(&mut self, l: Link) -> Result<()> {
|
||||||
use link::IntoUrl;
|
use link::IntoUrl;
|
||||||
|
|
||||||
l.into_url()
|
l.into_url()
|
||||||
.and_then(|url| self.add_external_link(self.store, url).map_err_into(BEK::LinkingError))
|
.and_then(|url| self.add_external_link(self.store, url).chain_err(|| BEK::LinkingError))
|
||||||
.map_err_into(BEK::LinkError)
|
.chain_err(|| BEK::LinkError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_links_matching(&self, r: Regex) -> Result<LinksMatchingRegexIter<'a>> {
|
pub fn get_links_matching(&self, r: Regex) -> Result<LinksMatchingRegexIter<'a>> {
|
||||||
use self::iter::IntoLinksMatchingRegexIter;
|
use self::iter::IntoLinksMatchingRegexIter;
|
||||||
|
|
||||||
self.get_external_links(self.store)
|
self.get_external_links(self.store)
|
||||||
.map_err_into(BEK::LinkError)
|
.chain_err(|| BEK::LinkError)
|
||||||
.map(|iter| iter.matching_regex(r))
|
.map(|iter| iter.matching_regex(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,17 +141,17 @@ impl<'a> BookmarkCollection<'a> {
|
||||||
|
|
||||||
l.into_url()
|
l.into_url()
|
||||||
.and_then(|url| {
|
.and_then(|url| {
|
||||||
self.remove_external_link(self.store, url).map_err_into(BEK::LinkingError)
|
self.remove_external_link(self.store, url).chain_err(|| BEK::LinkingError)
|
||||||
})
|
})
|
||||||
.map_err_into(BEK::LinkError)
|
.chain_err(|| BEK::LinkError)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod iter {
|
pub mod iter {
|
||||||
use link::Link;
|
use link::Link;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::{MapErrInto, BookmarkErrorKind as BEK};
|
use error::{ResultExt, BookmarkErrorKind as BEK};
|
||||||
|
|
||||||
pub struct LinkIter<I>(I)
|
pub struct LinkIter<I>(I)
|
||||||
where I: Iterator<Item = Link>;
|
where I: Iterator<Item = Link>;
|
||||||
|
@ -194,7 +194,7 @@ pub mod iter {
|
||||||
loop {
|
loop {
|
||||||
let n = match self.0.next() {
|
let n = match self.0.next() {
|
||||||
Some(Ok(n)) => n,
|
Some(Ok(n)) => n,
|
||||||
Some(Err(e)) => return Some(Err(e).map_err_into(BEK::LinkError)),
|
Some(Err(e)) => return Some(Err(e).chain_err(|| BEK::LinkError)),
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,37 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(BookmarkError, BookmarkErrorKind,
|
types {
|
||||||
StoreReadError => "Store read error",
|
BookmarkError, BookmarkErrorKind, ResultExt, Result;
|
||||||
LinkError => "Link error",
|
}
|
||||||
LinkParsingError => "Link parsing error",
|
|
||||||
LinkingError => "Error while linking",
|
|
||||||
CollectionNotFound => "Link-Collection not found"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::BookmarkError;
|
errors {
|
||||||
pub use self::error::BookmarkErrorKind;
|
StoreReadError {
|
||||||
pub use self::error::MapErrInto;
|
description("Store read error")
|
||||||
|
display("Store read error")
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkError {
|
||||||
|
description("Link error")
|
||||||
|
display("Link error")
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -35,9 +37,10 @@
|
||||||
|
|
||||||
extern crate url;
|
extern crate url;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
#[macro_use] extern crate libimagstore;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagentrylink;
|
extern crate libimagentrylink;
|
||||||
|
|
||||||
module_entry_path_mod!("bookmark");
|
module_entry_path_mod!("bookmark");
|
||||||
|
@ -45,4 +48,3 @@ module_entry_path_mod!("bookmark");
|
||||||
pub mod collection;
|
pub mod collection;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod link;
|
pub mod link;
|
||||||
pub mod result;
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use result::Result;
|
use error::Result;
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -67,9 +67,9 @@ impl IntoUrl for Link {
|
||||||
|
|
||||||
fn into_url(self) -> Result<Url> {
|
fn into_url(self) -> Result<Url> {
|
||||||
use error::BookmarkErrorKind as BEK;
|
use error::BookmarkErrorKind as BEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
|
|
||||||
Url::parse(&self[..]).map_err_into(BEK::LinkParsingError)
|
Url::parse(&self[..]).chain_err(|| BEK::LinkParsingError)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::BookmarkError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, BookmarkError>;
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ homepage = "http://imag-pim.org"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
toml = "0.4.*"
|
toml = "0.4.*"
|
||||||
toml-query = "0.3.*"
|
toml-query = "0.3.*"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -32,13 +32,12 @@ use libimagstore::storeid::StoreIdIterator;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use module_path::ModuleEntryPath;
|
use module_path::ModuleEntryPath;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::CounterError as CE;
|
use error::CounterError as CE;
|
||||||
use error::CounterErrorKind as CEK;
|
use error::CounterErrorKind as CEK;
|
||||||
use error::error::MapErrInto;
|
use error::ResultExt;
|
||||||
|
|
||||||
pub type CounterName = String;
|
pub type CounterName = String;
|
||||||
|
|
||||||
|
@ -71,25 +70,25 @@ impl<'a> Counter<'a> {
|
||||||
let fle = {
|
let fle = {
|
||||||
let id = try!(ModuleEntryPath::new(name.clone())
|
let id = try!(ModuleEntryPath::new(name.clone())
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map_err_into(CEK::StoreWriteError));
|
.chain_err(|| CEK::StoreWriteError));
|
||||||
let mut lockentry = try!(store.create(id).map_err_into(CEK::StoreWriteError));
|
let mut lockentry = try!(store.create(id).chain_err(|| CEK::StoreWriteError));
|
||||||
|
|
||||||
{
|
{
|
||||||
let entry = lockentry.deref_mut();
|
let entry = lockentry.deref_mut();
|
||||||
let header = entry.get_header_mut();
|
let header = entry.get_header_mut();
|
||||||
let setres = header.set(&String::from("counter"), Value::Table(BTreeMap::new()));
|
let setres = header.set(&String::from("counter"), Value::Table(BTreeMap::new()));
|
||||||
if setres.is_err() {
|
if setres.is_err() {
|
||||||
return Err(CEK::StoreWriteError.into_error());
|
return Err(CE::from_kind(CEK::StoreWriteError));
|
||||||
}
|
}
|
||||||
|
|
||||||
let setres = header.set(&String::from("counter.name"), Value::String(name));
|
let setres = header.set(&String::from("counter.name"), Value::String(name));
|
||||||
if setres.is_err() {
|
if setres.is_err() {
|
||||||
return Err(CEK::StoreWriteError.into_error())
|
return Err(CE::from_kind(CEK::StoreWriteError))
|
||||||
}
|
}
|
||||||
|
|
||||||
let setres = header.set(&String::from("counter.value"), Value::Integer(init));
|
let setres = header.set(&String::from("counter.value"), Value::Integer(init));
|
||||||
if setres.is_err() {
|
if setres.is_err() {
|
||||||
return Err(CEK::StoreWriteError.into_error())
|
return Err(CE::from_kind(CEK::StoreWriteError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +106,7 @@ impl<'a> Counter<'a> {
|
||||||
let setres = header.set(&String::from("counter.unit"), Value::String(u.0));
|
let setres = header.set(&String::from("counter.unit"), Value::String(u.0));
|
||||||
if setres.is_err() {
|
if setres.is_err() {
|
||||||
self.unit = None;
|
self.unit = None;
|
||||||
return Err(CEK::StoreWriteError.into_error())
|
return Err(CE::from_kind(CEK::StoreWriteError))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
@ -116,26 +115,26 @@ impl<'a> Counter<'a> {
|
||||||
pub fn inc(&mut self) -> Result<()> {
|
pub fn inc(&mut self) -> Result<()> {
|
||||||
let header = self.fle.deref_mut().get_header_mut();
|
let header = self.fle.deref_mut().get_header_mut();
|
||||||
let query = String::from("counter.value");
|
let query = String::from("counter.value");
|
||||||
match try!(header.read(&query).map_err_into(CEK::StoreReadError)) {
|
match try!(header.read(&query).chain_err(|| CEK::StoreReadError)) {
|
||||||
Some(&Value::Integer(i)) => {
|
Some(&Value::Integer(i)) => {
|
||||||
header.set(&query, Value::Integer(i + 1))
|
header.set(&query, Value::Integer(i + 1))
|
||||||
.map_err_into(CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
},
|
},
|
||||||
_ => Err(CE::new(CEK::StoreReadError, None)),
|
_ => Err(CE::from_kind(CEK::StoreReadError)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dec(&mut self) -> Result<()> {
|
pub fn dec(&mut self) -> Result<()> {
|
||||||
let header = self.fle.deref_mut().get_header_mut();
|
let header = self.fle.deref_mut().get_header_mut();
|
||||||
let query = String::from("counter.value");
|
let query = String::from("counter.value");
|
||||||
match try!(header.read(&query).map_err_into(CEK::StoreReadError)) {
|
match try!(header.read(&query).chain_err(|| CEK::StoreReadError)) {
|
||||||
Some(&Value::Integer(i)) => {
|
Some(&Value::Integer(i)) => {
|
||||||
header.set(&query, Value::Integer(i - 1))
|
header.set(&query, Value::Integer(i - 1))
|
||||||
.map_err_into(CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
},
|
},
|
||||||
_ => Err(CE::new(CEK::StoreReadError, None)),
|
_ => Err(CE::from_kind(CEK::StoreReadError)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,23 +147,23 @@ impl<'a> Counter<'a> {
|
||||||
.deref_mut()
|
.deref_mut()
|
||||||
.get_header_mut()
|
.get_header_mut()
|
||||||
.set(&String::from("counter.value"), Value::Integer(v))
|
.set(&String::from("counter.value"), Value::Integer(v))
|
||||||
.map_err_into(CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> Result<CounterName> {
|
pub fn name(&self) -> Result<CounterName> {
|
||||||
self.read_header_at("counter.name", |v| match v {
|
self.read_header_at("counter.name", |v| match v {
|
||||||
Some(&Value::String(ref s)) => Ok(s.clone()),
|
Some(&Value::String(ref s)) => Ok(s.clone()),
|
||||||
Some(_) => Err(CEK::HeaderTypeError.into_error()),
|
Some(_) => Err(CE::from_kind(CEK::HeaderTypeError)),
|
||||||
_ => Err(CEK::StoreReadError.into_error()),
|
_ => Err(CE::from_kind(CEK::StoreReadError)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> Result<i64> {
|
pub fn value(&self) -> Result<i64> {
|
||||||
self.read_header_at("counter.value", |v| match v {
|
self.read_header_at("counter.value", |v| match v {
|
||||||
Some(&Value::Integer(i)) => Ok(i),
|
Some(&Value::Integer(i)) => Ok(i),
|
||||||
Some(_) => Err(CEK::HeaderTypeError.into_error()),
|
Some(_) => Err(CE::from_kind(CEK::HeaderTypeError)),
|
||||||
_ => Err(CEK::StoreReadError.into_error()),
|
_ => Err(CE::from_kind(CEK::StoreReadError)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +174,8 @@ impl<'a> Counter<'a> {
|
||||||
pub fn read_unit(&self) -> Result<Option<CounterUnit>> {
|
pub fn read_unit(&self) -> Result<Option<CounterUnit>> {
|
||||||
self.read_header_at("counter.unit", |s| match s {
|
self.read_header_at("counter.unit", |s| match s {
|
||||||
Some(&Value::String(ref s)) => Ok(Some(CounterUnit::new(s.clone()))),
|
Some(&Value::String(ref s)) => Ok(Some(CounterUnit::new(s.clone()))),
|
||||||
Some(_) => Err(CEK::HeaderTypeError.into_error()),
|
Some(_) => Err(CE::from_kind(CEK::HeaderTypeError)),
|
||||||
_ => Err(CEK::StoreReadError.into_error()),
|
_ => Err(CE::from_kind(CEK::StoreReadError)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +186,7 @@ impl<'a> Counter<'a> {
|
||||||
self.fle
|
self.fle
|
||||||
.get_header()
|
.get_header()
|
||||||
.read(&String::from(name))
|
.read(&String::from(name))
|
||||||
.map_err_into(CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
.and_then(f)
|
.and_then(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +194,7 @@ impl<'a> Counter<'a> {
|
||||||
debug!("Loading counter: '{}'", name);
|
debug!("Loading counter: '{}'", name);
|
||||||
let id = try!(ModuleEntryPath::new(name)
|
let id = try!(ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map_err_into(CEK::StoreWriteError));
|
.chain_err(|| CEK::StoreWriteError));
|
||||||
Counter::from_storeid(store, id)
|
Counter::from_storeid(store, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,14 +202,14 @@ impl<'a> Counter<'a> {
|
||||||
debug!("Deleting counter: '{}'", name);
|
debug!("Deleting counter: '{}'", name);
|
||||||
let id = try!(ModuleEntryPath::new(name)
|
let id = try!(ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map_err_into(CEK::StoreWriteError));
|
.chain_err(|| CEK::StoreWriteError));
|
||||||
store.delete(id).map_err_into(CEK::StoreWriteError)
|
store.delete(id).chain_err(|| CEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_counters(store: &Store) -> Result<CounterIterator> {
|
pub fn all_counters(store: &Store) -> Result<CounterIterator> {
|
||||||
store.retrieve_for_module("counter")
|
store.retrieve_for_module("counter")
|
||||||
.map(|iter| CounterIterator::new(store, iter))
|
.map(|iter| CounterIterator::new(store, iter))
|
||||||
.map_err_into(CEK::StoreReadError)
|
.chain_err(|| CEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -224,11 +223,11 @@ impl<'a> FromStoreId for Counter<'a> {
|
||||||
fn from_storeid(store: &Store, id: StoreId) -> Result<Counter> {
|
fn from_storeid(store: &Store, id: StoreId) -> Result<Counter> {
|
||||||
debug!("Loading counter from storeid: '{:?}'", id);
|
debug!("Loading counter from storeid: '{:?}'", id);
|
||||||
match store.retrieve(id) {
|
match store.retrieve(id) {
|
||||||
Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))),
|
Err(e) => Err(e).chain_err(|| CEK::StoreReadError),
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
let mut counter = Counter { fle: c, unit: None };
|
let mut counter = Counter { fle: c, unit: None };
|
||||||
counter.read_unit()
|
counter.read_unit()
|
||||||
.map_err_into(CEK::StoreReadError)
|
.chain_err(|| CEK::StoreReadError)
|
||||||
.and_then(|u| {
|
.and_then(|u| {
|
||||||
counter.unit = u;
|
counter.unit = u;
|
||||||
Ok(counter)
|
Ok(counter)
|
||||||
|
|
|
@ -17,16 +17,37 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(CounterError, CounterErrorKind,
|
types {
|
||||||
StoreIdError => "StoreId error",
|
CounterError, CounterErrorKind, ResultExt, Result;
|
||||||
StoreReadError => "Store read error",
|
}
|
||||||
StoreWriteError => "Store write error",
|
|
||||||
HeaderTypeError => "Header type error",
|
|
||||||
HeaderFieldMissingError => "Header field missing error"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::CounterError;
|
errors {
|
||||||
pub use self::error::CounterErrorKind;
|
StoreIdError {
|
||||||
|
description("StoreId error")
|
||||||
|
display("StoreId error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreReadError {
|
||||||
|
description("Store read error")
|
||||||
|
display("Store read error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreWriteError {
|
||||||
|
description("Store write error")
|
||||||
|
display("Store write error")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeError {
|
||||||
|
description("Header type error")
|
||||||
|
display("Header type error")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderFieldMissingError {
|
||||||
|
description("Header field missing error")
|
||||||
|
display("Header field missing error")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -36,13 +38,13 @@
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
#[macro_use] extern crate libimagstore;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
|
||||||
module_entry_path_mod!("counter");
|
module_entry_path_mod!("counter");
|
||||||
|
|
||||||
pub mod counter;
|
pub mod counter;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod result;
|
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::CounterError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, CounterError>;
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ log = "0.3"
|
||||||
toml = "0.4.*"
|
toml = "0.4.*"
|
||||||
toml-query = "0.3.*"
|
toml-query = "0.3.*"
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -32,8 +32,8 @@ use chrono::Timelike;
|
||||||
use entry::DiaryEntry;
|
use entry::DiaryEntry;
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use error::DiaryErrorKind as DEK;
|
use error::DiaryErrorKind as DEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use iter::DiaryEntryIterator;
|
use iter::DiaryEntryIterator;
|
||||||
use iter::DiaryNameIterator;
|
use iter::DiaryNameIterator;
|
||||||
|
|
||||||
|
@ -63,10 +63,9 @@ impl Diary for Store {
|
||||||
let ndt = dt.naive_local();
|
let ndt = dt.naive_local();
|
||||||
let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
|
let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
|
||||||
|
|
||||||
self.retrieve(id).map_err_into(DEK::StoreReadError)
|
self.retrieve(id).chain_err(|| DEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create or get a new entry for today
|
|
||||||
fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry> {
|
fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry> {
|
||||||
let dt = Local::now();
|
let dt = Local::now();
|
||||||
let ndt = dt.naive_local();
|
let ndt = dt.naive_local();
|
||||||
|
@ -74,17 +73,17 @@ impl Diary for Store {
|
||||||
ndt.year(),
|
ndt.year(),
|
||||||
ndt.month(),
|
ndt.month(),
|
||||||
ndt.day(),
|
ndt.day(),
|
||||||
ndt.minute(),
|
ndt.hour(),
|
||||||
ndt.second());
|
ndt.minute());
|
||||||
|
|
||||||
self.retrieve(id).map_err_into(DEK::StoreReadError)
|
self.retrieve(id).chain_err(|| DEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get an iterator for iterating over all entries
|
// Get an iterator for iterating over all entries
|
||||||
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
|
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
|
||||||
self.retrieve_for_module("diary")
|
self.retrieve_for_module("diary")
|
||||||
.map(|iter| DiaryEntryIterator::new(self, String::from(diary_name), iter))
|
.map(|iter| DiaryEntryIterator::new(self, String::from(diary_name), iter))
|
||||||
.map_err_into(DEK::StoreReadError)
|
.chain_err(|| DEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> {
|
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> {
|
||||||
|
@ -127,7 +126,7 @@ impl Diary for Store {
|
||||||
/// Get all diary names
|
/// Get all diary names
|
||||||
fn diary_names(&self) -> Result<DiaryNameIterator> {
|
fn diary_names(&self) -> Result<DiaryNameIterator> {
|
||||||
self.retrieve_for_module("diary")
|
self.retrieve_for_module("diary")
|
||||||
.map_err_into(DEK::StoreReadError)
|
.chain_err(|| DEK::StoreReadError)
|
||||||
.map(DiaryNameIterator::new)
|
.map(DiaryNameIterator::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,7 @@ use libimagstore::store::Result as StoreResult;
|
||||||
|
|
||||||
use error::DiaryError as DE;
|
use error::DiaryError as DE;
|
||||||
use error::DiaryErrorKind as DEK;
|
use error::DiaryErrorKind as DEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use module_path::ModuleEntryPath;
|
use module_path::ModuleEntryPath;
|
||||||
|
|
||||||
|
@ -191,7 +190,7 @@ fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str, DE> {
|
||||||
Component::Normal(s) => Some(s),
|
Component::Normal(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}.and_then(|s| s.to_str())
|
}.and_then(|s| s.to_str())
|
||||||
.ok_or(DEK::IdParseError.into_error())
|
.ok_or(DE::from_kind(DEK::IdParseError))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStoreId for DiaryId {
|
impl FromStoreId for DiaryId {
|
||||||
|
@ -204,7 +203,7 @@ impl FromStoreId for DiaryId {
|
||||||
|
|
||||||
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, DE> {
|
||||||
components.next()
|
components.next()
|
||||||
.ok_or(DEK::IdParseError.into_error())
|
.ok_or(DE::from_kind(DEK::IdParseError))
|
||||||
.and_then(component_to_str)
|
.and_then(component_to_str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,21 +221,21 @@ impl FromStoreId for DiaryId {
|
||||||
|
|
||||||
match (hour, minute) {
|
match (hour, minute) {
|
||||||
(Some(h), Some(m)) => Ok((h, m)),
|
(Some(h), Some(m)) => Ok((h, m)),
|
||||||
_ => return Err(DE::new(DEK::IdParseError, None)),
|
_ => return Err(DE::from_kind(DEK::IdParseError)),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let day: Result<u32,_> = next_component(&mut cmps)
|
let day: Result<u32,_> = next_component(&mut cmps)
|
||||||
.and_then(|s| s.parse::<u32>()
|
.and_then(|s| s.parse::<u32>()
|
||||||
.map_err_into(DEK::IdParseError));
|
.chain_err(|| DEK::IdParseError));
|
||||||
|
|
||||||
let month: Result<u32,_> = next_component(&mut cmps)
|
let month: Result<u32,_> = next_component(&mut cmps)
|
||||||
.and_then(|s| s.parse::<u32>()
|
.and_then(|s| s.parse::<u32>()
|
||||||
.map_err_into(DEK::IdParseError));
|
.chain_err(|| DEK::IdParseError));
|
||||||
|
|
||||||
let year: Result<i32,_> = next_component(&mut cmps)
|
let year: Result<i32,_> = next_component(&mut cmps)
|
||||||
.and_then(|s| s.parse::<i32>()
|
.and_then(|s| s.parse::<i32>()
|
||||||
.map_err_into(DEK::IdParseError));
|
.chain_err(|| DEK::IdParseError));
|
||||||
|
|
||||||
let name = next_component(&mut cmps).map(String::from);
|
let name = next_component(&mut cmps).map(String::from);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use libimagstore::store::Entry;
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use diaryid::FromStoreId;
|
use diaryid::FromStoreId;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
|
|
||||||
pub trait DiaryEntry {
|
pub trait DiaryEntry {
|
||||||
fn diary_id(&self) -> Result<DiaryId>;
|
fn diary_id(&self) -> Result<DiaryId>;
|
||||||
|
|
|
@ -17,23 +17,67 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(DiaryError, DiaryErrorKind,
|
types {
|
||||||
StoreWriteError => "Error writing store",
|
DiaryError, DiaryErrorKind, ResultExt, Result;
|
||||||
StoreReadError => "Error reading store",
|
}
|
||||||
CannotFindDiary => "Cannot find diary",
|
|
||||||
CannotCreateNote => "Cannot create Note object for diary entry",
|
|
||||||
DiaryEditError => "Cannot edit diary entry",
|
|
||||||
PathConversionError => "Error while converting paths internally",
|
|
||||||
EntryNotInDiary => "Entry not in Diary",
|
|
||||||
IOError => "IO Error",
|
|
||||||
ViewError => "Error viewing diary entry",
|
|
||||||
IdParseError => "Error while parsing ID",
|
|
||||||
DiaryNameFindingError => "Error while finding a diary name"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::DiaryError;
|
errors {
|
||||||
pub use self::error::DiaryErrorKind;
|
StoreWriteError {
|
||||||
pub use self::error::MapErrInto;
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,15 +24,14 @@ use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use diaryid::FromStoreId;
|
use diaryid::FromStoreId;
|
||||||
use error::DiaryError as DE;
|
|
||||||
use error::DiaryErrorKind as DEK;
|
|
||||||
use error::MapErrInto;
|
|
||||||
use result::Result;
|
|
||||||
use is_in_diary::IsInDiary;
|
use is_in_diary::IsInDiary;
|
||||||
|
use error::DiaryErrorKind as DEK;
|
||||||
|
use error::DiaryError as DE;
|
||||||
|
use error::ResultExt;
|
||||||
|
use error::Result;
|
||||||
|
|
||||||
/// A iterator for iterating over diary entries
|
/// A iterator for iterating over diary entries
|
||||||
pub struct DiaryEntryIterator<'a> {
|
pub struct DiaryEntryIterator<'a> {
|
||||||
|
@ -120,8 +119,7 @@ impl<'a> Iterator for DiaryEntryIterator<'a> {
|
||||||
return Some(self
|
return Some(self
|
||||||
.store
|
.store
|
||||||
.retrieve(next)
|
.retrieve(next)
|
||||||
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
|
.chain_err(|| DEK::StoreReadError));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("Not in the requested diary ({}): {:?}", self.name, next);
|
debug!("Not in the requested diary ({}): {:?}", self.name, next);
|
||||||
|
@ -153,12 +151,12 @@ impl Iterator for DiaryNameIterator {
|
||||||
.next()
|
.next()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
s.to_str()
|
s.to_str()
|
||||||
.map_err_into(DEK::DiaryNameFindingError)
|
.chain_err(|| DEK::DiaryNameFindingError)
|
||||||
.and_then(|s| {
|
.and_then(|s| {
|
||||||
s.split("diary/")
|
s.split("diary/")
|
||||||
.nth(1)
|
.nth(1)
|
||||||
.and_then(|n| n.split("/").nth(0).map(String::from))
|
.and_then(|n| n.split("/").nth(0).map(String::from))
|
||||||
.ok_or(DEK::DiaryNameFindingError.into_error())
|
.ok_or(DE::from_kind(DEK::DiaryNameFindingError))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -38,9 +40,10 @@ extern crate chrono;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
#[macro_use] extern crate libimagstore;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagentryedit;
|
extern crate libimagentryedit;
|
||||||
extern crate libimagentryview;
|
extern crate libimagentryview;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
|
@ -54,6 +57,5 @@ pub mod diary;
|
||||||
pub mod is_in_diary;
|
pub mod is_in_diary;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
pub mod result;
|
|
||||||
pub mod viewer;
|
pub mod viewer;
|
||||||
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::DiaryError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, DiaryError>;
|
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
use entry::DiaryEntry;
|
use entry::DiaryEntry;
|
||||||
use error::DiaryErrorKind as DEK;
|
use error::DiaryErrorKind as DEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagentryview::viewer::Viewer;
|
use libimagentryview::viewer::Viewer;
|
||||||
|
@ -56,8 +56,8 @@ impl DiaryViewer {
|
||||||
}
|
}
|
||||||
let _ = try!(self.0
|
let _ = try!(self.0
|
||||||
.view_entry(&entry)
|
.view_entry(&entry)
|
||||||
.map_err_into(DEK::ViewError)
|
.chain_err(|| DEK::ViewError)
|
||||||
.map_err_into(DEK::IOError));
|
.chain_err(|| DEK::IOError));
|
||||||
println!("\n---\n");
|
println!("\n---\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ homepage = "http://imag-pim.org"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
email = "0.0.17"
|
email = "0.0.17"
|
||||||
filters = "0.1.*"
|
filters = "0.1.*"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -17,19 +17,44 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(MailError, MailErrorKind,
|
types {
|
||||||
RefCreationError => "Error creating a reference to a file/directory",
|
MailError, MailErrorKind, ResultExt, Result;
|
||||||
RefHandlingError => "Error while handling the internal reference object",
|
}
|
||||||
MailParsingError => "Error while parsing mail",
|
|
||||||
|
|
||||||
FetchByHashError => "Error fetching mail from Store by hash",
|
links {
|
||||||
FetchError => "Error fetching mail from Store",
|
RefError(::libimagentryref::error::RefError, ::libimagentryref::error::RefErrorKind);
|
||||||
IOError => "IO Error"
|
}
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::MailError;
|
|
||||||
pub use self::error::MailErrorKind;
|
errors {
|
||||||
pub use self::error::MapErrInto;
|
RefCreationError {
|
||||||
|
description("Error creating a reference to a file/directory")
|
||||||
|
display("Error creating a reference to a file/directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
RefHandlingError {
|
||||||
|
description("Error handling a reference")
|
||||||
|
display("Error handling a reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
MailParsingError {
|
||||||
|
description("Failed to parse mail")
|
||||||
|
display("Failed to parse mail")
|
||||||
|
}
|
||||||
|
|
||||||
|
FetchByHashError {
|
||||||
|
description("Error fetching mail from Store by hash")
|
||||||
|
display("Error fetching mail from Store by hash")
|
||||||
|
}
|
||||||
|
FetchError {
|
||||||
|
description("Error fetching mail from Store")
|
||||||
|
display("Error fetching mail from Store")
|
||||||
|
}
|
||||||
|
IOError {
|
||||||
|
description("IO Error")
|
||||||
|
display("IO Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,8 @@ use email::MimeMessage;
|
||||||
use libimagentryref::hasher::Hasher;
|
use libimagentryref::hasher::Hasher;
|
||||||
use libimagentryref::hasher::DefaultHasher;
|
use libimagentryref::hasher::DefaultHasher;
|
||||||
use libimagentryref::error::RefErrorKind as REK;
|
use libimagentryref::error::RefErrorKind as REK;
|
||||||
use libimagentryref::error::MapErrInto;
|
use libimagentryref::error::ResultExt;
|
||||||
use libimagentryref::result::Result as RResult;
|
use libimagentryref::error::Result as RResult;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use error::MailErrorKind as MEK;
|
|
||||||
|
|
||||||
pub struct MailHasher {
|
pub struct MailHasher {
|
||||||
defaulthasher: DefaultHasher,
|
defaulthasher: DefaultHasher,
|
||||||
|
@ -54,12 +51,10 @@ impl Hasher for MailHasher {
|
||||||
use email::Header;
|
use email::Header;
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
try!(c.read_to_string(&mut s).map_err_into(REK::UTF8Error).map_err_into(REK::IOError));
|
try!(c.read_to_string(&mut s).chain_err(|| REK::UTF8Error).chain_err(|| REK::IOError));
|
||||||
|
|
||||||
MimeMessage::parse(&s)
|
MimeMessage::parse(&s)
|
||||||
.map_err(Box::new)
|
.chain_err(|| REK::RefHashingError)
|
||||||
.map_err(|e| MEK::MailParsingError.into_error_with_cause(e))
|
|
||||||
.map_err_into(REK::RefHashingError)
|
|
||||||
.and_then(|mail| {
|
.and_then(|mail| {
|
||||||
let has_key = |hdr: &Header, exp: &str| hdr.name == exp;
|
let has_key = |hdr: &Header, exp: &str| hdr.name == exp;
|
||||||
|
|
||||||
|
@ -73,8 +68,7 @@ impl Hasher for MailHasher {
|
||||||
for hdr in mail.headers.iter().filter(|item| filter.filter(item)) {
|
for hdr in mail.headers.iter().filter(|item| filter.filter(item)) {
|
||||||
let s = try!(hdr
|
let s = try!(hdr
|
||||||
.get_value()
|
.get_value()
|
||||||
.map_err(Box::new)
|
.chain_err(|| REK::RefHashingError));
|
||||||
.map_err(|e| REK::RefHashingError.into_error_with_cause(e)));
|
|
||||||
|
|
||||||
v.push(s);
|
v.push(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use mail::Mail;
|
use mail::Mail;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -36,8 +38,9 @@
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate email;
|
extern crate email;
|
||||||
extern crate filters;
|
extern crate filters;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagentryref;
|
extern crate libimagentryref;
|
||||||
|
|
||||||
|
@ -45,5 +48,4 @@ pub mod error;
|
||||||
pub mod hasher;
|
pub mod hasher;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
pub mod mail;
|
pub mod mail;
|
||||||
pub mod result;
|
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ use email::MimeMessage;
|
||||||
use email::results::ParsingResult as EmailParsingResult;
|
use email::results::ParsingResult as EmailParsingResult;
|
||||||
|
|
||||||
use hasher::MailHasher;
|
use hasher::MailHasher;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::{MapErrInto, MailErrorKind as MEK};
|
use error::{ResultExt, MailErrorKind as MEK};
|
||||||
|
|
||||||
struct Buffer(String);
|
struct Buffer(String);
|
||||||
|
|
||||||
|
@ -61,17 +61,17 @@ impl<'a> Mail<'a> {
|
||||||
let p = PathBuf::from(p.as_ref());
|
let p = PathBuf::from(p.as_ref());
|
||||||
|
|
||||||
store.create_with_hasher(p, f, h)
|
store.create_with_hasher(p, f, h)
|
||||||
.map_err_into(MEK::RefCreationError)
|
.chain_err(|| MEK::RefCreationError)
|
||||||
.and_then(|reference| {
|
.and_then(|reference| {
|
||||||
debug!("Build reference file: {:?}", reference);
|
debug!("Build reference file: {:?}", reference);
|
||||||
reference.fs_file()
|
reference.fs_file()
|
||||||
.map_err_into(MEK::RefHandlingError)
|
.chain_err(|| MEK::RefHandlingError)
|
||||||
.and_then(|path| File::open(path).map_err_into(MEK::IOError))
|
.and_then(|path| File::open(path).chain_err(|| MEK::IOError))
|
||||||
.and_then(|mut file| {
|
.and_then(|mut file| {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
file.read_to_string(&mut s)
|
file.read_to_string(&mut s)
|
||||||
.map(|_| s)
|
.map(|_| s)
|
||||||
.map_err_into(MEK::IOError)
|
.chain_err(|| MEK::IOError)
|
||||||
})
|
})
|
||||||
.map(Buffer::from)
|
.map(Buffer::from)
|
||||||
.map(|buffer| Mail(reference, buffer))
|
.map(|buffer| Mail(reference, buffer))
|
||||||
|
@ -82,8 +82,8 @@ impl<'a> Mail<'a> {
|
||||||
pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
|
pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
|
||||||
debug!("Opening Mail by Hash");
|
debug!("Opening Mail by Hash");
|
||||||
store.get_by_hash(String::from(hash.as_ref()))
|
store.get_by_hash(String::from(hash.as_ref()))
|
||||||
.map_err_into(MEK::FetchByHashError)
|
.chain_err(|| MEK::FetchByHashError)
|
||||||
.map_err_into(MEK::FetchError)
|
.chain_err(|| MEK::FetchError)
|
||||||
.and_then(|o| match o {
|
.and_then(|o| match o {
|
||||||
Some(r) => Mail::from_fle(r).map(Some),
|
Some(r) => Mail::from_fle(r).map(Some),
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
|
@ -94,13 +94,13 @@ impl<'a> Mail<'a> {
|
||||||
/// Implement me as TryFrom as soon as it is stable
|
/// Implement me as TryFrom as soon as it is stable
|
||||||
pub fn from_fle(fle: FileLockEntry<'a>) -> Result<Mail<'a>> {
|
pub fn from_fle(fle: FileLockEntry<'a>) -> Result<Mail<'a>> {
|
||||||
fle.fs_file()
|
fle.fs_file()
|
||||||
.map_err_into(MEK::RefHandlingError)
|
.chain_err(|| MEK::RefHandlingError)
|
||||||
.and_then(|path| File::open(path).map_err_into(MEK::IOError))
|
.and_then(|path| File::open(path).chain_err(|| MEK::IOError))
|
||||||
.and_then(|mut file| {
|
.and_then(|mut file| {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
file.read_to_string(&mut s)
|
file.read_to_string(&mut s)
|
||||||
.map(|_| s)
|
.map(|_| s)
|
||||||
.map_err_into(MEK::IOError)
|
.chain_err(|| MEK::IOError)
|
||||||
})
|
})
|
||||||
.map(Buffer::from)
|
.map(Buffer::from)
|
||||||
.map(|buffer| Mail(fle, buffer))
|
.map(|buffer| Mail(fle, buffer))
|
||||||
|
@ -110,7 +110,7 @@ impl<'a> Mail<'a> {
|
||||||
debug!("Getting field in mail: {:?}", field);
|
debug!("Getting field in mail: {:?}", field);
|
||||||
self.1
|
self.1
|
||||||
.parsed()
|
.parsed()
|
||||||
.map_err_into(MEK::MailParsingError)
|
.chain_err(|| MEK::MailParsingError)
|
||||||
.map(|parsed| {
|
.map(|parsed| {
|
||||||
parsed.headers
|
parsed.headers
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::MailError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, MailError>;
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ homepage = "http://imag-pim.org"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
toml = "^0.4"
|
toml = "^0.4"
|
||||||
toml-query = "0.3.0"
|
toml-query = "0.3.0"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -17,16 +17,32 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(NoteError, NoteErrorKind,
|
types {
|
||||||
StoreWriteError => "Error writing store",
|
NoteError, NoteErrorKind, ResultExt, Result;
|
||||||
StoreReadError => "Error reading store",
|
}
|
||||||
HeaderTypeError => "Header type error",
|
|
||||||
NoteToEntryConversion => "Error converting Note instance to Entry instance"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::NoteError;
|
errors {
|
||||||
pub use self::error::NoteErrorKind;
|
StoreWriteError {
|
||||||
pub use self::error::MapErrInto;
|
description("Error writing store")
|
||||||
|
display("Error writing store")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreReadError {
|
||||||
|
description("Error reading store")
|
||||||
|
display("Error reading store")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeError {
|
||||||
|
description("Header type error")
|
||||||
|
display("Header type error")
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteToEntryConversion {
|
||||||
|
description("Error converting Note instance to Entry instance")
|
||||||
|
display("Error converting Note instance to Entry instance")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -36,15 +38,15 @@
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
#[macro_use] extern crate libimagstore;
|
#[macro_use] extern crate libimagstore;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagentryedit;
|
extern crate libimagentryedit;
|
||||||
|
|
||||||
module_entry_path_mod!("notes");
|
module_entry_path_mod!("notes");
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod note;
|
pub mod note;
|
||||||
pub mod result;
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use toml::Value;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagentryedit::edit::Edit;
|
use libimagentryedit::edit::Edit;
|
||||||
use libimagentryedit::result::Result as EditResult;
|
use libimagentryedit::error::Result as EditResult;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
|
@ -35,10 +35,10 @@ use toml_query::read::TomlValueReadExt;
|
||||||
use toml_query::set::TomlValueSetExt;
|
use toml_query::set::TomlValueSetExt;
|
||||||
|
|
||||||
use module_path::ModuleEntryPath;
|
use module_path::ModuleEntryPath;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::NoteError as NE;
|
|
||||||
use error::NoteErrorKind as NEK;
|
use error::NoteErrorKind as NEK;
|
||||||
use error::MapErrInto;
|
use error::NoteError as NE;
|
||||||
|
use error::ResultExt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Note<'a> {
|
pub struct Note<'a> {
|
||||||
|
@ -55,24 +55,20 @@ impl<'a> Note<'a> {
|
||||||
let mut lockentry = try!(ModuleEntryPath::new(name.clone())
|
let mut lockentry = try!(ModuleEntryPath::new(name.clone())
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| store.create(id))
|
.and_then(|id| store.create(id))
|
||||||
.map_err_into(NEK::StoreWriteError));
|
.chain_err(|| NEK::StoreWriteError));
|
||||||
|
|
||||||
{
|
{
|
||||||
let entry = lockentry.deref_mut();
|
let entry = lockentry.deref_mut();
|
||||||
|
|
||||||
{
|
{
|
||||||
let header = entry.get_header_mut();
|
let header = entry.get_header_mut();
|
||||||
let setres = header.set("note", Value::Table(BTreeMap::new()));
|
let _ = header
|
||||||
if setres.is_err() {
|
.set("note", Value::Table(BTreeMap::new()))
|
||||||
let kind = NEK::StoreWriteError;
|
.chain_err(|| NEK::StoreWriteError);
|
||||||
return Err(NE::new(kind, Some(Box::new(setres.unwrap_err()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
let setres = header.set("note.name", Value::String(name));
|
let _ = header
|
||||||
if setres.is_err() {
|
.set("note.name", Value::String(name))
|
||||||
let kind = NEK::StoreWriteError;
|
.chain_err(|| NEK::StoreWriteError);
|
||||||
return Err(NE::new(kind, Some(Box::new(setres.unwrap_err()))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*entry.get_content_mut() = text;
|
*entry.get_content_mut() = text;
|
||||||
|
@ -88,7 +84,7 @@ impl<'a> Note<'a> {
|
||||||
self.entry
|
self.entry
|
||||||
.get_header_mut()
|
.get_header_mut()
|
||||||
.set("note.name", Value::String(n))
|
.set("note.name", Value::String(n))
|
||||||
.map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
|
.chain_err(|| NEK::StoreWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,10 +93,9 @@ impl<'a> Note<'a> {
|
||||||
match header.read("note.name") {
|
match header.read("note.name") {
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
|
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let e = NE::new(NEK::HeaderTypeError, None);
|
Err(NE::from_kind(NEK::HeaderTypeError)).chain_err(|| NEK::StoreReadError)
|
||||||
Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
|
|
||||||
},
|
},
|
||||||
Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
|
Err(e) => Err(e).chain_err(|| NEK::StoreReadError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,14 +111,14 @@ impl<'a> Note<'a> {
|
||||||
ModuleEntryPath::new(name)
|
ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| store.delete(id))
|
.and_then(|id| store.delete(id))
|
||||||
.map_err_into(NEK::StoreWriteError)
|
.chain_err(|| NEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve(store: &Store, name: String) -> Result<Note> {
|
pub fn retrieve(store: &Store, name: String) -> Result<Note> {
|
||||||
ModuleEntryPath::new(name)
|
ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| store.retrieve(id))
|
.and_then(|id| store.retrieve(id))
|
||||||
.map_err_into(NEK::StoreWriteError)
|
.chain_err(|| NEK::StoreWriteError)
|
||||||
.map(|entry| Note { entry: entry })
|
.map(|entry| Note { entry: entry })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,14 +126,14 @@ impl<'a> Note<'a> {
|
||||||
ModuleEntryPath::new(name)
|
ModuleEntryPath::new(name)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| store.get(id))
|
.and_then(|id| store.get(id))
|
||||||
.map_err_into(NEK::StoreWriteError)
|
.chain_err(|| NEK::StoreWriteError)
|
||||||
.map(|o| o.map(|entry| Note { entry: entry }))
|
.map(|o| o.map(|entry| Note { entry: entry }))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_notes(store: &Store) -> Result<NoteIterator> {
|
pub fn all_notes(store: &Store) -> Result<NoteIterator> {
|
||||||
store.retrieve_for_module("notes")
|
store.retrieve_for_module("notes")
|
||||||
.map(|iter| NoteIterator::new(store, iter))
|
.map(|iter| NoteIterator::new(store, iter))
|
||||||
.map_err(|e| NE::new(NEK::StoreReadError, Some(Box::new(e))))
|
.chain_err(|| NEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -160,7 +155,7 @@ impl<'a> FromStoreId for Note<'a> {
|
||||||
fn from_storeid(store: &Store, id: StoreId) -> Result<Note> {
|
fn from_storeid(store: &Store, id: StoreId) -> Result<Note> {
|
||||||
debug!("Loading note from storeid: '{:?}'", id);
|
debug!("Loading note from storeid: '{:?}'", id);
|
||||||
match store.retrieve(id) {
|
match store.retrieve(id) {
|
||||||
Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e)))),
|
Err(e) => Err(e).chain_err(|| NEK::StoreReadError),
|
||||||
Ok(entry) => Ok(Note { entry: entry }),
|
Ok(entry) => Ok(Note { entry: entry }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::NoteError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, NoteError>;
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ toml = "0.4"
|
||||||
toml-query = "0.3"
|
toml-query = "0.3"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
is-match = "0.1"
|
is-match = "0.1"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
|
@ -17,23 +17,48 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(TimeTrackError, TimeTrackErrorKind,
|
types {
|
||||||
StoreReadError => "Store read error",
|
TimeTrackError, TimeTrackErrorKind, ResultExt, Result;
|
||||||
StoreWriteError => "Store write error",
|
}
|
||||||
|
|
||||||
StoreIdError => "Error while handling StoreId",
|
errors {
|
||||||
|
StoreReadError {
|
||||||
|
description("Error while writing Store")
|
||||||
|
display("Error while writing Store")
|
||||||
|
}
|
||||||
|
|
||||||
TagFormat => "Tag has invalid format",
|
StoreWriteError {
|
||||||
|
description("Error while reading Store")
|
||||||
|
display("Error while reading Store")
|
||||||
|
}
|
||||||
|
|
||||||
HeaderReadError => "Error writing header",
|
StoreIdError {
|
||||||
HeaderWriteError => "Error writing header",
|
description("Error while handling StoreId")
|
||||||
HeaderFieldTypeError => "Type error in header",
|
display("Error while handling StoreId")
|
||||||
DateTimeParserError => "Error while parsing DateTime"
|
}
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::TimeTrackError;
|
TagFormat {
|
||||||
pub use self::error::TimeTrackErrorKind;
|
description("Tag has invalid format")
|
||||||
pub use self::error::MapErrInto;
|
display("Tag has invalid format")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderReadError {
|
||||||
|
description("Error writing header")
|
||||||
|
display("Error writing header")
|
||||||
|
}
|
||||||
|
HeaderWriteError {
|
||||||
|
description("Error writing header")
|
||||||
|
display("Error writing header")
|
||||||
|
}
|
||||||
|
HeaderFieldTypeError {
|
||||||
|
description("Type error in header")
|
||||||
|
display("Type error in header")
|
||||||
|
}
|
||||||
|
DateTimeParserError {
|
||||||
|
description("Error while parsing DateTime")
|
||||||
|
display("Error while parsing DateTime")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use chrono::naive::NaiveDateTime as NDT;
|
||||||
use constants::*;
|
use constants::*;
|
||||||
use error::TimeTrackError as TTE;
|
use error::TimeTrackError as TTE;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use iter::storeid::TagStoreIdIter;
|
use iter::storeid::TagStoreIdIter;
|
||||||
use iter::setendtime::SetEndTimeIter;
|
use iter::setendtime::SetEndTimeIter;
|
||||||
|
|
||||||
|
@ -61,12 +61,12 @@ impl<'a> Iterator for CreateTimeTrackIter<'a>
|
||||||
res.and_then(|(id, starttime)| {
|
res.and_then(|(id, starttime)| {
|
||||||
self.store
|
self.store
|
||||||
.create(id)
|
.create(id)
|
||||||
.map_err_into(TTEK::StoreWriteError)
|
.chain_err(|| TTEK::StoreWriteError)
|
||||||
.and_then(|mut entry| {
|
.and_then(|mut entry| {
|
||||||
let v = Value::String(starttime.format(DATE_TIME_FORMAT).to_string());
|
let v = Value::String(starttime.format(DATE_TIME_FORMAT).to_string());
|
||||||
entry.get_header_mut()
|
entry.get_header_mut()
|
||||||
.insert(DATE_TIME_START_HEADER_PATH, v)
|
.insert(DATE_TIME_START_HEADER_PATH, v)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| entry)
|
.map(|_| entry)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,12 +19,11 @@
|
||||||
|
|
||||||
use error::TimeTrackError as TTE;
|
use error::TimeTrackError as TTE;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
pub struct GetTimeTrackIter<'a>{
|
pub struct GetTimeTrackIter<'a>{
|
||||||
inner: StoreIdIterator,
|
inner: StoreIdIterator,
|
||||||
|
@ -46,8 +45,8 @@ impl<'a> Iterator for GetTimeTrackIter<'a> {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.inner.next().map(|sid| {
|
self.inner.next().map(|sid| {
|
||||||
match self.store.get(sid).map_err_into(TTEK::StoreReadError) {
|
match self.store.get(sid).chain_err(|| TTEK::StoreReadError) {
|
||||||
Ok(None) => Err(TTEK::StoreReadError.into_error()),
|
Ok(None) => Err(TTE::from_kind(TTEK::StoreReadError)),
|
||||||
Ok(Some(s)) => Ok(s),
|
Ok(Some(s)) => Ok(s),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use chrono::naive::NaiveDateTime as NDT;
|
||||||
use constants::*;
|
use constants::*;
|
||||||
use error::TimeTrackError as TTE;
|
use error::TimeTrackError as TTE;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use iter::create::CreateTimeTrackIter;
|
use iter::create::CreateTimeTrackIter;
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
|
@ -55,7 +55,7 @@ impl<'a> Iterator for SetEndTimeIter<'a> {
|
||||||
let v = Value::String(self.datetime.format(DATE_TIME_FORMAT).to_string());
|
let v = Value::String(self.datetime.format(DATE_TIME_FORMAT).to_string());
|
||||||
fle.get_header_mut()
|
fle.get_header_mut()
|
||||||
.insert(DATE_TIME_END_HEADER_PATH, v)
|
.insert(DATE_TIME_END_HEADER_PATH, v)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| fle)
|
.map(|_| fle)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -22,7 +22,7 @@ use chrono::naive::NaiveDateTime as NDT;
|
||||||
use constants::*;
|
use constants::*;
|
||||||
use error::TimeTrackError;
|
use error::TimeTrackError;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use iter::tag::TagIter;
|
use iter::tag::TagIter;
|
||||||
use iter::create::CreateTimeTrackIter;
|
use iter::create::CreateTimeTrackIter;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ impl Iterator for TagStoreIdIter {
|
||||||
let id_str = format!("{}-{}", dt, tag.as_str());
|
let id_str = format!("{}-{}", dt, tag.as_str());
|
||||||
ModuleEntryPath::new(id_str)
|
ModuleEntryPath::new(id_str)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map_err_into(TTEK::StoreIdError)
|
.chain_err(|| TTEK::StoreIdError)
|
||||||
.map(|id| (id, self.datetime.clone()))
|
.map(|id| (id, self.datetime.clone()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,11 +21,11 @@ use chrono::naive::NaiveDateTime as NDT;
|
||||||
|
|
||||||
use error::TimeTrackError;
|
use error::TimeTrackError;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
|
use error::TimeTrackError as TTE;
|
||||||
use tag::TimeTrackingTag as TTT;
|
use tag::TimeTrackingTag as TTT;
|
||||||
use iter::storeid::TagStoreIdIter;
|
use iter::storeid::TagStoreIdIter;
|
||||||
|
|
||||||
use libimagentrytag::tag::is_tag_str;
|
use libimagentrytag::tag::is_tag_str;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
pub struct TagIter(Box<Iterator<Item = String>>);
|
pub struct TagIter(Box<Iterator<Item = String>>);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ impl Iterator for TagIter {
|
||||||
.map(|t| if is_tag_str(&t).is_ok() {
|
.map(|t| if is_tag_str(&t).is_ok() {
|
||||||
Ok(TTT::from(t))
|
Ok(TTT::from(t))
|
||||||
} else {
|
} else {
|
||||||
Err(TTEK::TagFormat.into_error())
|
Err(TTE::from_kind(TTEK::TagFormat))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -41,20 +43,19 @@ extern crate toml_query;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate is_match;
|
extern crate is_match;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate libimagerror;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagentrydatetime;
|
extern crate libimagentrydatetime;
|
||||||
extern crate libimagentrytag;
|
extern crate libimagentrytag;
|
||||||
|
extern crate libimagerror;
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod timetracking;
|
pub mod timetracking;
|
||||||
pub mod timetrackingstore;
|
pub mod timetrackingstore;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
pub mod result;
|
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
|
|
||||||
module_entry_path_mod!("timetrack");
|
module_entry_path_mod!("timetrack");
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::TimeTrackError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, TimeTrackError>;
|
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
use chrono::naive::NaiveDateTime;
|
use chrono::naive::NaiveDateTime;
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use tag::TimeTrackingTag as TTT;
|
use tag::TimeTrackingTag as TTT;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
use error::MapErrInto;
|
use error::TimeTrackError as TTE;
|
||||||
use result::Result;
|
use error::ResultExt;
|
||||||
|
use error::Result;
|
||||||
use constants::*;
|
use constants::*;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
@ -65,11 +65,11 @@ impl TimeTracking for Entry {
|
||||||
fn get_timetrack_tag(&self) -> Result<TTT> {
|
fn get_timetrack_tag(&self) -> Result<TTT> {
|
||||||
self.get_header()
|
self.get_header()
|
||||||
.read(DATE_TIME_TAG_HEADER_PATH)
|
.read(DATE_TIME_TAG_HEADER_PATH)
|
||||||
.map_err_into(TTEK::HeaderReadError)
|
.chain_err(|| TTEK::HeaderReadError)
|
||||||
.and_then(|value| match value {
|
.and_then(|value| match value {
|
||||||
Some(&Value::String(ref s)) => Ok(s.clone().into()),
|
Some(&Value::String(ref s)) => Ok(s.clone().into()),
|
||||||
Some(_) => Err(TTEK::HeaderFieldTypeError.into_error()),
|
Some(_) => Err(TTE::from_kind(TTEK::HeaderFieldTypeError)),
|
||||||
_ => Err(TTEK::HeaderReadError.into_error())
|
_ => Err(TTE::from_kind(TTEK::HeaderReadError))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,21 +78,21 @@ impl TimeTracking for Entry {
|
||||||
|
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.insert(DATE_TIME_START_HEADER_PATH, Value::String(s))
|
.insert(DATE_TIME_START_HEADER_PATH, Value::String(s))
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_start_datetime(&self) -> Result<Option<NaiveDateTime>> {
|
fn get_start_datetime(&self) -> Result<Option<NaiveDateTime>> {
|
||||||
self.get_header()
|
self.get_header()
|
||||||
.read(DATE_TIME_START_HEADER_PATH)
|
.read(DATE_TIME_START_HEADER_PATH)
|
||||||
.map_err_into(TTEK::HeaderReadError)
|
.chain_err(|| TTEK::HeaderReadError)
|
||||||
.and_then(header_value_to_dt)
|
.and_then(header_value_to_dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_start_datetime(&mut self) -> Result<()> {
|
fn delete_start_datetime(&mut self) -> Result<()> {
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.delete(DATE_TIME_START_HEADER_PATH)
|
.delete(DATE_TIME_START_HEADER_PATH)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,21 +101,21 @@ impl TimeTracking for Entry {
|
||||||
|
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.insert(DATE_TIME_END_HEADER_PATH, Value::String(s))
|
.insert(DATE_TIME_END_HEADER_PATH, Value::String(s))
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_end_datetime(&self) -> Result<Option<NaiveDateTime>> {
|
fn get_end_datetime(&self) -> Result<Option<NaiveDateTime>> {
|
||||||
self.get_header()
|
self.get_header()
|
||||||
.read(DATE_TIME_END_HEADER_PATH)
|
.read(DATE_TIME_END_HEADER_PATH)
|
||||||
.map_err_into(TTEK::HeaderReadError)
|
.chain_err(|| TTEK::HeaderReadError)
|
||||||
.and_then(header_value_to_dt)
|
.and_then(header_value_to_dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_end_datetime(&mut self) -> Result<()> {
|
fn delete_end_datetime(&mut self) -> Result<()> {
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.delete(DATE_TIME_END_HEADER_PATH)
|
.delete(DATE_TIME_END_HEADER_PATH)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,11 +141,11 @@ fn header_value_to_dt(val: Option<&Value>) -> Result<Option<NaiveDateTime>> {
|
||||||
match val {
|
match val {
|
||||||
Some(&Value::String(ref s)) => {
|
Some(&Value::String(ref s)) => {
|
||||||
NaiveDateTime::parse_from_str(s, DATE_TIME_FORMAT)
|
NaiveDateTime::parse_from_str(s, DATE_TIME_FORMAT)
|
||||||
.map_err_into(TTEK::DateTimeParserError)
|
.chain_err(|| TTEK::DateTimeParserError)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
|
|
||||||
},
|
},
|
||||||
Some(_) => Err(TTEK::HeaderFieldTypeError.into_error()),
|
Some(_) => Err(TTE::from_kind(TTEK::HeaderFieldTypeError)),
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,10 @@ use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagentrydatetime::datepath::compiler::DatePathCompiler;
|
use libimagentrydatetime::datepath::compiler::DatePathCompiler;
|
||||||
|
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use constants::*;
|
use constants::*;
|
||||||
use error::TimeTrackErrorKind as TTEK;
|
use error::TimeTrackErrorKind as TTEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use iter::get::GetTimeTrackIter;
|
use iter::get::GetTimeTrackIter;
|
||||||
|
|
||||||
use tag::TimeTrackingTag as TTT;
|
use tag::TimeTrackingTag as TTT;
|
||||||
|
@ -71,24 +71,24 @@ impl<'a> TimeTrackStore<'a> for Store {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
COMPILER.compile(CRATE_NAME, start)
|
COMPILER.compile(CRATE_NAME, start)
|
||||||
.map_err_into(TTEK::StoreIdError)
|
.chain_err(|| TTEK::StoreIdError)
|
||||||
.map(|mut id| {
|
.map(|mut id| {
|
||||||
id.local_push(PathBuf::from(ts.as_str()));
|
id.local_push(PathBuf::from(ts.as_str()));
|
||||||
id
|
id
|
||||||
})
|
})
|
||||||
.and_then(|id| self.create(id).map_err_into(TTEK::StoreWriteError))
|
.and_then(|id| self.create(id).chain_err(|| TTEK::StoreWriteError))
|
||||||
.and_then(|mut fle| {
|
.and_then(|mut fle| {
|
||||||
let v = Value::String(ts.as_str().to_owned());
|
let v = Value::String(ts.as_str().to_owned());
|
||||||
fle.get_header_mut()
|
fle.get_header_mut()
|
||||||
.insert(DATE_TIME_TAG_HEADER_PATH, v)
|
.insert(DATE_TIME_TAG_HEADER_PATH, v)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| fle)
|
.map(|_| fle)
|
||||||
})
|
})
|
||||||
.and_then(|mut fle| {
|
.and_then(|mut fle| {
|
||||||
let v = Value::String(start.format(DATE_TIME_FORMAT).to_string());
|
let v = Value::String(start.format(DATE_TIME_FORMAT).to_string());
|
||||||
fle.get_header_mut()
|
fle.get_header_mut()
|
||||||
.insert(DATE_TIME_START_HEADER_PATH, v)
|
.insert(DATE_TIME_START_HEADER_PATH, v)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| fle)
|
.map(|_| fle)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -99,14 +99,14 @@ impl<'a> TimeTrackStore<'a> for Store {
|
||||||
let v = Value::String(end.format(DATE_TIME_FORMAT).to_string());
|
let v = Value::String(end.format(DATE_TIME_FORMAT).to_string());
|
||||||
fle.get_header_mut()
|
fle.get_header_mut()
|
||||||
.insert(DATE_TIME_END_HEADER_PATH, v)
|
.insert(DATE_TIME_END_HEADER_PATH, v)
|
||||||
.map_err_into(TTEK::HeaderWriteError)
|
.chain_err(|| TTEK::HeaderWriteError)
|
||||||
.map(|_| fle)
|
.map(|_| fle)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_timetrackings(&'a self) -> Result<GetTimeTrackIter<'a>> {
|
fn get_timetrackings(&'a self) -> Result<GetTimeTrackIter<'a>> {
|
||||||
self.retrieve_for_module(CRATE_NAME)
|
self.retrieve_for_module(CRATE_NAME)
|
||||||
.map_err_into(TTEK::StoreReadError)
|
.chain_err(|| TTEK::StoreReadError)
|
||||||
.map(|iter| GetTimeTrackIter::new(iter, self))
|
.map(|iter| GetTimeTrackIter::new(iter, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ toml = "0.4.*"
|
||||||
toml-query = "0.3.*"
|
toml-query = "0.3.*"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
serde_json = "0.8"
|
serde_json = "0.8"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -17,20 +17,51 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(TodoError, TodoErrorKind,
|
types {
|
||||||
ConversionError => "Conversion Error",
|
TodoError, TodoErrorKind, ResultExt, Result;
|
||||||
StoreError => "Store Error",
|
}
|
||||||
StoreIdError => "Store Id handling error",
|
|
||||||
ImportError => "Error importing",
|
|
||||||
UTF8Error => "Encountered non-UTF8 characters while reading input",
|
|
||||||
HeaderFieldMissing => "Header field missing",
|
|
||||||
HeaderTypeError => "Header field type error",
|
|
||||||
UuidParserError => "Uuid parser error"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::TodoError;
|
errors {
|
||||||
pub use self::error::TodoErrorKind;
|
ConversionError {
|
||||||
pub use self::error::MapErrInto;
|
description("Conversion Error")
|
||||||
|
display("Conversion Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreError {
|
||||||
|
description("Store Error")
|
||||||
|
display("Store Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreIdError {
|
||||||
|
description("Store Id handling error")
|
||||||
|
display("Store Id handling error")
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportError {
|
||||||
|
description("Error importing")
|
||||||
|
display("Error importing")
|
||||||
|
}
|
||||||
|
|
||||||
|
UTF8Error {
|
||||||
|
description("Encountered non-UTF8 characters while reading input")
|
||||||
|
display("Encountered non-UTF8 characters while reading input")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderFieldMissing {
|
||||||
|
description("Header field missing")
|
||||||
|
display("Header field missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeError {
|
||||||
|
description("Header field type error")
|
||||||
|
display("Header field type error")
|
||||||
|
}
|
||||||
|
|
||||||
|
UuidParserError {
|
||||||
|
description("Uuid parser error")
|
||||||
|
display("Uuid parser error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -38,15 +40,15 @@ extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
#[macro_use] extern crate libimagstore;
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate task_hookrs;
|
extern crate task_hookrs;
|
||||||
|
|
||||||
module_entry_path_mod!("todo");
|
module_entry_path_mod!("todo");
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod result;
|
|
||||||
pub mod task;
|
pub mod task;
|
||||||
pub mod taskstore;
|
pub mod taskstore;
|
||||||
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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 error::TodoError;
|
|
||||||
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, TodoError>;
|
|
|
@ -17,12 +17,12 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use error::TodoError as TE;
|
||||||
use error::TodoErrorKind as TEK;
|
use error::TodoErrorKind as TEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
use result::Result;
|
use error::Result;
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
@ -36,11 +36,11 @@ impl Task for Entry {
|
||||||
fn get_uuid(&self) -> Result<Uuid> {
|
fn get_uuid(&self) -> Result<Uuid> {
|
||||||
match self.get_header().read("todo.uuid") {
|
match self.get_header().read("todo.uuid") {
|
||||||
Ok(Some(&Value::String(ref uuid))) => {
|
Ok(Some(&Value::String(ref uuid))) => {
|
||||||
Uuid::parse_str(uuid).map_err_into(TEK::UuidParserError)
|
Uuid::parse_str(uuid).chain_err(|| TEK::UuidParserError)
|
||||||
},
|
},
|
||||||
Ok(Some(_)) => Err(TEK::HeaderTypeError.into_error()),
|
Ok(Some(_)) => Err(TE::from_kind(TEK::HeaderTypeError)),
|
||||||
Ok(None) => Err(TEK::HeaderFieldMissing.into_error()),
|
Ok(None) => Err(TE::from_kind(TEK::HeaderFieldMissing)),
|
||||||
Err(e) => Err(e).map_err_into(TEK::StoreError),
|
Err(e) => Err(e).chain_err(|| TEK::StoreError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,10 @@ use libimagstore::store::{FileLockEntry, Store};
|
||||||
use libimagstore::storeid::{IntoStoreId, StoreIdIterator};
|
use libimagstore::storeid::{IntoStoreId, StoreIdIterator};
|
||||||
use module_path::ModuleEntryPath;
|
use module_path::ModuleEntryPath;
|
||||||
|
|
||||||
use error::{TodoErrorKind as TEK, MapErrInto};
|
use error::TodoErrorKind as TEK;
|
||||||
use result::Result;
|
use error::TodoError as TE;
|
||||||
|
use error::Result;
|
||||||
|
use error::ResultExt;
|
||||||
|
|
||||||
/// Task struct containing a `FileLockEntry`
|
/// Task struct containing a `FileLockEntry`
|
||||||
pub trait TaskStore<'a> {
|
pub trait TaskStore<'a> {
|
||||||
|
@ -52,9 +54,9 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
|
|
||||||
fn import_task_from_reader<R: BufRead>(&'a self, mut r: R) -> Result<(FileLockEntry<'a>, String, Uuid)> {
|
fn import_task_from_reader<R: BufRead>(&'a self, mut r: R) -> Result<(FileLockEntry<'a>, String, Uuid)> {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
try!(r.read_line(&mut line).map_err_into(TEK::UTF8Error));
|
try!(r.read_line(&mut line).map_err(|_| TE::from_kind(TEK::UTF8Error)));
|
||||||
import_task(&line.as_str())
|
import_task(&line.as_str())
|
||||||
.map_err_into(TEK::ImportError)
|
.map_err(|_| TE::from_kind(TEK::ImportError))
|
||||||
.and_then(|t| {
|
.and_then(|t| {
|
||||||
let uuid = t.uuid().clone();
|
let uuid = t.uuid().clone();
|
||||||
self.new_from_twtask(t).map(|t| (t, line, uuid))
|
self.new_from_twtask(t).map(|t| (t, line, uuid))
|
||||||
|
@ -72,7 +74,7 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
///
|
///
|
||||||
fn get_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<RResult<FileLockEntry<'a>, String>> {
|
fn get_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<RResult<FileLockEntry<'a>, String>> {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
try!(r.read_line(&mut line).map_err_into(TEK::UTF8Error));
|
try!(r.read_line(&mut line).chain_err(|| TEK::UTF8Error));
|
||||||
self.get_task_from_string(line)
|
self.get_task_from_string(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +84,7 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
/// For an explanation on the return values see `Task::get_from_import()`.
|
/// For an explanation on the return values see `Task::get_from_import()`.
|
||||||
fn get_task_from_string(&'a self, s: String) -> Result<RResult<FileLockEntry<'a>, String>> {
|
fn get_task_from_string(&'a self, s: String) -> Result<RResult<FileLockEntry<'a>, String>> {
|
||||||
import_task(s.as_str())
|
import_task(s.as_str())
|
||||||
.map_err_into(TEK::ImportError)
|
.map_err(|_| TE::from_kind(TEK::ImportError))
|
||||||
.map(|t| t.uuid().clone())
|
.map(|t| t.uuid().clone())
|
||||||
.and_then(|uuid| self.get_task_from_uuid(uuid))
|
.and_then(|uuid| self.get_task_from_uuid(uuid))
|
||||||
.and_then(|o| match o {
|
.and_then(|o| match o {
|
||||||
|
@ -98,14 +100,14 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|store_id| self.get(store_id))
|
.and_then(|store_id| self.get(store_id))
|
||||||
.map_err_into(TEK::StoreError)
|
.chain_err(|| TEK::StoreError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
|
/// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
|
||||||
/// implicitely create the task if it does not exist.
|
/// implicitely create the task if it does not exist.
|
||||||
fn retrieve_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<FileLockEntry<'a>> {
|
fn retrieve_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<FileLockEntry<'a>> {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
try!(r.read_line(&mut line).map_err_into(TEK::UTF8Error));
|
try!(r.read_line(&mut line).chain_err(|| TEK::UTF8Error));
|
||||||
self.retrieve_task_from_string(line)
|
self.retrieve_task_from_string(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +118,7 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
.and_then(|opt| match opt {
|
.and_then(|opt| match opt {
|
||||||
Ok(task) => Ok(task),
|
Ok(task) => Ok(task),
|
||||||
Err(string) => import_task(string.as_str())
|
Err(string) => import_task(string.as_str())
|
||||||
.map_err_into(TEK::ImportError)
|
.map_err(|_| TE::from_kind(TEK::ImportError))
|
||||||
.and_then(|t| self.new_from_twtask(t)),
|
.and_then(|t| self.new_from_twtask(t)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -133,7 +135,7 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
// task before the change, and the second one after
|
// task before the change, and the second one after
|
||||||
// the change. The (maybe modified) second one is
|
// the change. The (maybe modified) second one is
|
||||||
// expected by taskwarrior.
|
// expected by taskwarrior.
|
||||||
match serde_to_string(&ttask).map_err_into(TEK::ImportError) {
|
match serde_to_string(&ttask).chain_err(|| TEK::ImportError) {
|
||||||
// use println!() here, as we talk with TW
|
// use println!() here, as we talk with TW
|
||||||
Ok(val) => println!("{}", val),
|
Ok(val) => println!("{}", val),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
|
@ -152,7 +154,7 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
}
|
}
|
||||||
} // end if c % 2
|
} // end if c % 2
|
||||||
},
|
},
|
||||||
Err(e) => return Err(e).map_err_into(TEK::ImportError),
|
Err(e) => return Err(TE::from_kind(TEK::ImportError)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -162,12 +164,12 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| self.delete(id))
|
.and_then(|id| self.delete(id))
|
||||||
.map_err_into(TEK::StoreError)
|
.chain_err(|| TEK::StoreError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_tasks(&self) -> Result<StoreIdIterator> {
|
fn all_tasks(&self) -> Result<StoreIdIterator> {
|
||||||
self.retrieve_for_module("todo/taskwarrior")
|
self.retrieve_for_module("todo/taskwarrior")
|
||||||
.map_err_into(TEK::StoreError)
|
.chain_err(|| TEK::StoreError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>> {
|
fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>> {
|
||||||
|
@ -177,21 +179,21 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
let uuid = task.uuid();
|
let uuid = task.uuid();
|
||||||
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map_err_into(TEK::StoreIdError)
|
.chain_err(|| TEK::StoreIdError)
|
||||||
.and_then(|id| {
|
.and_then(|id| {
|
||||||
self.retrieve(id)
|
self.retrieve(id)
|
||||||
.map_err_into(TEK::StoreError)
|
.chain_err(|| TEK::StoreError)
|
||||||
.and_then(|mut fle| {
|
.and_then(|mut fle| {
|
||||||
{
|
{
|
||||||
let hdr = fle.get_header_mut();
|
let hdr = fle.get_header_mut();
|
||||||
if try!(hdr.read("todo").map_err_into(TEK::StoreError)).is_none() {
|
if try!(hdr.read("todo").chain_err(|| TEK::StoreError)).is_none() {
|
||||||
try!(hdr
|
try!(hdr
|
||||||
.set("todo", Value::Table(BTreeMap::new()))
|
.set("todo", Value::Table(BTreeMap::new()))
|
||||||
.map_err_into(TEK::StoreError));
|
.chain_err(|| TEK::StoreError));
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(hdr.set("todo.uuid", Value::String(format!("{}",uuid)))
|
try!(hdr.set("todo.uuid", Value::String(format!("{}",uuid)))
|
||||||
.map_err_into(TEK::StoreError));
|
.chain_err(|| TEK::StoreError));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If none of the errors above have returned the function, everything is fine
|
// If none of the errors above have returned the function, everything is fine
|
||||||
|
|
|
@ -13,6 +13,7 @@ license = "LGPL-2.1"
|
||||||
lazy_static = "0.1.15"
|
lazy_static = "0.1.15"
|
||||||
toml = "^0.4"
|
toml = "^0.4"
|
||||||
toml-query = "0.3.0"
|
toml-query = "0.3.0"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -25,14 +25,14 @@ use libimagstore::store::Entry;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::internal::InternalLinker;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
use toml_query::insert::TomlValueInsertExt;
|
use toml_query::insert::TomlValueInsertExt;
|
||||||
|
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::AnnotationErrorKind as AEK;
|
use error::AnnotationErrorKind as AEK;
|
||||||
use error::MapErrInto;
|
use error::AnnotationError as AE;
|
||||||
|
use error::ResultExt;
|
||||||
|
|
||||||
pub trait Annotateable {
|
pub trait Annotateable {
|
||||||
|
|
||||||
|
@ -51,16 +51,16 @@ impl Annotateable for Entry {
|
||||||
|
|
||||||
fn annotate<'a>(&mut self, store: &'a Store, ann_name: &str) -> Result<FileLockEntry<'a>> {
|
fn annotate<'a>(&mut self, store: &'a Store, ann_name: &str) -> Result<FileLockEntry<'a>> {
|
||||||
store.retrieve(PathBuf::from(ann_name))
|
store.retrieve(PathBuf::from(ann_name))
|
||||||
.map_err_into(AEK::StoreWriteError)
|
.chain_err(|| AEK::StoreWriteError)
|
||||||
.and_then(|mut anno| {
|
.and_then(|mut anno| {
|
||||||
anno.get_header_mut()
|
anno.get_header_mut()
|
||||||
.insert("annotation.is_annotation", Value::Boolean(true))
|
.insert("annotation.is_annotation", Value::Boolean(true))
|
||||||
.map_err_into(AEK::HeaderWriteError)
|
.chain_err(|| AEK::HeaderWriteError)
|
||||||
.map(|_| anno)
|
.map(|_| anno)
|
||||||
})
|
})
|
||||||
.and_then(|mut anno| {
|
.and_then(|mut anno| {
|
||||||
anno.add_internal_link(self)
|
anno.add_internal_link(self)
|
||||||
.map_err_into(AEK::LinkingError)
|
.chain_err(|| AEK::LinkingError)
|
||||||
.map(|_| anno)
|
.map(|_| anno)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,11 @@ impl Annotateable for Entry {
|
||||||
fn is_annotation(&self) -> Result<bool> {
|
fn is_annotation(&self) -> Result<bool> {
|
||||||
self.get_header()
|
self.get_header()
|
||||||
.read("annotation.is_annotation")
|
.read("annotation.is_annotation")
|
||||||
.map_err_into(AEK::StoreReadError)
|
.chain_err(|| AEK::StoreReadError)
|
||||||
.and_then(|res| match res {
|
.and_then(|res| match res {
|
||||||
Some(&Value::Boolean(b)) => Ok(b),
|
Some(&Value::Boolean(b)) => Ok(b),
|
||||||
None => Ok(false),
|
None => Ok(false),
|
||||||
_ => Err(AEK::HeaderTypeError.into_error()),
|
_ => Err(AE::from_kind(AEK::HeaderTypeError)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ use libimagnotes::note::Note;
|
||||||
use libimagnotes::note::NoteIterator;
|
use libimagnotes::note::NoteIterator;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
|
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::AnnotationErrorKind as AEK;
|
use error::AnnotationErrorKind as AEK;
|
||||||
use error::MapErrInto;
|
use error::ResultExt;
|
||||||
|
|
||||||
use self::iter::*;
|
use self::iter::*;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ impl<'a> AnnotationFetcher<'a> for Store {
|
||||||
fn all_annotations(&'a self) -> Result<AnnotationIter<'a>> {
|
fn all_annotations(&'a self) -> Result<AnnotationIter<'a>> {
|
||||||
Note::all_notes(self)
|
Note::all_notes(self)
|
||||||
.map(|iter| AnnotationIter::new(iter))
|
.map(|iter| AnnotationIter::new(iter))
|
||||||
.map_err_into(AEK::StoreReadError)
|
.chain_err(|| AEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all annotations (in an iterator) for an entry
|
/// Get all annotations (in an iterator) for an entry
|
||||||
|
@ -57,7 +57,7 @@ impl<'a> AnnotationFetcher<'a> for Store {
|
||||||
/// entry, but should normally be not that heavy.
|
/// entry, but should normally be not that heavy.
|
||||||
fn annotations_for_entry(&'a self, entry: &Entry) -> Result<AnnotationIter<'a>> {
|
fn annotations_for_entry(&'a self, entry: &Entry) -> Result<AnnotationIter<'a>> {
|
||||||
entry.get_internal_links()
|
entry.get_internal_links()
|
||||||
.map_err_into(AEK::StoreReadError)
|
.chain_err(|| AEK::StoreReadError)
|
||||||
.map(|iter| StoreIdIterator::new(Box::new(iter.map(|e| e.get_store_id().clone()))))
|
.map(|iter| StoreIdIterator::new(Box::new(iter.map(|e| e.get_store_id().clone()))))
|
||||||
.map(|iter| NoteIterator::new(self, iter))
|
.map(|iter| NoteIterator::new(self, iter))
|
||||||
.map(|iter| AnnotationIter::new(iter))
|
.map(|iter| AnnotationIter::new(iter))
|
||||||
|
@ -70,13 +70,13 @@ pub mod iter {
|
||||||
|
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
use libimagnotes::note::Note;
|
use libimagnotes::note::Note;
|
||||||
use libimagnotes::note::NoteIterator;
|
use libimagnotes::note::NoteIterator;
|
||||||
|
|
||||||
use result::Result;
|
use error::Result;
|
||||||
use error::AnnotationErrorKind as AEK;
|
use error::AnnotationErrorKind as AEK;
|
||||||
use error::MapErrInto;
|
use error::AnnotationError as AE;
|
||||||
|
use error::ResultExt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnnotationIter<'a>(NoteIterator<'a>);
|
pub struct AnnotationIter<'a>(NoteIterator<'a>);
|
||||||
|
@ -99,11 +99,11 @@ pub mod iter {
|
||||||
match note.get_header().read("annotation.is_annotation") {
|
match note.get_header().read("annotation.is_annotation") {
|
||||||
Ok(None) => continue, // not an annotation
|
Ok(None) => continue, // not an annotation
|
||||||
Ok(Some(&Value::Boolean(true))) => return Some(Ok(note)),
|
Ok(Some(&Value::Boolean(true))) => return Some(Ok(note)),
|
||||||
Ok(Some(_)) => return Some(Err(AEK::HeaderTypeError.into_error())),
|
Ok(Some(_)) => return Some(Err(AE::from_kind(AEK::HeaderTypeError))),
|
||||||
Err(e) => return Some(Err(e).map_err_into(AEK::HeaderReadError)),
|
Err(e) => return Some(Err(e).chain_err(|| AEK::HeaderReadError)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(Err(e)) => return Some(Err(e).map_err_into(AEK::StoreReadError)),
|
Some(Err(e)) => return Some(Err(e).chain_err(|| AEK::StoreReadError)),
|
||||||
None => return None, // iterator consumed
|
None => return None, // iterator consumed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,19 +17,42 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(AnnotationError, AnnotationErrorKind,
|
types {
|
||||||
StoreReadError => "Store read error",
|
AnnotationError, AnnotationErrorKind, ResultExt, Result;
|
||||||
StoreWriteError => "Store write error",
|
}
|
||||||
|
|
||||||
LinkingError => "Error while linking",
|
errors {
|
||||||
HeaderWriteError => "Couldn't write Header for annotation",
|
StoreReadError {
|
||||||
HeaderReadError => "Couldn't read Header of Entry",
|
description("Store read error")
|
||||||
HeaderTypeError => "Header field has unexpected type"
|
display("Store read error")
|
||||||
);
|
}
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::AnnotationError;
|
StoreWriteError {
|
||||||
pub use self::error::AnnotationErrorKind;
|
description("Store write error")
|
||||||
pub use self::error::MapErrInto;
|
display("Store write error")
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkingError {
|
||||||
|
description("Error while linking")
|
||||||
|
display("Error while linking")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderWriteError {
|
||||||
|
description("Couldn't write Header for annotation")
|
||||||
|
display("Couldn't write Header for annotation")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderReadError {
|
||||||
|
description("Couldn't read Header of Entry")
|
||||||
|
display("Couldn't read Header of Entry")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeError {
|
||||||
|
description("Header field has unexpected type")
|
||||||
|
display("Header field has unexpected type")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -35,8 +37,9 @@
|
||||||
|
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagentrylink;
|
extern crate libimagentrylink;
|
||||||
extern crate libimagnotes;
|
extern crate libimagnotes;
|
||||||
|
@ -44,5 +47,4 @@ extern crate libimagnotes;
|
||||||
pub mod annotateable;
|
pub mod annotateable;
|
||||||
pub mod annotation_fetcher;
|
pub mod annotation_fetcher;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod result;
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::AnnotationError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, AnnotationError>;
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ log = "0.3"
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
toml-query = "0.3"
|
toml-query = "0.3"
|
||||||
is-match = "0.1"
|
is-match = "0.1"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
|
@ -23,11 +23,11 @@ use toml_query::error::ErrorKind as TQEK;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use error::CategoryErrorKind as CEK;
|
use error::CategoryErrorKind as CEK;
|
||||||
use error::MapErrInto;
|
use error::CategoryError as CE;
|
||||||
use result::Result;
|
use error::ResultExt;
|
||||||
|
use error::Result;
|
||||||
use register::CategoryRegister;
|
use register::CategoryRegister;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
@ -64,7 +64,7 @@ impl EntryCategory for Entry {
|
||||||
fn set_category(&mut self, s: Category) -> Result<()> {
|
fn set_category(&mut self, s: Category) -> Result<()> {
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.insert(&String::from("category.value"), Value::String(s.into()))
|
.insert(&String::from("category.value"), Value::String(s.into()))
|
||||||
.map_err_into(CEK::HeaderWriteError)
|
.chain_err(|| CEK::HeaderWriteError)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ impl EntryCategory for Entry {
|
||||||
.and_then(|bl| if bl {
|
.and_then(|bl| if bl {
|
||||||
self.set_category(s)
|
self.set_category(s)
|
||||||
} else {
|
} else {
|
||||||
Err(CEK::CategoryDoesNotExist.into_error())
|
Err(CE::from_kind(CEK::CategoryDoesNotExist))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,17 +86,17 @@ impl EntryCategory for Entry {
|
||||||
&TQEK::IdentifierNotFoundInDocument(_) => Ok(None),
|
&TQEK::IdentifierNotFoundInDocument(_) => Ok(None),
|
||||||
_ => Err(res),
|
_ => Err(res),
|
||||||
}
|
}
|
||||||
.map_err_into(CEK::HeaderReadError),
|
.chain_err(|| CEK::HeaderReadError),
|
||||||
|
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(Some(s.clone().into())),
|
Ok(Some(&Value::String(ref s))) => Ok(Some(s.clone().into())),
|
||||||
Ok(None) => Err(CEK::StoreReadError.into_error()).map_err_into(CEK::HeaderReadError),
|
Ok(None) => Err(CE::from_kind(CEK::StoreReadError)).chain_err(|| CEK::HeaderReadError),
|
||||||
Ok(_) => Err(CEK::TypeError.into_error()).map_err_into(CEK::HeaderReadError),
|
Ok(_) => Err(CE::from_kind(CEK::TypeError)).chain_err(|| CEK::HeaderReadError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_category(&self) -> Result<bool> {
|
fn has_category(&self) -> Result<bool> {
|
||||||
self.get_header().read(&String::from("category.value"))
|
self.get_header().read(&String::from("category.value"))
|
||||||
.map_err_into(CEK::HeaderReadError)
|
.chain_err(|| CEK::HeaderReadError)
|
||||||
.map(|e| e.is_some())
|
.map(|e| e.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,20 +17,46 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(CategoryError, CategoryErrorKind,
|
types {
|
||||||
StoreReadError => "Store Read error",
|
CategoryError, CategoryErrorKind, ResultExt, Result;
|
||||||
StoreWriteError => "Store Write error",
|
}
|
||||||
StoreIdHandlingError => "StoreId handling error",
|
|
||||||
HeaderReadError => "Header read error",
|
|
||||||
HeaderWriteError => "Header write error",
|
|
||||||
TypeError => "Found wrong type in header",
|
|
||||||
|
|
||||||
CategoryDoesNotExist => "Category does not exist"
|
errors {
|
||||||
);
|
StoreReadError {
|
||||||
);
|
description("Store Read error")
|
||||||
|
display("Store Read error")
|
||||||
|
}
|
||||||
|
|
||||||
pub use self::error::CategoryError;
|
StoreWriteError {
|
||||||
pub use self::error::CategoryErrorKind;
|
description("Store Write error")
|
||||||
pub use self::error::MapErrInto;
|
display("Store Write error")
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreIdHandlingError {
|
||||||
|
description("StoreId handling error")
|
||||||
|
display("StoreId handling error")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderReadError {
|
||||||
|
description("Header read error")
|
||||||
|
display("Header read error")
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderWriteError {
|
||||||
|
description("Header write error")
|
||||||
|
display("Header write error")
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoryDoesNotExist {
|
||||||
|
description("Category does not exist")
|
||||||
|
display("Category does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeError {
|
||||||
|
description("Type Error")
|
||||||
|
display("Type Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#![recursion_limit="256"]
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
@ -39,8 +41,8 @@ extern crate toml;
|
||||||
extern crate is_match;
|
extern crate is_match;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
#[macro_use] extern crate error_chain;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
@ -48,7 +50,6 @@ extern crate libimagstore;
|
||||||
pub mod category;
|
pub mod category;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
pub mod result;
|
|
||||||
|
|
||||||
module_entry_path_mod!("category");
|
module_entry_path_mod!("category");
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,12 @@ use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use category::Category;
|
use category::Category;
|
||||||
use error::CategoryErrorKind as CEK;
|
use error::CategoryErrorKind as CEK;
|
||||||
use error::MapErrInto;
|
use error::CategoryError as CE;
|
||||||
use result::Result;
|
use error::ResultExt;
|
||||||
|
use error::Result;
|
||||||
|
|
||||||
pub const CATEGORY_REGISTER_NAME_FIELD_PATH : &'static str = "category.register.name";
|
pub const CATEGORY_REGISTER_NAME_FIELD_PATH : &'static str = "category.register.name";
|
||||||
|
|
||||||
|
@ -81,13 +81,13 @@ impl CategoryRegister for Store {
|
||||||
warn!("Setting category header replaced existing value: {:?}", opt);
|
warn!("Setting category header replaced existing value: {:?}", opt);
|
||||||
})
|
})
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
.map_err_into(CEK::HeaderWriteError)
|
.chain_err(|| CEK::HeaderWriteError)
|
||||||
.map_err_into(CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
Err(store_error) => if is_match!(store_error.err_type(), SEK::EntryAlreadyExists) {
|
Err(store_error) => if is_match!(store_error.kind(), &SEK::EntryAlreadyExists) {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
} else {
|
} else {
|
||||||
Err(store_error).map_err_into(CEK::StoreWriteError)
|
Err(store_error).chain_err(|| CEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,13 +96,13 @@ impl CategoryRegister for Store {
|
||||||
fn delete_category(&self, name: &str) -> Result<()> {
|
fn delete_category(&self, name: &str) -> Result<()> {
|
||||||
let sid = try!(mk_category_storeid(self.path().clone(), name));
|
let sid = try!(mk_category_storeid(self.path().clone(), name));
|
||||||
|
|
||||||
self.delete(sid).map_err_into(CEK::StoreWriteError)
|
self.delete(sid).chain_err(|| CEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all category names
|
/// Get all category names
|
||||||
fn all_category_names(&self) -> Result<CategoryNameIter> {
|
fn all_category_names(&self) -> Result<CategoryNameIter> {
|
||||||
self.retrieve_for_module("category")
|
self.retrieve_for_module("category")
|
||||||
.map_err_into(CEK::StoreReadError)
|
.chain_err(|| CEK::StoreReadError)
|
||||||
.map(|iter| CategoryNameIter::new(self, iter))
|
.map(|iter| CategoryNameIter::new(self, iter))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ impl CategoryRegister for Store {
|
||||||
let sid = try!(mk_category_storeid(self.path().clone(), name));
|
let sid = try!(mk_category_storeid(self.path().clone(), name));
|
||||||
|
|
||||||
self.get(sid)
|
self.get(sid)
|
||||||
.map_err_into(CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,26 +212,26 @@ fn mk_category_storeid(base: PathBuf, s: &str) -> Result<StoreId> {
|
||||||
::module_path::ModuleEntryPath::new(s)
|
::module_path::ModuleEntryPath::new(s)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map(|id| id.with_base(base))
|
.map(|id| id.with_base(base))
|
||||||
.map_err_into(CEK::StoreIdHandlingError)
|
.chain_err(|| CEK::StoreIdHandlingError)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn represents_category(store: &Store, sid: StoreId, name: &str) -> Result<bool> {
|
fn represents_category(store: &Store, sid: StoreId, name: &str) -> Result<bool> {
|
||||||
sid.exists()
|
sid.exists()
|
||||||
.map_err_into(CEK::StoreIdHandlingError)
|
.chain_err(|| CEK::StoreIdHandlingError)
|
||||||
.and_then(|bl| {
|
.and_then(|bl| {
|
||||||
if bl {
|
if bl {
|
||||||
store.get(sid)
|
store.get(sid)
|
||||||
.map_err_into(CEK::StoreReadError)
|
.chain_err(|| CEK::StoreReadError)
|
||||||
.and_then(|fle| {
|
.and_then(|fle| {
|
||||||
if let Some(fle) = fle {
|
if let Some(fle) = fle {
|
||||||
match fle.get_header()
|
match fle.get_header()
|
||||||
.read(&String::from(CATEGORY_REGISTER_NAME_FIELD_PATH))
|
.read(&String::from(CATEGORY_REGISTER_NAME_FIELD_PATH))
|
||||||
.map_err_into(CEK::HeaderReadError)
|
.chain_err(|| CEK::HeaderReadError)
|
||||||
{
|
{
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(s == name),
|
Ok(Some(&Value::String(ref s))) => Ok(s == name),
|
||||||
Ok(_) => Err(CEK::TypeError.into_error()),
|
Ok(_) => Err(CE::from_kind(CEK::TypeError)),
|
||||||
Err(e) => Err(e).map_err_into(CEK::HeaderReadError),
|
Err(e) => Err(e).chain_err(|| CEK::HeaderReadError),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
@ -277,12 +277,12 @@ impl<'a> Iterator for CategoryNameIter<'a> {
|
||||||
.map(|sid| {
|
.map(|sid| {
|
||||||
self.0
|
self.0
|
||||||
.get(sid)
|
.get(sid)
|
||||||
.map_err_into(CEK::StoreReadError)
|
.chain_err(|| CEK::StoreReadError)
|
||||||
.and_then(|fle| fle.ok_or(CEK::StoreReadError.into_error()))
|
.and_then(|fle| fle.ok_or(CE::from_kind(CEK::StoreReadError)))
|
||||||
.and_then(|fle| match fle.get_header().read(&query) {
|
.and_then(|fle| match fle.get_header().read(&query) {
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(Category::from(s.clone())),
|
Ok(Some(&Value::String(ref s))) => Ok(Category::from(s.clone())),
|
||||||
Ok(_) => Err(CEK::TypeError.into_error()),
|
Ok(_) => Err(CE::from_kind(CEK::TypeError)),
|
||||||
Err(e) => Err(e).map_err_into(CEK::HeaderReadError),
|
Err(e) => Err(e).chain_err(|| CEK::HeaderReadError),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
|
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::CategoryError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, CategoryError>;
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ chrono = "0.4"
|
||||||
toml-query = "0.3"
|
toml-query = "0.3"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
|
error-chain = "0.10"
|
||||||
|
|
||||||
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
|
||||||
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
|
@ -27,9 +27,9 @@ use libimagstore::storeid::StoreId;
|
||||||
|
|
||||||
use datepath::accuracy::Accuracy;
|
use datepath::accuracy::Accuracy;
|
||||||
use datepath::format::Format;
|
use datepath::format::Format;
|
||||||
use datepath::result::Result;
|
use datepath::error::Result;
|
||||||
use datepath::error::DatePathCompilerErrorKind as DPCEK;
|
use datepath::error::DatePathCompilerErrorKind as DPCEK;
|
||||||
use datepath::error::MapErrInto;
|
use datepath::error::ResultExt;
|
||||||
|
|
||||||
pub struct DatePathCompiler {
|
pub struct DatePathCompiler {
|
||||||
accuracy : Accuracy,
|
accuracy : Accuracy,
|
||||||
|
@ -122,7 +122,7 @@ impl DatePathCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreId::new_baseless(PathBuf::from(s))
|
StoreId::new_baseless(PathBuf::from(s))
|
||||||
.map_err_into(DPCEK::StoreIdBuildFailed)
|
.chain_err(|| DPCEK::StoreIdBuildFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,22 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
/// Error module for the DatePathCompiler type
|
error_chain! {
|
||||||
generate_error_module! {
|
types {
|
||||||
generate_error_types!(DatePathCompilerError, DatePathCompilerErrorKind,
|
DatePathCompilerError, DatePathCompilerErrorKind, ResultExt, Result;
|
||||||
UnknownDatePathCompilerError => "Unknown DatePathCompiler error",
|
}
|
||||||
StoreIdBuildFailed => "Failed building StoreId object"
|
|
||||||
);
|
errors {
|
||||||
}
|
UnknownDatePathCompilerError {
|
||||||
pub use self::error::DatePathCompilerError;
|
description("Unknown DatePathCompiler error")
|
||||||
pub use self::error::DatePathCompilerErrorKind;
|
display("Unknown DatePathCompiler error")
|
||||||
pub use self::error::MapErrInto;
|
}
|
||||||
|
|
||||||
|
StoreIdBuildFailed {
|
||||||
|
description("Failed building StoreId object")
|
||||||
|
display("Failed building StoreId object")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,5 @@ pub mod accuracy;
|
||||||
pub mod compiler;
|
pub mod compiler;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
pub mod result;
|
|
||||||
pub mod to_store_id;
|
pub mod to_store_id;
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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
|
|
||||||
//
|
|
||||||
|
|
||||||
/// Result type for this module.
|
|
||||||
use super::error::DatePathCompilerError as DPCE;
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, DPCE>;
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
use chrono::naive::NaiveDateTime;
|
use chrono::naive::NaiveDateTime;
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use datepath::result::Result;
|
use datepath::error::Result;
|
||||||
use datepath::compiler::DatePathCompiler;
|
use datepath::compiler::DatePathCompiler;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -24,11 +24,10 @@ use toml_query::read::TomlValueReadExt;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use error::DateErrorKind as DEK;
|
use error::DateErrorKind as DEK;
|
||||||
|
use error::DateError as DE;
|
||||||
use error::*;
|
use error::*;
|
||||||
use result::Result;
|
|
||||||
use range::DateTimeRange;
|
use range::DateTimeRange;
|
||||||
|
|
||||||
pub trait EntryDate {
|
pub trait EntryDate {
|
||||||
|
@ -56,19 +55,19 @@ impl EntryDate for Entry {
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.delete(&DATE_HEADER_LOCATION)
|
.delete(&DATE_HEADER_LOCATION)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err_into(DEK::DeleteDateError)
|
.chain_err(|| DEK::DeleteDateError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_date(&self) -> Result<NaiveDateTime> {
|
fn read_date(&self) -> Result<NaiveDateTime> {
|
||||||
self.get_header()
|
self.get_header()
|
||||||
.read(&DATE_HEADER_LOCATION)
|
.read(&DATE_HEADER_LOCATION)
|
||||||
.map_err_into(DEK::ReadDateError)
|
.chain_err(|| DEK::ReadDateError)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
match v {
|
match v {
|
||||||
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
|
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
|
||||||
.map_err_into(DEK::DateTimeParsingError),
|
.chain_err(|| DEK::DateTimeParsingError),
|
||||||
Some(_) => Err(DEK::DateHeaderFieldTypeError.into_error()),
|
Some(_) => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
|
||||||
_ => Err(DEK::ReadDateError.into_error()),
|
_ => Err(DE::from_kind(DEK::ReadDateError)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -97,11 +96,11 @@ impl EntryDate for Entry {
|
||||||
.map(|opt| opt.map(|stri| {
|
.map(|opt| opt.map(|stri| {
|
||||||
match stri {
|
match stri {
|
||||||
Value::String(ref s) => s.parse::<NaiveDateTime>()
|
Value::String(ref s) => s.parse::<NaiveDateTime>()
|
||||||
.map_err_into(DEK::DateTimeParsingError),
|
.chain_err(|| DEK::DateTimeParsingError),
|
||||||
_ => Err(DEK::DateHeaderFieldTypeError.into_error()),
|
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.map_err_into(DEK::SetDateError)
|
.chain_err(|| DEK::SetDateError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,43 +116,43 @@ impl EntryDate for Entry {
|
||||||
.get_header_mut()
|
.get_header_mut()
|
||||||
.delete(&DATE_RANGE_START_HEADER_LOCATION)
|
.delete(&DATE_RANGE_START_HEADER_LOCATION)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err_into(DEK::DeleteDateTimeRangeError));
|
.chain_err(|| DEK::DeleteDateTimeRangeError));
|
||||||
|
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.delete(&DATE_RANGE_END_HEADER_LOCATION)
|
.delete(&DATE_RANGE_END_HEADER_LOCATION)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err_into(DEK::DeleteDateTimeRangeError)
|
.chain_err(|| DEK::DeleteDateTimeRangeError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_date_range(&self) -> Result<DateTimeRange> {
|
fn read_date_range(&self) -> Result<DateTimeRange> {
|
||||||
let start = try!(self
|
let start = try!(self
|
||||||
.get_header()
|
.get_header()
|
||||||
.read(&DATE_RANGE_START_HEADER_LOCATION)
|
.read(&DATE_RANGE_START_HEADER_LOCATION)
|
||||||
.map_err_into(DEK::ReadDateTimeRangeError)
|
.chain_err(|| DEK::ReadDateTimeRangeError)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
match v {
|
match v {
|
||||||
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
|
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
|
||||||
.map_err_into(DEK::DateTimeParsingError),
|
.chain_err(|| DEK::DateTimeParsingError),
|
||||||
Some(_) => Err(DEK::DateHeaderFieldTypeError.into_error()),
|
Some(_) => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
|
||||||
_ => Err(DEK::ReadDateError.into_error()),
|
_ => Err(DE::from_kind(DEK::ReadDateError)),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let end = try!(self
|
let end = try!(self
|
||||||
.get_header()
|
.get_header()
|
||||||
.read(&DATE_RANGE_START_HEADER_LOCATION)
|
.read(&DATE_RANGE_START_HEADER_LOCATION)
|
||||||
.map_err_into(DEK::ReadDateTimeRangeError)
|
.chain_err(|| DEK::ReadDateTimeRangeError)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
match v {
|
match v {
|
||||||
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
|
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
|
||||||
.map_err_into(DEK::DateTimeParsingError),
|
.chain_err(|| DEK::DateTimeParsingError),
|
||||||
Some(_) => Err(DEK::DateHeaderFieldTypeError.into_error()),
|
Some(_) => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
|
||||||
_ => Err(DEK::ReadDateError.into_error()),
|
_ => Err(DE::from_kind(DEK::ReadDateError)),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
DateTimeRange::new(start, end)
|
DateTimeRange::new(start, end)
|
||||||
.map_err_into(DEK::DateTimeRangeError)
|
.chain_err(|| DEK::DateTimeRangeError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the date range
|
/// Set the date range
|
||||||
|
@ -175,11 +174,11 @@ impl EntryDate for Entry {
|
||||||
.map(|opt| opt.map(|stri| {
|
.map(|opt| opt.map(|stri| {
|
||||||
match stri {
|
match stri {
|
||||||
Value::String(ref s) => s.parse::<NaiveDateTime>()
|
Value::String(ref s) => s.parse::<NaiveDateTime>()
|
||||||
.map_err_into(DEK::DateTimeParsingError),
|
.chain_err(|| DEK::DateTimeParsingError),
|
||||||
_ => Err(DEK::DateHeaderFieldTypeError.into_error()),
|
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.map_err_into(DEK::SetDateTimeRangeError));
|
.chain_err(|| DEK::SetDateTimeRangeError));
|
||||||
|
|
||||||
let opt_old_end = try!(self
|
let opt_old_end = try!(self
|
||||||
.get_header_mut()
|
.get_header_mut()
|
||||||
|
@ -187,16 +186,16 @@ impl EntryDate for Entry {
|
||||||
.map(|opt| opt.map(|stri| {
|
.map(|opt| opt.map(|stri| {
|
||||||
match stri {
|
match stri {
|
||||||
Value::String(ref s) => s.parse::<NaiveDateTime>()
|
Value::String(ref s) => s.parse::<NaiveDateTime>()
|
||||||
.map_err_into(DEK::DateTimeParsingError),
|
.chain_err(|| DEK::DateTimeParsingError),
|
||||||
_ => Err(DEK::DateHeaderFieldTypeError.into_error()),
|
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.map_err_into(DEK::SetDateTimeRangeError));
|
.chain_err(|| DEK::SetDateTimeRangeError));
|
||||||
|
|
||||||
match (opt_old_start, opt_old_end) {
|
match (opt_old_start, opt_old_end) {
|
||||||
(Some(Ok(old_start)), Some(Ok(old_end))) => {
|
(Some(Ok(old_start)), Some(Ok(old_end))) => {
|
||||||
let dr = DateTimeRange::new(old_start, old_end)
|
let dr = DateTimeRange::new(old_start, old_end)
|
||||||
.map_err_into(DEK::DateTimeRangeError);
|
.chain_err(|| DEK::DateTimeRangeError);
|
||||||
|
|
||||||
Ok(Some(dr))
|
Ok(Some(dr))
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,23 +17,61 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
generate_error_module!(
|
error_chain! {
|
||||||
generate_error_types!(DateError, DateErrorKind,
|
types {
|
||||||
DeleteDateError => "Error deleting date",
|
DateError, DateErrorKind, ResultExt, Result;
|
||||||
ReadDateError => "Error reading date",
|
}
|
||||||
SetDateError => "Error setting date",
|
|
||||||
DeleteDateTimeRangeError => "Error deleting date-time range",
|
|
||||||
ReadDateTimeRangeError => "Error reading date-time range",
|
|
||||||
SetDateTimeRangeError => "Error setting date-time range",
|
|
||||||
|
|
||||||
DateTimeRangeError => "DateTime Range error",
|
errors {
|
||||||
|
DeleteDateError {
|
||||||
|
description("Error deleting date")
|
||||||
|
display("Error deleting date")
|
||||||
|
}
|
||||||
|
|
||||||
DateHeaderFieldTypeError => "Expected the header field in the entry to have type 'String', but have other type",
|
ReadDateError {
|
||||||
DateTimeParsingError => "Error parsing DateTime"
|
description("Error reading date")
|
||||||
);
|
display("Error reading date")
|
||||||
);
|
}
|
||||||
|
|
||||||
pub use self::error::DateError;
|
SetDateError {
|
||||||
pub use self::error::DateErrorKind;
|
description("Error setting date")
|
||||||
pub use self::error::MapErrInto;
|
display("Error setting date")
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteDateTimeRangeError {
|
||||||
|
description("Error deleting date-time range")
|
||||||
|
display("Error deleting date-time range")
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadDateTimeRangeError {
|
||||||
|
description("Error reading date-time range")
|
||||||
|
display("Error reading date-time range")
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDateTimeRangeError {
|
||||||
|
description("Error setting date-time range")
|
||||||
|
display("Error setting date-time range")
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeRangeError {
|
||||||
|
description("DateTime Range error")
|
||||||
|
display("DateTime Range error")
|
||||||
|
}
|
||||||
|
|
||||||
|
DateHeaderFieldTypeError {
|
||||||
|
description("Expected the header field in the entry to have type 'String', but have other type")
|
||||||
|
display("Expected the header field in the entry to have type 'String', but have other type")
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeParsingError {
|
||||||
|
description("Error parsing DateTime")
|
||||||
|
display("Error parsing DateTime")
|
||||||
|
}
|
||||||
|
|
||||||
|
EndDateTimeBeforeStartDateTime {
|
||||||
|
description("End datetime is before start datetime")
|
||||||
|
display("End datetime is before start datetime")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue