Merge branch 'error-context' into master

This commit is contained in:
Matthias Beyer 2019-05-18 00:55:20 +02:00
commit 85f8082cbe
39 changed files with 177 additions and 65 deletions

View file

@ -370,6 +370,7 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
for (module_name, v) in t { for (module_name, v) in t {
let destinations = inner_try! { let destinations = inner_try! {
v.read("destinations") v.read("destinations")
.context("Failed reading header 'destinations'")
.map_err(Error::from) .map_err(Error::from)
.context(EM::TomlQueryError)? .context(EM::TomlQueryError)?
.map(|val| { .map(|val| {
@ -384,6 +385,7 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
let level = inner_try! { let level = inner_try! {
v.read_string("level") v.read_string("level")
.context("Failed reading header 'level'")
.map_err(Error::from) .map_err(Error::from)
.context(EM::TomlQueryError)? .context(EM::TomlQueryError)?
.map(|s| match_log_level_str(&s)) .map(|s| match_log_level_str(&s))

View file

@ -408,6 +408,7 @@ impl<'a> Runtime<'a> {
let mut buf = String::new(); let mut buf = String::new();
lock.read_to_string(&mut buf) lock.read_to_string(&mut buf)
.context("Failed to read stdin to buffer")
.map_err(Error::from) .map_err(Error::from)
.and_then(|_| { .and_then(|_| {
trace!("Got IDs = {}", buf); trace!("Got IDs = {}", buf);

View file

@ -34,6 +34,7 @@ pub fn config_implicit_store_create_allowed(config: &Option<Value>) -> Result<bo
if let Some(ref t) = *config { if let Some(ref t) = *config {
t.read_bool(key) t.read_bool(key)
.context(format_err!("Error reading header '{}' in configuration", key))
.map_err(Error::from) .map_err(Error::from)
.context(EM::TomlQueryError)? .context(EM::TomlQueryError)?
.ok_or_else(|| format_err!("Config key missing: {}", key)) .ok_or_else(|| format_err!("Config key missing: {}", key))

View file

@ -184,6 +184,9 @@ impl<'a> StoreIdWithBase<'a> {
store_part.display()); store_part.display());
let p = full_path let p = full_path
.strip_prefix(store_part) .strip_prefix(store_part)
.context(format_err!("Cannot strip prefix '{}' from path: '{}'",
store_part.display(),
full_path.display()))
.map_err(Error::from) .map_err(Error::from)
.context(err_msg("Error building Store Id from full path"))?; .context(err_msg("Error building Store Id from full path"))?;
Ok(StoreIdWithBase(store_part, PathBuf::from(p))) Ok(StoreIdWithBase(store_part, PathBuf::from(p)))

View file

@ -27,6 +27,7 @@
use regex::Regex; use regex::Regex;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use libimagstore::store::Store; use libimagstore::store::Store;
@ -52,19 +53,28 @@ impl<'a> BookmarkCollectionStore<'a> for Store {
fn new(&'a self, name: &str) -> Result<FileLockEntry<'a>> { fn new(&'a self, name: &str) -> Result<FileLockEntry<'a>> {
crate::module_path::new_id(name) crate::module_path::new_id(name)
.and_then(|id| self.create(id).map_err(Error::from)) .and_then(|id| self.create(id)
.context("Failed to create FileLockEntry")
.map_err(Error::from))
.context("Failed to create Id for new Bookmark Collection")
.map_err(Error::from) .map_err(Error::from)
} }
fn get(&'a self, name: &str) -> Result<Option<FileLockEntry<'a>>> { fn get(&'a self, name: &str) -> Result<Option<FileLockEntry<'a>>> {
crate::module_path::new_id(name) crate::module_path::new_id(name)
.and_then(|id| self.get(id).map_err(Error::from)) .and_then(|id| self.get(id)
.context("Failed to get FileLockEntry")
.map_err(Error::from))
.context("Failed to get Bookmark Collection")
.map_err(Error::from) .map_err(Error::from)
} }
fn delete(&'a self, name: &str) -> Result<()> { fn delete(&'a self, name: &str) -> Result<()> {
crate::module_path::new_id(name) crate::module_path::new_id(name)
.and_then(|id| self.delete(id).map_err(Error::from)) .and_then(|id| self.delete(id)
.context("Failed to delete FileLockEntry")
.map_err(Error::from))
.context("Failed to delete Bookmark Collection")
.map_err(Error::from) .map_err(Error::from)
} }

View file

@ -25,6 +25,7 @@ use libimagerror::errors::ErrorMsg as EM;
use crate::contact::Contact; use crate::contact::Contact;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::Error; use failure::Error;
use failure::ResultExt;
pub struct ContactIter<'a>(StoreIdIterator, &'a Store); pub struct ContactIter<'a>(StoreIdIterator, &'a Store);
@ -44,12 +45,21 @@ impl<'a> Iterator for ContactIter<'a> {
loop { loop {
match self.0.next() { match self.0.next() {
None => return None, None => return None,
Some(Err(e)) => return Some(Err(e).map_err(Error::from)), Some(Err(e)) => {
let e = Err(e)
.context("Found error while iterating over contacts")
.map_err(Error::from);
return Some(e)
},
Some(Ok(sid)) => match self.1.get(sid.clone()).map_err(From::from) { Some(Ok(sid)) => match self.1.get(sid.clone()).map_err(From::from) {
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
Ok(None) => return Ok(None) => return
Some(Err(Error::from(EM::EntryNotFound(sid.local_display_string())))), Some(Err(Error::from(EM::EntryNotFound(sid.local_display_string())))),
Ok(Some(entry)) => match entry.is_contact().map_err(Error::from) { Ok(Some(entry)) => match entry.is_contact()
.context("Cannot check whether entry is a contact")
.map_err(Error::from)
{
Ok(true) => return Some(Ok(entry)), Ok(true) => return Some(Ok(entry)),
Ok(false) => continue, Ok(false) => continue,
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),

View file

@ -27,6 +27,7 @@ use toml_query::insert::TomlValueInsertExt;
use vobject::vcard::Vcard; use vobject::vcard::Vcard;
use failure::Error; use failure::Error;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::iter::Entries; use libimagstore::iter::Entries;
@ -152,7 +153,7 @@ impl<'a> ContactStore<'a> for Store {
/// ///
/// That means calculating the StoreId and the Value from the vcard data /// That means calculating the StoreId and the Value from the vcard data
fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> { fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
let vcard = Vcard::build(&buf).map_err(Error::from)?; let vcard = Vcard::build(&buf).context("Cannot parse Vcard").map_err(Error::from)?;
debug!("Parsed: {:?}", vcard); debug!("Parsed: {:?}", vcard);
let uid = vcard.uid() let uid = vcard.uid()

View file

@ -30,6 +30,7 @@ use itertools::Itertools;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use chrono::Timelike; use chrono::Timelike;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use crate::entry::IsDiaryEntry; use crate::entry::IsDiaryEntry;
@ -141,6 +142,7 @@ impl Diary for Store {
fn diary_names(&self) -> Result<DiaryNameIterator> { fn diary_names(&self) -> Result<DiaryNameIterator> {
self.entries() self.entries()
.map(|it| DiaryNameIterator::new(it.into_storeid_iter())) .map(|it| DiaryNameIterator::new(it.into_storeid_iter()))
.context("Failed building DiaryNameIteator from entries iterator")
.map_err(Error::from) .map_err(Error::from)
} }

View file

@ -234,6 +234,7 @@ impl FromStoreId for DiaryId {
let day: Result<u32> = next_component(&mut cmps) let day: Result<u32> = next_component(&mut cmps)
.and_then(|s| { .and_then(|s| {
s.parse::<u32>() s.parse::<u32>()
.context("Failed to parse day from u32")
.map_err(Error::from) .map_err(Error::from)
.context(err_msg("ID parse error")) .context(err_msg("ID parse error"))
.map_err(Error::from) .map_err(Error::from)
@ -242,6 +243,7 @@ impl FromStoreId for DiaryId {
let month: Result<u32> = next_component(&mut cmps) let month: Result<u32> = next_component(&mut cmps)
.and_then(|s| { .and_then(|s| {
s.parse::<u32>() s.parse::<u32>()
.context("Failed to parse month from u32")
.map_err(Error::from) .map_err(Error::from)
.context(err_msg("ID Parse error")) .context(err_msg("ID Parse error"))
.map_err(Error::from) .map_err(Error::from)
@ -250,6 +252,7 @@ impl FromStoreId for DiaryId {
let year: Result<i32> = next_component(&mut cmps) let year: Result<i32> = next_component(&mut cmps)
.and_then(|s| { .and_then(|s| {
s.parse::<i32>() s.parse::<i32>()
.context("Failed to parse year from i32")
.map_err(Error::from) .map_err(Error::from)
.context(err_msg("ID Parse error")) .context(err_msg("ID Parse error"))
.map_err(Error::from) .map_err(Error::from)

View file

@ -25,6 +25,7 @@ use chrono::Local;
use chrono::NaiveDate; use chrono::NaiveDate;
use failure::Error; use failure::Error;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::err_msg; use failure::err_msg;
use crate::iter::HabitInstanceStoreIdIterator; use crate::iter::HabitInstanceStoreIdIterator;
@ -257,7 +258,9 @@ impl HabitTemplate for Entry {
} }
fn instance_id_for_name_and_datestr(habit_name: &String, habit_date: &String) -> Result<StoreId> { fn instance_id_for_name_and_datestr(habit_name: &String, habit_date: &String) -> Result<StoreId> {
crate::module_path::new_id(format!("instance/{}-{}", habit_name, habit_date)).map_err(Error::from) crate::module_path::new_id(format!("instance/{}-{}", habit_name, habit_date))
.context(format_err!("Failed building ID for instance: habit name = {}, habit date = {}", habit_name, habit_date))
.map_err(Error::from)
} }
pub mod builder { pub mod builder {

View file

@ -19,6 +19,7 @@
use failure::Error; use failure::Error;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagstore::storeid::StoreIdIteratorWithStore; use libimagstore::storeid::StoreIdIteratorWithStore;
@ -33,11 +34,11 @@ impl Iterator for HabitTemplateStoreIdIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(n) = self.0.next() { while let Some(n) = self.0.next() {
match n { match n.context("Error while iterating").map_err(Error::from) {
Ok(n) => if n.is_habit_template() { Ok(n) => if n.is_habit_template() {
return Some(Ok(n)) return Some(Ok(n))
}, },
Err(e) => return Some(Err(e).map_err(Error::from)), Err(e) => return Some(Err(e)),
} }
} }
None None

View file

@ -21,6 +21,7 @@ use std::ops::BitXor;
use failure::Error; use failure::Error;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use crate::habit::HabitTemplate; use crate::habit::HabitTemplate;
use crate::instance::HabitInstance; use crate::instance::HabitInstance;
@ -88,6 +89,7 @@ pub fn get_string_header_from_entry(e: &Entry, path: &'static str) -> Result<Str
e.get_header() e.get_header()
.read_string(path)? .read_string(path)?
.ok_or_else(|| EM::EntryHeaderFieldMissing(path)) .ok_or_else(|| EM::EntryHeaderFieldMissing(path))
.context(format_err!("Error while reading header '{}' from '{}'", path, e.get_location()))
.map_err(Error::from) .map_err(Error::from)
} }

View file

@ -24,6 +24,7 @@ use libimagentryutil::isa::IsKindHeaderPathProvider;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::Error; use failure::Error;
use failure::ResultExt;
use toml::Value; use toml::Value;
@ -38,12 +39,13 @@ provide_kindflag_path!(pub IsLog, "log.is_log");
impl Log for Entry { impl Log for Entry {
fn is_log(&self) -> Result<bool> { fn is_log(&self) -> Result<bool> {
self.is::<IsLog>().map_err(From::from) self.is::<IsLog>().context("Cannot check whether Entry is a Log").map_err(From::from)
} }
fn make_log_entry(&mut self) -> Result<()> { fn make_log_entry(&mut self) -> Result<()> {
self.get_header_mut() self.get_header_mut()
.insert("log.is_log", Value::Boolean(true)) .insert("log.is_log", Value::Boolean(true))
.context("Cannot insert 'log.is_log' into header of entry")
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }

View file

@ -57,12 +57,17 @@ impl Mail for Entry {
.context(format_err!("Cannot parse Email {}", mail_file_location.display()))? .context(format_err!("Cannot parse Email {}", mail_file_location.display()))?
.headers .headers
.into_iter() .into_iter()
.filter_map(|hdr| match hdr.get_key() { .filter_map(|hdr| {
Err(e) => Some(Err(e).map_err(Error::from)), match hdr.get_key()
Ok(k) => if k == field { .context(format_err!("Cannot fetch key '{}' from Email {}", field, mail_file_location.display()))
Some(Ok(hdr)) .map_err(Error::from)
} else { {
None Ok(k) => if k == field {
Some(Ok(hdr))
} else {
None
},
Err(e) => Some(Err(e)),
} }
}) })
.next() .next()
@ -135,12 +140,17 @@ impl<'a> MailHeader<'a> {
pub fn get_field(&self, field: &str) -> Result<Option<String>> { pub fn get_field(&self, field: &str) -> Result<Option<String>> {
match self.0 match self.0
.iter() .iter()
.filter_map(|hdr| match hdr.get_key() { .filter_map(|hdr| {
Err(e) => Some(Err(e).map_err(Error::from)), match hdr.get_key()
Ok(key) => if key == field { .context(format_err!("Cannot get field {}", field))
Some(Ok(hdr)) .map_err(Error::from)
} else { {
None Ok(key) => if key == field {
Some(Ok(hdr))
} else {
None
},
Err(e) => Some(Err(e))
} }
}) })
.next() .next()

View file

@ -39,8 +39,7 @@ pub(crate) fn get_message_header_at_key<P: AsRef<Path>, K: AsRef<str>>(p: P, k:
.context(format_err!("Cannot parse Email {}", p.as_ref().display()))? .context(format_err!("Cannot parse Email {}", p.as_ref().display()))?
.headers .headers
.into_iter() .into_iter()
.filter_map(|hdr| match hdr.get_key() { .filter_map(|hdr| match hdr.get_key().context("Cannot get key from mail header").map_err(Error::from) {
Err(e) => Some(Err(e).map_err(Error::from)),
Ok(key) => { Ok(key) => {
let lower_key = key.to_lowercase(); let lower_key = key.to_lowercase();
trace!("Test: {} == {}", lower_key, k.as_ref()); trace!("Test: {} == {}", lower_key, k.as_ref());
@ -49,11 +48,12 @@ pub(crate) fn get_message_header_at_key<P: AsRef<Path>, K: AsRef<str>>(p: P, k:
} else { } else {
None None
} }
} },
Err(e) => Some(Err(e))
}) })
.next() .next()
.ok_or_else(|| format_err!("'{}' not found in {}", k.as_ref(), p.as_ref().display()))? .ok_or_else(|| format_err!("'{}' not found in {}", k.as_ref(), p.as_ref().display()))?
.and_then(|hdr| hdr.get_value().map_err(Error::from)) .and_then(|hdr| hdr.get_value().context("Cannot get value from mail header").map_err(Error::from))
} }
pub(crate) fn get_message_id_for_mailfile<P: AsRef<Path>>(p: P) -> Result<String> { pub(crate) fn get_message_id_for_mailfile<P: AsRef<Path>>(p: P) -> Result<String> {
@ -77,6 +77,7 @@ pub fn get_mail_text_content<P: AsRef<Path>>(p: P) -> Result<String> {
::mailparse::parse_mail(::std::fs::read_to_string(p.as_ref())?.as_bytes()) ::mailparse::parse_mail(::std::fs::read_to_string(p.as_ref())?.as_bytes())
.context(format_err!("Cannot parse Email {}", p.as_ref().display()))? .context(format_err!("Cannot parse Email {}", p.as_ref().display()))?
.get_body() .get_body()
.context("Cannot get body of mail")
.map_err(Error::from) .map_err(Error::from)
} }

View file

@ -23,6 +23,7 @@ use libimagstore::storeid::StoreIdIterator;
use crate::notestoreid::*; use crate::notestoreid::*;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::Error; use failure::Error;
use failure::ResultExt;
#[derive(Debug)] #[derive(Debug)]
pub struct NoteIterator(StoreIdIterator); pub struct NoteIterator(StoreIdIterator);
@ -40,11 +41,11 @@ impl Iterator for NoteIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(n) = self.0.next() { while let Some(n) = self.0.next() {
match n { match n.context("Error while iterating").map_err(Error::from) {
Ok(n) => if n.is_note_id() { Ok(n) => if n.is_note_id() {
return Some(Ok(n)); return Some(Ok(n));
}, },
Err(e) => return Some(Err(e).map_err(Error::from)), Err(e) => return Some(Err(e)),
} }
} }

View file

@ -27,6 +27,7 @@ use toml_query::set::TomlValueSetExt;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::Error; use failure::Error;
use failure::ResultExt;
pub trait Note { pub trait Note {
fn set_name(&mut self, n: String) -> Result<()>; fn set_name(&mut self, n: String) -> Result<()>;
@ -40,6 +41,7 @@ impl Note for Entry {
fn set_name(&mut self, n: String) -> Result<()> { fn set_name(&mut self, n: String) -> Result<()> {
self.get_header_mut() self.get_header_mut()
.set("note.name", Value::String(n)) .set("note.name", Value::String(n))
.context(format_err!("Cannot set 'note.name' in header of {}", self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }

View file

@ -21,6 +21,7 @@ use toml::Value;
use toml_query::insert::TomlValueInsertExt; use toml_query::insert::TomlValueInsertExt;
use chrono::naive::NaiveDateTime as NDT; use chrono::naive::NaiveDateTime as NDT;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use crate::constants::*; use crate::constants::*;
@ -60,6 +61,7 @@ impl<'a> Iterator for CreateTimeTrackIter<'a>
res.and_then(|(id, starttime)| { res.and_then(|(id, starttime)| {
self.store self.store
.create(id) .create(id)
.context("Failed to create entry")
.map_err(Error::from) .map_err(Error::from)
.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());

View file

@ -37,6 +37,7 @@ use toml_query::delete::TomlValueDeleteExt;
use toml_query::insert::TomlValueInsertExt; use toml_query::insert::TomlValueInsertExt;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
pub trait TimeTracking { pub trait TimeTracking {
@ -64,6 +65,8 @@ 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_string(DATE_TIME_TAG_HEADER_PATH) .read_string(DATE_TIME_TAG_HEADER_PATH)
.context(format_err!("Failed to read header '{}' of {}", DATE_TIME_TAG_HEADER_PATH,
self.get_location()))
.map_err(Error::from)? .map_err(Error::from)?
.ok_or_else(|| Error::from(EM::EntryHeaderReadError)) .ok_or_else(|| Error::from(EM::EntryHeaderReadError))
.map(Into::into) .map(Into::into)
@ -74,6 +77,8 @@ 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))
.context(format_err!("Failed get header '{}' of {}", DATE_TIME_START_HEADER_PATH,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }
@ -81,6 +86,8 @@ impl TimeTracking for Entry {
fn get_start_datetime(&self) -> Result<Option<NaiveDateTime>> { fn get_start_datetime(&self) -> Result<Option<NaiveDateTime>> {
self.get_header() self.get_header()
.read_string(DATE_TIME_START_HEADER_PATH) .read_string(DATE_TIME_START_HEADER_PATH)
.context(format_err!("Failed read header '{}' of {}", DATE_TIME_START_HEADER_PATH,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.and_then(header_value_to_dt) .and_then(header_value_to_dt)
} }
@ -88,6 +95,8 @@ impl TimeTracking for Entry {
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)
.context(format_err!("Failed delete header '{}' of {}", DATE_TIME_START_HEADER_PATH,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }
@ -97,6 +106,8 @@ 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))
.context(format_err!("Failed insert header '{}' in {}", DATE_TIME_END_HEADER_PATH,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }
@ -104,6 +115,8 @@ impl TimeTracking for Entry {
fn get_end_datetime(&self) -> Result<Option<NaiveDateTime>> { fn get_end_datetime(&self) -> Result<Option<NaiveDateTime>> {
self.get_header() self.get_header()
.read_string(DATE_TIME_END_HEADER_PATH) .read_string(DATE_TIME_END_HEADER_PATH)
.context(format_err!("Failed read header '{}' of {}", DATE_TIME_END_HEADER_PATH,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.and_then(header_value_to_dt) .and_then(header_value_to_dt)
} }
@ -111,6 +124,8 @@ impl TimeTracking for Entry {
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)
.context(format_err!("Failed delete header '{}' of {}", DATE_TIME_END_HEADER_PATH,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }
@ -135,7 +150,10 @@ impl TimeTracking for Entry {
fn header_value_to_dt(val: Option<String>) -> Result<Option<NaiveDateTime>> { fn header_value_to_dt(val: Option<String>) -> Result<Option<NaiveDateTime>> {
match val { match val {
Some(ref s) => NaiveDateTime::parse_from_str(s, DATE_TIME_FORMAT).map_err(Error::from).map(Some), Some(ref s) => NaiveDateTime::parse_from_str(s, DATE_TIME_FORMAT)
.context(format_err!("Failed to parse '{}' datetime with format '{}'",
s, DATE_TIME_FORMAT))
.map_err(Error::from).map(Some),
None => Ok(None), None => Ok(None),
} }
} }

View file

@ -26,6 +26,7 @@ use chrono::NaiveDateTime as NDT;
use toml::Value; use toml::Value;
use toml_query::insert::TomlValueInsertExt; use toml_query::insert::TomlValueInsertExt;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use libimagstore::store::Store; use libimagstore::store::Store;
@ -70,6 +71,8 @@ impl<'a> TimeTrackStore<'a> for Store {
use std::path::PathBuf; use std::path::PathBuf;
COMPILER.compile(CRATE_NAME, start) COMPILER.compile(CRATE_NAME, start)
.context(format_err!("Failed to compile DatePath for crate '{}' with start = '{}'",
CRATE_NAME, start))
.map_err(Error::from) .map_err(Error::from)
.map(|mut id| { .map(|mut id| {
id.local_push(PathBuf::from(ts.as_str())); id.local_push(PathBuf::from(ts.as_str()));

View file

@ -27,6 +27,7 @@ use libimagentrylink::internal::InternalLinker;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::Error; use failure::Error;
use failure::err_msg; use failure::err_msg;
use failure::ResultExt;
pub struct Wiki<'a, 'b>(&'a Store, &'b str); pub struct Wiki<'a, 'b>(&'a Store, &'b str);
@ -58,6 +59,7 @@ impl<'a, 'b> Wiki<'a, 'b> {
self.0 self.0
.get(sid) .get(sid)
.context("Cannot get ID from store")
.map_err(Error::from)? .map_err(Error::from)?
.ok_or_else(|| Error::from(err_msg("Missing index"))) .ok_or_else(|| Error::from(err_msg("Missing index")))
} }

View file

@ -27,6 +27,7 @@ use libimagentrylink::internal::InternalLinker;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use failure::err_msg; use failure::err_msg;
use crate::store::CATEGORY_REGISTER_NAME_FIELD_PATH; use crate::store::CATEGORY_REGISTER_NAME_FIELD_PATH;
@ -49,6 +50,7 @@ impl Category for Entry {
trace!("Getting category name of '{:?}'", self.get_location()); trace!("Getting category name of '{:?}'", self.get_location());
self.get_header() self.get_header()
.read_string(CATEGORY_REGISTER_NAME_FIELD_PATH) .read_string(CATEGORY_REGISTER_NAME_FIELD_PATH)
.context(format_err!("Failed to read header at '{}'", CATEGORY_REGISTER_NAME_FIELD_PATH))
.map_err(Error::from)? .map_err(Error::from)?
.ok_or_else(|| Error::from(err_msg("Category name missing"))) .ok_or_else(|| Error::from(err_msg("Category name missing")))
} }

View file

@ -52,7 +52,7 @@ impl EntryCategory for Entry {
trace!("Setting category '{}' UNCHECKED", s); trace!("Setting category '{}' UNCHECKED", s);
self.get_header_mut() self.get_header_mut()
.insert(&String::from("category.value"), Value::String(s.to_string())) .insert(&String::from("category.value"), Value::String(s.to_string()))
.map_err(Error::from) .context(format_err!("Failed to insert header at 'category.value' of '{}'", self.get_location()))
.context(EM::EntryHeaderWriteError) .context(EM::EntryHeaderWriteError)
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
@ -84,7 +84,7 @@ impl EntryCategory for Entry {
trace!("Has category? '{}'", self.get_location()); trace!("Has category? '{}'", self.get_location());
self.get_header() self.get_header()
.read("category.value") .read("category.value")
.map_err(Error::from) .context(format_err!("Failed to read header at 'category.value' of '{}'", self.get_location()))
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)
.map_err(Error::from) .map_err(Error::from)
.map(|x| x.is_some()) .map(|x| x.is_some())
@ -101,7 +101,7 @@ impl EntryCategory for Entry {
self.get_header_mut() self.get_header_mut()
.delete("category.value") .delete("category.value")
.map_err(Error::from) .context(format_err!("Failed to delete header at 'category.value' of '{}'", self.get_location()))
.context(EM::EntryHeaderWriteError) .context(EM::EntryHeaderWriteError)
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())

View file

@ -20,7 +20,6 @@
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagerror::errors::ErrorMsg as EM;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
@ -60,8 +59,8 @@ impl<'a> Iterator for CategoryNameIter<'a> {
let query = CATEGORY_REGISTER_NAME_FIELD_PATH; let query = CATEGORY_REGISTER_NAME_FIELD_PATH;
while let Some(sid) = self.1.next() { while let Some(sid) = self.1.next() {
match sid { match sid.context("Error while iterating over category names").map_err(Error::from) {
Err(e) => return Some(Err(e).map_err(Error::from)), Err(e) => return Some(Err(e)),
Ok(sid) => { Ok(sid) => {
if sid.is_in_collection(&["category"]) { if sid.is_in_collection(&["category"]) {
let func = |store: &Store| { // hack for returning Some(Result<_, _>) let func = |store: &Store| { // hack for returning Some(Result<_, _>)
@ -70,8 +69,7 @@ impl<'a> Iterator for CategoryNameIter<'a> {
.ok_or_else(|| err_msg("Store read error"))? .ok_or_else(|| err_msg("Store read error"))?
.get_header() .get_header()
.read_string(query) .read_string(query)
.map_err(Error::from) .context(format_err!("Failed to read header at '{}'", query))?
.context(EM::EntryHeaderReadError)?
.ok_or_else(|| err_msg("Store read error")) .ok_or_else(|| err_msg("Store read error"))
.map_err(Error::from) .map_err(Error::from)
}; };
@ -99,8 +97,8 @@ impl<'a> Iterator for CategoryEntryIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(next) = self.1.next() { while let Some(next) = self.1.next() {
match next { match next.context("Error while iterating over category entries").map_err(Error::from) {
Err(e) => return Some(Err(e).map_err(Error::from)), Err(e) => return Some(Err(e)),
Ok(next) => { Ok(next) => {
let getter = |next| -> Result<(String, FileLockEntry<'a>)> { let getter = |next| -> Result<(String, FileLockEntry<'a>)> {
let entry = self.0 let entry = self.0

View file

@ -92,6 +92,9 @@ impl EntryDate for Entry {
self.get_header_mut() self.get_header_mut()
.insert(&DATE_HEADER_LOCATION, Value::String(date)) .insert(&DATE_HEADER_LOCATION, Value::String(date))
.context(format_err!("Failed to insert header '{}' in '{}'",
*DATE_HEADER_LOCATION,
self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|opt| opt.map(|stri| { .map(|opt| opt.map(|stri| {
stri.as_str() stri.as_str()

View file

@ -38,10 +38,10 @@
)] )]
#[macro_use] extern crate lazy_static; #[macro_use] extern crate lazy_static;
#[macro_use] extern crate failure;
extern crate chrono; extern crate chrono;
extern crate toml_query; extern crate toml_query;
extern crate toml; extern crate toml;
extern crate failure;
extern crate libimagerror; extern crate libimagerror;
extern crate libimagstore; extern crate libimagstore;

View file

@ -66,7 +66,9 @@ impl EditHeader for Entry {
fn edit_header_and_content(&mut self, rt: &Runtime) -> Result<()> { fn edit_header_and_content(&mut self, rt: &Runtime) -> Result<()> {
let mut header_and_content = self.to_str()?; let mut header_and_content = self.to_str()?;
let _ = edit_in_tmpfile(rt, &mut header_and_content)?; let _ = edit_in_tmpfile(rt, &mut header_and_content)?;
self.replace_from_buffer(&header_and_content).map_err(Error::from) self.replace_from_buffer(&header_and_content)
.context("Failed to replace header and content from buffer")
.map_err(Error::from)
} }
} }

View file

@ -23,6 +23,7 @@ use toml_query::read::TomlValueReadExt;
use filters::failable::filter::FailableFilter; use filters::failable::filter::FailableFilter;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use crate::builtin::header::field_path::FieldPath; use crate::builtin::header::field_path::FieldPath;
@ -47,6 +48,9 @@ impl FailableFilter<Entry> for FieldExists {
fn filter(&self, e: &Entry) -> Result<bool> { fn filter(&self, e: &Entry) -> Result<bool> {
e.get_header() e.get_header()
.read(&self.header_field_path[..]) .read(&self.header_field_path[..])
.context(format_err!("Failed reading header '{}' in '{}'",
self.header_field_path,
e.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|o| o.is_some()) .map(|o| o.is_some())
} }

View file

@ -40,7 +40,7 @@ extern crate regex;
extern crate semver; extern crate semver;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate failure; #[macro_use] extern crate failure;
extern crate libimagstore; extern crate libimagstore;
extern crate libimagentrytag; extern crate libimagentrytag;

View file

@ -60,11 +60,16 @@ impl GPSEntry for Entry {
self.get_header_mut() self.get_header_mut()
.insert("gps.coordinates", c.into()) .insert("gps.coordinates", c.into())
.map(|_| ()) .map(|_| ())
.context(format_err!("Error while inserting header 'gps.coordinates' in '{}'", self.get_location()))
.map_err(Error::from) .map_err(Error::from)
} }
fn get_coordinates(&self) -> Result<Option<Coordinates>> { fn get_coordinates(&self) -> Result<Option<Coordinates>> {
match self.get_header().read("gps.coordinates").map_err(Error::from)? { match self
.get_header()
.read("gps.coordinates")
.context(format_err!("Error while reading header 'gps.coordinates' in '{}'", self.get_location()))?
{
Some(hdr) => Coordinates::from_value(hdr).map(Some), Some(hdr) => Coordinates::from_value(hdr).map(Some),
None => Ok(None), None => Ok(None),
} }
@ -89,7 +94,7 @@ impl GPSEntry for Entry {
let hdr = self.get_header_mut(); let hdr = self.get_header_mut();
for pattern in patterns.iter() { for pattern in patterns.iter() {
let _ = hdr.delete(pattern) let _ = hdr.delete(pattern)
.map_err(Error::from) .context(format_err!("Error while deleting header '{}'", pattern))
.context("Error writing header")?; .context("Error writing header")?;
} }

View file

@ -38,7 +38,7 @@
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
extern crate failure; #[macro_use] extern crate failure;
extern crate libimagstore; extern crate libimagstore;
extern crate libimagerror; extern crate libimagerror;

View file

@ -70,7 +70,7 @@ impl Link for Entry {
fn get_link_uri_from_filelockentry(&self) -> Result<Option<Url>> { fn get_link_uri_from_filelockentry(&self) -> Result<Option<Url>> {
self.get_header() self.get_header()
.read_string("links.external.content.url") .read_string("links.external.content.url")
.map_err(Error::from) .context(format_err!("Error reading header 'links.external.content.url' from '{}'", self.get_location()))
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)
.map_err(Error::from) .map_err(Error::from)
.and_then(|opt| match opt { .and_then(|opt| match opt {
@ -79,11 +79,13 @@ impl Link for Entry {
debug!("Found url, parsing: {:?}", s); debug!("Found url, parsing: {:?}", s);
Url::parse(&s[..]) Url::parse(&s[..])
.map_err(Error::from) .map_err(Error::from)
.context(format_err!("Failed to parse URL: '{}'", s))
.context(err_msg("Invalid URI")) .context(err_msg("Invalid URI"))
.map_err(Error::from) .map_err(Error::from)
.map(Some) .map(Some)
}, },
}) })
.context("Failed to get link URI from entry")
.map_err(Error::from) .map_err(Error::from)
} }
@ -91,6 +93,7 @@ impl Link for Entry {
match self.get_header().read_string("links.external.url")? { match self.get_header().read_string("links.external.url")? {
None => Ok(None), None => Ok(None),
Some(ref s) => Url::parse(&s[..]) Some(ref s) => Url::parse(&s[..])
.context(format_err!("Failed to parse URL: '{}'", s))
.map(Some) .map(Some)
.map_err(Error::from) .map_err(Error::from)
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)

View file

@ -265,7 +265,7 @@ impl InternalLinker for Entry {
let res = self let res = self
.get_header() .get_header()
.read("links.internal") .read("links.internal")
.map_err(Error::from) .context(format_err!("Failed to read header 'links.internal' of '{}'", self.get_location()))
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)
.context(EM::EntryHeaderError) .context(EM::EntryHeaderError)
.map_err(Error::from) .map_err(Error::from)
@ -299,7 +299,7 @@ impl InternalLinker for Entry {
let res = self let res = self
.get_header_mut() .get_header_mut()
.insert("links.internal", Value::Array(new_links)) .insert("links.internal", Value::Array(new_links))
.map_err(Error::from) .context(format_err!("Failed to insert header 'links.internal' of '{}'", self.get_location()))
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)
.map_err(Error::from); .map_err(Error::from);
process_rw_result(res) process_rw_result(res)
@ -336,7 +336,7 @@ impl InternalLinker for Entry {
fn unlink(&mut self, store: &Store) -> Result<()> { fn unlink(&mut self, store: &Store) -> Result<()> {
for id in self.get_internal_links()?.map(|l| l.get_store_id().clone()) { for id in self.get_internal_links()?.map(|l| l.get_store_id().clone()) {
match store.get(id).map_err(Error::from)? { match store.get(id).context("Failed to get entry")? {
Some(mut entry) => self.remove_internal_link(&mut entry)?, Some(mut entry) => self.remove_internal_link(&mut entry)?,
None => return Err(err_msg("Link target does not exist")), None => return Err(err_msg("Link target does not exist")),
} }
@ -382,7 +382,7 @@ fn rewrite_links<I: Iterator<Item = Link>>(header: &mut Value, links: I) -> Resu
debug!("Setting new link array: {:?}", links); debug!("Setting new link array: {:?}", links);
let process = header let process = header
.insert("links.internal", Value::Array(links)) .insert("links.internal", Value::Array(links))
.map_err(Error::from) .context(format_err!("Failed to insert header 'links.internal'"))
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)
.map_err(Error::from); .map_err(Error::from);
process_rw_result(process).map(|_| ()) process_rw_result(process).map(|_| ())
@ -409,7 +409,7 @@ fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
let res = target let res = target
.get_header_mut() .get_header_mut()
.insert("links.internal", Value::Array(links)) .insert("links.internal", Value::Array(links))
.map_err(Error::from) .context(format_err!("Failed to insert header 'links.internal'"))
.context(EM::EntryHeaderReadError) .context(EM::EntryHeaderReadError)
.map_err(Error::from); .map_err(Error::from);

View file

@ -89,6 +89,7 @@ pub mod fassade {
use libimagentryutil::isa::Is; use libimagentryutil::isa::Is;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use crate::hasher::sha1::Sha1Hasher; use crate::hasher::sha1::Sha1Hasher;
@ -104,7 +105,7 @@ pub mod fassade {
impl RefFassade for Entry { impl RefFassade for Entry {
/// Check whether the underlying object is actually a ref /// Check whether the underlying object is actually a ref
fn is_ref(&self) -> Result<bool> { fn is_ref(&self) -> Result<bool> {
self.is::<IsRef>().map_err(Error::from) self.is::<IsRef>().context("Failed to check is-ref flag").map_err(Error::from)
} }
fn as_ref_with_hasher<H: Hasher>(&self) -> RefWithHasher<H> { fn as_ref_with_hasher<H: Hasher>(&self) -> RefWithHasher<H> {
@ -163,7 +164,7 @@ impl<'a, H: Hasher> Ref for RefWithHasher<'a, H> {
/// Check whether the underlying object is actually a ref /// Check whether the underlying object is actually a ref
fn is_ref(&self) -> Result<bool> { fn is_ref(&self) -> Result<bool> {
self.0.is::<IsRef>().map_err(Error::from) self.0.is::<IsRef>().context("Failed to check is-ref flag").map_err(Error::from)
} }
fn get_hash(&self) -> Result<&str> { fn get_hash(&self) -> Result<&str> {
@ -171,6 +172,7 @@ impl<'a, H: Hasher> Ref for RefWithHasher<'a, H> {
self.0 self.0
.get_header() .get_header()
.read(&header_path) .read(&header_path)
.context(format_err!("Failed to read header at '{}'", header_path))
.map_err(Error::from)? .map_err(Error::from)?
.ok_or_else(|| { .ok_or_else(|| {
Error::from(EM::EntryHeaderFieldMissing("ref.hash.<hash>")) Error::from(EM::EntryHeaderFieldMissing("ref.hash.<hash>"))
@ -210,7 +212,7 @@ impl<'a, H: Hasher> Ref for RefWithHasher<'a, H> {
self.0 self.0
.get_header() .get_header()
.read("ref.relpath") .read("ref.relpath")
.map_err(Error::from)? .context("Failed to read header at 'ref.relpath'")?
.ok_or_else(|| Error::from(EM::EntryHeaderFieldMissing("ref.relpath"))) .ok_or_else(|| Error::from(EM::EntryHeaderFieldMissing("ref.relpath")))
.and_then(|v| { .and_then(|v| {
v.as_str() v.as_str()
@ -223,19 +225,20 @@ impl<'a, H: Hasher> Ref for RefWithHasher<'a, H> {
fn hash_valid(&self, config: &Config) -> Result<bool> { fn hash_valid(&self, config: &Config) -> Result<bool> {
let ref_header = self.0 let ref_header = self.0
.get_header() .get_header()
.read("ref")? .read("ref")
.context("Failed to read header at 'ref'")?
.ok_or_else(|| err_msg("Header missing at 'ref'"))?; .ok_or_else(|| err_msg("Header missing at 'ref'"))?;
let basepath_name = ref_header let basepath_name = ref_header
.read("basepath") .read("basepath")
.map_err(Error::from)? .context("Failed to read header at 'ref.basepath'")?
.ok_or_else(|| err_msg("Header missing at 'ref.basepath'"))? .ok_or_else(|| err_msg("Header missing at 'ref.basepath'"))?
.as_str() .as_str()
.ok_or_else(|| Error::from(EM::EntryHeaderTypeError2("ref.hash.<hash>", "string")))?; .ok_or_else(|| Error::from(EM::EntryHeaderTypeError2("ref.hash.<hash>", "string")))?;
let path = ref_header let path = ref_header
.read("relpath") .read("relpath")
.map_err(Error::from)? .context("Failed to read header at 'ref.relpath'")?
.ok_or_else(|| err_msg("Header missing at 'ref.relpath'"))? .ok_or_else(|| err_msg("Header missing at 'ref.relpath'"))?
.as_str() .as_str()
.map(PathBuf::from) .map(PathBuf::from)
@ -246,7 +249,7 @@ impl<'a, H: Hasher> Ref for RefWithHasher<'a, H> {
ref_header ref_header
.read(H::NAME) .read(H::NAME)
.map_err(Error::from)? .context(format_err!("Failed to read header at 'ref.{}'", H::NAME))?
.ok_or_else(|| format_err!("Header missing at 'ref.{}'", H::NAME)) .ok_or_else(|| format_err!("Header missing at 'ref.{}'", H::NAME))
.and_then(|v| { .and_then(|v| {
v.as_str().ok_or_else(|| { v.as_str().ok_or_else(|| {
@ -352,7 +355,9 @@ impl<'a, H> MutRef for MutRefWithHasher<'a, H>
trace!("Using relpath = {} to make header section", relpath.display()); trace!("Using relpath = {} to make header section", relpath.display());
make_header_section(hash, H::NAME, relpath, basepath_name) make_header_section(hash, H::NAME, relpath, basepath_name)
}) })
.and_then(|h| self.0.get_header_mut().insert("ref", h).map_err(Error::from)) .and_then(|h| self.0.get_header_mut().insert("ref", h)
.context("Failed to insert 'ref' in header")
.map_err(Error::from))
.and_then(|_| self.0.set_isflag::<IsRef>()) .and_then(|_| self.0.set_isflag::<IsRef>())
.context("Making ref out of entry")?; .context("Making ref out of entry")?;

View file

@ -51,6 +51,7 @@ impl Tagable for Value {
fn get_tags(&self) -> Result<Vec<Tag>> { fn get_tags(&self) -> Result<Vec<Tag>> {
self.read("tag.values") self.read("tag.values")
.context(format_err!("Failed to read header at 'tag.values'"))
.map_err(Error::from) .map_err(Error::from)
.context(EM::EntryHeaderReadError)? .context(EM::EntryHeaderReadError)?
.map(|val| { .map(|val| {

View file

@ -18,6 +18,7 @@
// //
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error; use failure::Error;
use toml::Value; use toml::Value;
@ -79,7 +80,12 @@ impl Is for ::libimagstore::store::Entry {
fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool> { fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool> {
let field = T::kindflag_header_location(); let field = T::kindflag_header_location();
match self.get_header().read_bool(field).map_err(Error::from)? { match self
.get_header()
.read_bool(field)
.context(format_err!("Failed reading header '{}' in '{}'", field, self.get_location()))
.map_err(Error::from)?
{
Some(b) => Ok(b), Some(b) => Ok(b),
None => Ok(false), None => Ok(false),
} }
@ -88,6 +94,7 @@ impl Is for ::libimagstore::store::Entry {
fn set_isflag<T: IsKindHeaderPathProvider>(&mut self) -> Result<()> { fn set_isflag<T: IsKindHeaderPathProvider>(&mut self) -> Result<()> {
self.get_header_mut() self.get_header_mut()
.insert(T::kindflag_header_location(), Value::Boolean(true)) .insert(T::kindflag_header_location(), Value::Boolean(true))
.context(format_err!("Failed inserting header '{}' in '{}'", T::kindflag_header_location(), self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }
@ -96,6 +103,7 @@ impl Is for ::libimagstore::store::Entry {
trace!("Trying to remove: {}", T::kindflag_header_location()); trace!("Trying to remove: {}", T::kindflag_header_location());
self.get_header_mut() self.get_header_mut()
.delete(T::kindflag_header_location()) .delete(T::kindflag_header_location())
.context(format_err!("Failed deleting header '{}' in '{}'", T::kindflag_header_location(), self.get_location()))
.map_err(Error::from) .map_err(Error::from)
.map(|_| ()) .map(|_| ())
} }

View file

@ -40,7 +40,7 @@
extern crate filters; extern crate filters;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate failure; #[macro_use] extern crate failure;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate libimagstore; extern crate libimagstore;

View file

@ -27,7 +27,6 @@ use crate::viewer::Viewer;
use failure::Fallible as Result; use failure::Fallible as Result;
use failure::ResultExt; use failure::ResultExt;
use failure::Error; use failure::Error;
use failure::err_msg;
pub struct EditorView<'a>(&'a Runtime<'a>); pub struct EditorView<'a>(&'a Runtime<'a>);
@ -43,7 +42,7 @@ impl<'a> Viewer for EditorView<'a> {
{ {
let mut entry = e.to_str()?.clone().to_string(); let mut entry = e.to_str()?.clone().to_string();
edit_in_tmpfile(self.0, &mut entry) edit_in_tmpfile(self.0, &mut entry)
.context(err_msg("Error while viewing")) .context("Error while viewing")
.map_err(Error::from) .map_err(Error::from)
} }
} }

View file

@ -178,10 +178,12 @@ pub fn ask_select_from_list(list: &[&str]) -> Result<String> {
/// The `nl` parameter can be used to configure whether a newline character should be printed /// The `nl` parameter can be used to configure whether a newline character should be printed
pub fn ask_question(question: &str, nl: bool, output: &mut Write) -> Result<()> { pub fn ask_question(question: &str, nl: bool, output: &mut Write) -> Result<()> {
if nl { if nl {
writeln!(output, "[imag]: {}?", Yellow.paint(question)).map_err(Error::from) writeln!(output, "[imag]: {}?", Yellow.paint(question))
} else { } else {
write!(output, "[imag]: {}?", Yellow.paint(question)).map_err(Error::from) write!(output, "[imag]: {}?", Yellow.paint(question))
} }
.context("Failed to write question to output")
.map_err(Error::from)
} }
#[cfg(test)] #[cfg(test)]