Merge pull request #1200 from matthiasbeyer/refactor-matching-into-command-chaining

Refactor matching into command chaining
This commit is contained in:
Matthias Beyer 2018-01-05 15:19:32 +01:00 committed by GitHub
commit c0f4a20367
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 377 additions and 475 deletions

View file

@ -80,21 +80,18 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
s s
}; };
match ::toml::de::from_str::<::toml::Value>(&content[..]) { ::toml::de::from_str::<::toml::Value>(&content[..])
Ok(res) => Some(res), .map(Some)
Err(e) => { .unwrap_or_else(|e| {
let line_col = e let line_col = e
.line_col() .line_col()
.map(|(line, col)| { .map(|(line, col)| format!("Line {}, Column {}", line, col))
format!("Line {}, Column {}", line, col)
})
.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(&e); trace_error(&e);
None None
} })
}
}) })
.nth(0) .nth(0)
.ok_or(RE::from_kind(REK::ConfigNoConfigFileFound)) .ok_or(RE::from_kind(REK::ConfigNoConfigFileFound))
@ -114,27 +111,20 @@ pub fn override_config(val: &mut Value, v: Vec<String>) -> Result<()> {
let iter = v.into_iter() let iter = v.into_iter()
.map(|s| { debug!("Trying to process '{}'", s); s }) .map(|s| { debug!("Trying to process '{}'", s); s })
.filter_map(|s| match s.into_kv() { .filter_map(|s| s.into_kv().map(Into::into).or_else(|| {
Some(kv) => Some(kv.into()),
None => {
warn!("Could split at '=' - will be ignore override"); warn!("Could split at '=' - will be ignore override");
None None
} }))
}) .map(|(k, v)| {
.map(|(k, v)| val let value = val
.read(&k[..]) .read(&k)
.chain_err(|| REK::ConfigTOMLParserError) .chain_err(|| REK::ConfigTOMLParserError)?
.map(|toml| match toml { .ok_or(RE::from_kind(REK::ConfigOverrideKeyNotAvailable))?;
Some(value) => match into_value(value, v) {
Some(v) => { into_value(value, v)
info!("Successfully overridden: {} = {}", k, v); .map(|v| info!("Successfully overridden: {} = {}", k, v))
Ok(()) .ok_or_else(|| RE::from_kind(REK::ConfigOverrideTypeNotMatching))
}, });
None => Err(RE::from_kind(REK::ConfigOverrideTypeNotMatching)),
},
None => Err(RE::from_kind(REK::ConfigOverrideKeyNotAvailable)),
})
);
for elem in iter { for elem in iter {
let _ = try!(elem.chain_err(|| REK::ConfigOverrideError)); let _ = try!(elem.chain_err(|| REK::ConfigOverrideError));

View file

@ -238,16 +238,16 @@ fn aggregate_global_loglevel(matches: &ArgMatches, config: Option<&Value>)
} }
if let Some(cfg) = config { if let Some(cfg) = config {
let cfg_loglevel = match cfg.read("imag.logging.level") { let cfg_loglevel = cfg
Ok(Some(&Value::String(ref s))) => match_log_level_str(s), .read("imag.logging.level")?
Ok(Some(_)) => { .ok_or(RE::from_kind(EK::GlobalLogLevelConfigMissing))?
.as_str()
.ok_or_else(|| {
let path = "imag.logging.level".to_owned(); let path = "imag.logging.level".to_owned();
let ty = "String"; let ty = "String";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty))) RE::from_kind(EK::ConfigTypeError(path, ty))
}, })
Ok(None) => return Err(RE::from_kind(EK::GlobalLogLevelConfigMissing)), .and_then(match_log_level_str)?;
Err(e) => return Err(e).map_err(From::from),
}?;
if let Some(cli_loglevel) = get_arg_loglevel(matches)? { if let Some(cli_loglevel) = get_arg_loglevel(matches)? {
if cli_loglevel > cfg_loglevel { if cli_loglevel > cfg_loglevel {
@ -285,14 +285,13 @@ fn translate_destinations(raw: &Vec<Value>) -> Result<Vec<LogDestination>> {
raw.iter() raw.iter()
.fold(Ok(vec![]), |acc, val| { .fold(Ok(vec![]), |acc, val| {
acc.and_then(|mut v| { acc.and_then(|mut v| {
let dest = match *val { let dest = val.as_str()
Value::String(ref s) => translate_destination(s)?, .ok_or_else(|| {
_ => {
let path = "imag.logging.modules.<mod>.destinations".to_owned(); let path = "imag.logging.modules.<mod>.destinations".to_owned();
let ty = "Array<String>"; let ty = "Array<String>";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty))) RE::from_kind(EK::ConfigTypeError(path, ty))
}, })
}; .and_then(translate_destination)?;
v.push(dest); v.push(dest);
Ok(v) Ok(v)
}) })
@ -304,16 +303,16 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
{ {
match config { match config {
Some(cfg) => match cfg.read("imag.logging.destinations") { Some(cfg) => cfg
Ok(Some(&Value::Array(ref a))) => translate_destinations(a), .read("imag.logging.destinations")?
Ok(Some(_)) => { .ok_or_else(|| RE::from_kind(EK::GlobalDestinationConfigMissing))?
.as_array()
.ok_or_else(|| {
let path = "imag.logging.destinations".to_owned(); let path = "imag.logging.destinations".to_owned();
let ty = "Array"; let ty = "Array";
Err(RE::from_kind(EK::ConfigTypeError(path, ty))) RE::from_kind(EK::ConfigTypeError(path, ty))
}, })
Ok(None) => Err(RE::from_kind(EK::GlobalDestinationConfigMissing)), .and_then(translate_destinations),
Err(e) => Err(e).map_err(From::from),
},
None => { None => {
if let Some(values) = matches.value_of(Runtime::arg_logdest_name()) { if let Some(values) = matches.value_of(Runtime::arg_logdest_name()) {
// parse logdest specification from commandline // parse logdest specification from commandline
@ -334,12 +333,12 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
macro_rules! aggregate_global_format { macro_rules! aggregate_global_format {
($read_str:expr, $error_kind_if_missing:expr, $config:expr) => { ($read_str:expr, $error_kind_if_missing:expr, $config:expr) => {
match try!($config.ok_or(RE::from_kind($error_kind_if_missing))).read($read_str) { try!($config.ok_or(RE::from_kind($error_kind_if_missing)))
Ok(Some(&Value::String(ref s))) => Ok(s.clone()), .read($read_str)?
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError($read_str.to_owned(), "String"))), .ok_or_else(|| RE::from_kind($error_kind_if_missing))?
Ok(None) => Err(RE::from_kind($error_kind_if_missing)), .as_str()
Err(e) => Err(e).map_err(From::from), .map(String::from)
} .ok_or_else(|| RE::from_kind(EK::ConfigTypeError($read_str.to_owned(), "String")))
}; };
} }
@ -386,6 +385,18 @@ fn aggregate_global_format_error(config: Option<&Value>)
fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>) fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
-> Result<BTreeMap<ModuleName, ModuleSettings>> -> Result<BTreeMap<ModuleName, ModuleSettings>>
{ {
// Helper macro to return the error from Some(Err(_)) and map everything else to an
// Option<_>
macro_rules! inner_try {
($v:expr) => {
match $v {
Some(Ok(v)) => Some(v),
Some(Err(e)) => return Err(e),
None => None,
}
}
};
match config { match config {
Some(cfg) => match cfg.read("imag.logging.modules") { Some(cfg) => match cfg.read("imag.logging.modules") {
Ok(Some(&Value::Table(ref t))) => { Ok(Some(&Value::Table(ref t))) => {
@ -393,35 +404,39 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
let mut settings = BTreeMap::new(); let mut settings = BTreeMap::new();
for (module_name, v) in t { for (module_name, v) in t {
let destinations = match v.read("destinations")? { let destinations = inner_try! {
Some(&Value::Array(ref a)) => Some(translate_destinations(a)?), v.read("destinations")?
None => None, .map(|val| {
Some(_) => { val.as_array()
.ok_or_else(|| {
let path = "imag.logging.modules.<mod>.destinations".to_owned(); let path = "imag.logging.modules.<mod>.destinations".to_owned();
let ty = "Array"; let ty = "Array";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty))) RE::from_kind(EK::ConfigTypeError(path, ty))
}, })
.and_then(translate_destinations)
})
}; };
let level = match v.read("level")? { let level = inner_try! {
Some(&Value::String(ref s)) => Some(match_log_level_str(s)?), v.read("level")?
None => None, .map(|val| {
Some(_) => { val.as_str()
.ok_or_else(|| {
let path = "imag.logging.modules.<mod>.level".to_owned(); let path = "imag.logging.modules.<mod>.level".to_owned();
let ty = "String"; let ty = "String";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty))) RE::from_kind(EK::ConfigTypeError(path, ty))
}, })
.and_then(match_log_level_str)
})
}; };
let enabled = match v.read("enabled")? { let enabled = v.read("enabled")?
Some(&Value::Boolean(b)) => b, .map(|v| v.as_bool().unwrap_or(false))
None => false, .ok_or_else(|| {
Some(_) => {
let path = "imag.logging.modules.<mod>.enabled".to_owned(); let path = "imag.logging.modules.<mod>.enabled".to_owned();
let ty = "Boolean"; let ty = "Boolean";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty))) RE::from_kind(EK::ConfigTypeError(path, ty))
}, })?;
};
let module_settings = ModuleSettings { let module_settings = ModuleSettings {
enabled: enabled, enabled: enabled,

View file

@ -325,10 +325,11 @@ impl Store {
debug!("Creating id: '{}'", id); debug!("Creating id: '{}'", id);
{ {
let mut hsmap = match self.entries.write() { let mut hsmap = self
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)).chain_err(|| SEK::CreateCallError), .entries
Ok(s) => s, .write()
}; .map_err(|_| SE::from_kind(SEK::LockPoisoned))
.chain_err(|| SEK::CreateCallError)?;
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);
@ -480,10 +481,7 @@ impl Store {
/// - Errors StoreEntry::write_entry() might return /// - Errors StoreEntry::write_entry() might return
/// ///
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 = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?;
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
Ok(e) => e,
};
let se = hsmap.get_mut(&entry.location).ok_or_else(|| { let se = hsmap.get_mut(&entry.location).ok_or_else(|| {
SE::from_kind(SEK::IdNotFound(entry.location.clone())) SE::from_kind(SEK::IdNotFound(entry.location.clone()))
@ -519,13 +517,9 @@ impl Store {
pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> { pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
let id = id.into_storeid()?.with_base(self.path().clone()); let id = id.into_storeid()?.with_base(self.path().clone());
debug!("Retrieving copy of '{}'", id); debug!("Retrieving copy of '{}'", id);
let entries = match self.entries.write() { let entries = self.entries.write()
Err(_) => { .map_err(|_| SE::from_kind(SEK::LockPoisoned))
return Err(SE::from_kind(SEK::LockPoisoned)) .chain_err(|| SEK::RetrieveCopyCallError)?;
.chain_err(|| SEK::RetrieveCopyCallError);
},
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) {
@ -552,11 +546,11 @@ impl Store {
debug!("Deleting id: '{}'", id); debug!("Deleting id: '{}'", id);
{ {
let mut entries = match self.entries.write() { let mut entries = self
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)) .entries
.chain_err(|| SEK::DeleteCallError), .write()
Ok(e) => e, .map_err(|_| SE::from_kind(SEK::LockPoisoned))
}; .chain_err(|| SEK::DeleteCallError)?;
// 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) {
@ -588,11 +582,11 @@ impl Store {
// remove the entry first, then the file // remove the entry first, then the file
entries.remove(&id); entries.remove(&id);
let pb = id.clone().with_base(self.path().clone()).into_pathbuf()?; let pb = id.clone().with_base(self.path().clone()).into_pathbuf()?;
if let Err(e) = self.backend.remove_file(&pb) { let _ = self
return Err(e) .backend
.remove_file(&pb)
.chain_err(|| SEK::FileError) .chain_err(|| SEK::FileError)
.chain_err(|| SEK::DeleteCallError); .chain_err(|| SEK::DeleteCallError)?;
}
} }
debug!("Deleted"); debug!("Deleted");
@ -631,14 +625,13 @@ impl Store {
let old_id_as_path = old_id.clone().with_base(self.path().clone()).into_pathbuf()?; let old_id_as_path = old_id.clone().with_base(self.path().clone()).into_pathbuf()?;
let new_id_as_path = new_id.clone().with_base(self.path().clone()).into_pathbuf()?; let new_id_as_path = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
self.backend.copy(&old_id_as_path, &new_id_as_path) self.backend
.and_then(|_| { .copy(&old_id_as_path, &new_id_as_path)
if remove_old { .and_then(|_| if remove_old {
debug!("Removing old '{:?}'", old_id_as_path); debug!("Removing old '{:?}'", old_id_as_path);
self.backend.remove_file(&old_id_as_path) self.backend.remove_file(&old_id_as_path)
} else { } else {
Ok(()) Ok(())
}
}) })
.chain_err(|| SEK::FileError) .chain_err(|| SEK::FileError)
.chain_err(|| SEK::MoveCallError) .chain_err(|| SEK::MoveCallError)
@ -684,10 +677,7 @@ impl Store {
debug!("Moving '{}' to '{}'", old_id, new_id); debug!("Moving '{}' to '{}'", old_id, new_id);
{ {
let mut hsmap = match self.entries.write() { let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?;
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
Ok(m) => m,
};
if hsmap.contains_key(&new_id) { if hsmap.contains_key(&new_id) {
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone()))); return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone())));
@ -711,9 +701,11 @@ impl Store {
} }
debug!("New entry does not yet exist on filesystem. Good."); debug!("New entry does not yet exist on filesystem. Good.");
match self.backend.rename(&old_id_pb, &new_id_pb) { let _ = self
Err(e) => return Err(e).chain_err(|| SEK::EntryRenameError(old_id_pb, new_id_pb)), .backend
Ok(_) => { .rename(&old_id_pb, &new_id_pb)
.chain_err(|| SEK::EntryRenameError(old_id_pb, new_id_pb))?;
debug!("Rename worked on filesystem"); debug!("Rename worked on filesystem");
// assert enforced through check hsmap.contains_key(&new_id) above. // assert enforced through check hsmap.contains_key(&new_id) above.
@ -725,9 +717,6 @@ impl Store {
hsmap.insert(new_id.clone(), entry) hsmap.insert(new_id.clone(), entry)
}).is_none()) }).is_none())
} }
}
}
debug!("Moved"); debug!("Moved");
Ok(()) Ok(())
@ -1036,18 +1025,13 @@ mod glob_store_iter {
debug!("GlobStoreIdIterator::next() => {:?}", o); debug!("GlobStoreIdIterator::next() => {:?}", o);
match o.chain_err(|| SEK::StoreIdHandlingError) { match o.chain_err(|| SEK::StoreIdHandlingError) {
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
Ok(path) => { Ok(path) => if path.exists() && path.is_file() {
if path.exists() && path.is_file() { return Some(StoreId::from_full_path(&self.store_path, path));
return match StoreId::from_full_path(&self.store_path, path) {
Ok(id) => Some(Ok(id)),
Err(e) => Some(Err(e)),
}
/* } else { */ /* } else { */
/* continue */ /* continue */
} }
} }
} }
}
None None
} }

View file

@ -90,13 +90,8 @@ impl<'a> BookmarkCollection<'a> {
.and_then(|id| store.get(id)) .and_then(|id| store.get(id))
.chain_err(|| BEK::StoreReadError) .chain_err(|| BEK::StoreReadError)
.and_then(|fle| { .and_then(|fle| {
match fle { fle.ok_or(BE::from_kind(BEK::CollectionNotFound))
None => Err(BE::from_kind(BEK::CollectionNotFound)), .map(|e| BookmarkCollection { fle: e, store: store })
Some(e) => Ok(BookmarkCollection {
fle: e,
store: store,
}),
}
}) })
} }

View file

@ -30,6 +30,7 @@ use error::*;
use iter::HabitInstanceStoreIdIterator; use iter::HabitInstanceStoreIdIterator;
use util::date_to_string; use util::date_to_string;
use util::IsHabitCheck; use util::IsHabitCheck;
use util::get_string_header_from_entry;
use libimagentrylink::internal::InternalLinker; use libimagentrylink::internal::InternalLinker;
use libimagstore::store::Store; use libimagstore::store::Store;
@ -202,27 +203,26 @@ impl HabitTemplate for Entry {
} }
fn habit_name(&self) -> Result<String> { fn habit_name(&self) -> Result<String> {
get_string_header_from_habit(self, "habit.template.name") get_string_header_from_entry(self, "habit.template.name")
} }
fn habit_basedate(&self) -> Result<String> { fn habit_basedate(&self) -> Result<String> {
get_string_header_from_habit(self, "habit.template.basedate") get_string_header_from_entry(self, "habit.template.basedate")
} }
fn habit_recur_spec(&self) -> Result<String> { fn habit_recur_spec(&self) -> Result<String> {
get_string_header_from_habit(self, "habit.template.recurspec") get_string_header_from_entry(self, "habit.template.recurspec")
} }
fn habit_comment(&self) -> Result<String> { fn habit_comment(&self) -> Result<String> {
get_string_header_from_habit(self, "habit.template.comment") get_string_header_from_entry(self, "habit.template.comment")
} }
fn habit_until_date(&self) -> Result<Option<String>> { fn habit_until_date(&self) -> Result<Option<String>> {
match self.get_header().read("habit.template.until")? { self.get_header()
Some(&Value::String(ref s)) => Ok(Some(s.clone())), .read("habit.template.until")?
Some(_) => Err(HEK::HeaderTypeError("habit.template.until", "String").into()), .map(|v| v.as_str().map(String::from))
None => Ok(None), .ok_or(HEK::HeaderTypeError("habit.template.until", "String").into())
}
} }
fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId> { fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId> {
@ -239,15 +239,6 @@ fn instance_id_for_name_and_datestr(habit_name: &String, habit_date: &String) ->
.map_err(HE::from) .map_err(HE::from)
} }
#[inline]
fn get_string_header_from_habit(e: &Entry, path: &'static str) -> Result<String> {
match e.get_header().read(path)? {
Some(&Value::String(ref s)) => Ok(s.clone()),
Some(_) => Err(HEK::HeaderTypeError(path, "String").into()),
None => Err(HEK::HeaderFieldMissing(path).into()),
}
}
pub mod builder { pub mod builder {
use toml::Value; use toml::Value;
use toml_query::insert::TomlValueInsertExt; use toml_query::insert::TomlValueInsertExt;

View file

@ -22,7 +22,6 @@ use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt; use toml_query::set::TomlValueSetExt;
use error::HabitErrorKind as HEK;
use error::*; use error::*;
use util::*; use util::*;
@ -61,11 +60,8 @@ impl HabitInstance for Entry {
} }
fn get_date(&self) -> Result<NaiveDate> { fn get_date(&self) -> Result<NaiveDate> {
match self.get_header().read("habit.instance.date")? { use util::date_from_string;
Some(&Value::String(ref s)) => date_from_string(s), get_string_header_from_entry(self, "habit.instance.date").and_then(date_from_string)
Some(_) => Err(HEK::HeaderTypeError("habit.instance.date", "String").into()),
None => Err(HEK::HeaderFieldMissing("habit.instance.date").into()),
}
} }
fn set_date(&mut self, n: &NaiveDate) -> Result<()> { fn set_date(&mut self, n: &NaiveDate) -> Result<()> {
@ -77,11 +73,7 @@ impl HabitInstance for Entry {
} }
fn get_comment(&self) -> Result<String> { fn get_comment(&self) -> Result<String> {
match self.get_header().read("habit.instance.comment")? { get_string_header_from_entry(self, "habit.instance.comment")
Some(&Value::String(ref s)) => Ok(s.clone()),
Some(_) => Err(HEK::HeaderTypeError("habit.instance.comment", "String").into()),
None => Err(HEK::HeaderFieldMissing("habit.instance.comment").into()),
}
} }
fn set_comment(&mut self, c: String) -> Result<()> { fn set_comment(&mut self, c: String) -> Result<()> {
@ -93,11 +85,7 @@ impl HabitInstance for Entry {
} }
fn get_template_name(&self) -> Result<String> { fn get_template_name(&self) -> Result<String> {
match self.get_header().read("habit.instance.name")? { get_string_header_from_entry(self, "habit.instance.name")
Some(&Value::String(ref s)) => Ok(s.clone()),
Some(_) => Err(HEK::HeaderTypeError("habit.instance.name", "String").into()),
None => Err(HEK::HeaderFieldMissing("habit.instance.name").into()),
}
} }
} }

View file

@ -34,8 +34,8 @@ pub fn date_to_string(ndt: &NaiveDate) -> String {
ndt.format(NAIVE_DATE_STRING_FORMAT).to_string() ndt.format(NAIVE_DATE_STRING_FORMAT).to_string()
} }
pub fn date_from_string(s: &str) -> Result<NaiveDate> { pub fn date_from_string(s: String) -> Result<NaiveDate> {
NaiveDate::parse_from_str(s, NAIVE_DATE_STRING_FORMAT).map_err(From::from) NaiveDate::parse_from_str(&s, NAIVE_DATE_STRING_FORMAT).map_err(From::from)
} }
/// Helper trait to check whether a object which can be a habit instance and a habit template is /// Helper trait to check whether a object which can be a habit instance and a habit template is
@ -90,3 +90,14 @@ impl IsHabitCheck for Entry {
} }
} }
#[inline]
pub fn get_string_header_from_entry(e: &Entry, path: &'static str) -> Result<String> {
use error::HabitErrorKind as HEK;
use toml_query::read::TomlValueReadExt;
e.get_header()
.read(path)?
.ok_or(HEK::HeaderFieldMissing(path).into())
.and_then(|o| o.as_str().map(String::from).ok_or(HEK::HeaderTypeError(path, "String").into()))
}

View file

@ -36,11 +36,10 @@ pub trait Log : DiaryEntry {
impl Log for Entry { impl Log for Entry {
fn is_log(&self) -> Result<bool> { fn is_log(&self) -> Result<bool> {
let location = "log.is_log"; let location = "log.is_log";
match self.get_header().read(location)? { self.get_header()
Some(&Value::Boolean(b)) => Ok(b), .read(location)?
Some(_) => Err(LE::from_kind(LEK::HeaderTypeError("boolean", location))), .ok_or(LE::from_kind(LEK::HeaderTypeError("boolean", location)))
None => Ok(false) .map(|v| v.as_bool().unwrap_or(false))
}
} }
fn make_log_entry(&mut self) -> Result<()> { fn make_log_entry(&mut self) -> Result<()> {

View file

@ -46,13 +46,12 @@ impl Note for Entry {
} }
fn get_name(&self) -> Result<String> { fn get_name(&self) -> Result<String> {
match self.get_header().read("note.name") { self.get_header()
Ok(Some(&Value::String(ref s))) => Ok(s.clone()), .read("note.name")
Ok(_) => { .chain_err(|| NEK::StoreReadError)?
Err(NE::from_kind(NEK::HeaderTypeError)).chain_err(|| NEK::StoreReadError) .and_then(Value::as_str)
}, .map(String::from)
Err(e) => Err(e).chain_err(|| NEK::StoreReadError) .ok_or(NE::from_kind(NEK::HeaderTypeError))
}
} }
fn set_text(&mut self, n: String) { fn set_text(&mut self, n: String) {

View file

@ -45,11 +45,10 @@ 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).chain_err(|| TTEK::StoreReadError) { self.store
Ok(None) => Err(TTE::from_kind(TTEK::StoreReadError)), .get(sid)
Ok(Some(s)) => Ok(s), .chain_err(|| TTEK::StoreReadError)?
Err(e) => Err(e) .ok_or(TTE::from_kind(TTEK::StoreReadError))
}
}) })
} }
} }

View file

@ -65,11 +65,13 @@ 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)
.chain_err(|| TTEK::HeaderReadError) .chain_err(|| TTEK::HeaderReadError)?
.and_then(|value| match value { .ok_or(TTE::from_kind(TTEK::HeaderReadError))
Some(&Value::String(ref s)) => Ok(s.clone().into()), .and_then(|v| {
Some(_) => Err(TTE::from_kind(TTEK::HeaderFieldTypeError)), v.as_str()
_ => Err(TTE::from_kind(TTEK::HeaderReadError)) .map(String::from)
.map(Into::into)
.ok_or(TTE::from_kind(TTEK::HeaderFieldTypeError))
}) })
} }

View file

@ -25,7 +25,6 @@ use error::Result;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use uuid::Uuid; use uuid::Uuid;
use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
pub trait Task { pub trait Task {
@ -34,14 +33,13 @@ pub trait Task {
impl Task for Entry { impl Task for Entry {
fn get_uuid(&self) -> Result<Uuid> { fn get_uuid(&self) -> Result<Uuid> {
match self.get_header().read("todo.uuid") { self.get_header()
Ok(Some(&Value::String(ref uuid))) => { .read("todo.uuid")
Uuid::parse_str(uuid).chain_err(|| TEK::UuidParserError) .chain_err(|| TEK::StoreError)?
}, .ok_or(TE::from_kind(TEK::HeaderFieldMissing))?
Ok(Some(_)) => Err(TE::from_kind(TEK::HeaderTypeError)), .as_str()
Ok(None) => Err(TE::from_kind(TEK::HeaderFieldMissing)), .ok_or(TE::from_kind(TEK::HeaderTypeError))
Err(e) => Err(e).chain_err(|| TEK::StoreError), .and_then(|u| Uuid::parse_str(u).chain_err(|| TEK::UuidParserError))
}
} }
} }

View file

@ -97,13 +97,9 @@ 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(From::from) .map(|val| val.as_bool().unwrap_or(false))
.and_then(|res| match res { .ok_or(AE::from_kind(AEK::HeaderTypeError))
Some(&Value::Boolean(b)) => Ok(b),
None => Ok(false),
_ => Err(AE::from_kind(AEK::HeaderTypeError)),
})
} }
} }

View file

@ -19,7 +19,6 @@
use toml_query::insert::TomlValueInsertExt; use toml_query::insert::TomlValueInsertExt;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
use toml_query::error::ErrorKind as TQEK;
use toml::Value; use toml::Value;
use libimagstore::store::Entry; use libimagstore::store::Entry;
@ -81,17 +80,17 @@ impl EntryCategory for Entry {
} }
fn get_category(&self) -> Result<Option<Category>> { fn get_category(&self) -> Result<Option<Category>> {
match self.get_header().read(&String::from("category.value")) { self.get_header()
Err(res) => match res.kind() { .read("category.value")
&TQEK::IdentifierNotFoundInDocument(_) => Ok(None), .chain_err(|| CEK::HeaderReadError)
_ => Err(res), .and_then(|opt| {
} opt.map(|v| {
.chain_err(|| CEK::HeaderReadError), v.as_str()
.map(String::from)
Ok(Some(&Value::String(ref s))) => Ok(Some(s.clone().into())), .map(Category::from)
Ok(None) => Err(CE::from_kind(CEK::StoreReadError)).chain_err(|| CEK::HeaderReadError), })
Ok(_) => Err(CE::from_kind(CEK::TypeError)).chain_err(|| CEK::HeaderReadError), .ok_or(CE::from_kind(CEK::TypeError))
} })
} }
fn has_category(&self) -> Result<bool> { fn has_category(&self) -> Result<bool> {

View file

@ -22,6 +22,14 @@ error_chain! {
CategoryError, CategoryErrorKind, ResultExt, Result; CategoryError, CategoryErrorKind, ResultExt, Result;
} }
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
}
foreign_links {
TomlQueryError(::toml_query::error::Error);
}
errors { errors {
StoreReadError { StoreReadError {
description("Store Read error") description("Store Read error")

View file

@ -225,14 +225,13 @@ fn represents_category(store: &Store, sid: StoreId, name: &str) -> Result<bool>
.chain_err(|| 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() fle.get_header()
.read(&String::from(CATEGORY_REGISTER_NAME_FIELD_PATH)) .read(&String::from(CATEGORY_REGISTER_NAME_FIELD_PATH))
.chain_err(|| CEK::HeaderReadError) .chain_err(|| CEK::HeaderReadError)?
{ .ok_or(CE::from_kind(CEK::TypeError))?
Ok(Some(&Value::String(ref s))) => Ok(s == name), .as_str()
Ok(_) => Err(CE::from_kind(CEK::TypeError)), .map(|s| s == name)
Err(e) => Err(e).chain_err(|| CEK::HeaderReadError), .ok_or(CE::from_kind(CEK::TypeError))
}
} else { } else {
Ok(false) Ok(false)
} }
@ -276,14 +275,15 @@ impl<'a> Iterator for CategoryNameIter<'a> {
.next() .next()
.map(|sid| { .map(|sid| {
self.0 self.0
.get(sid) .get(sid)?
.chain_err(|| CEK::StoreReadError) .ok_or_else(|| CE::from_kind(CEK::StoreReadError))?
.and_then(|fle| fle.ok_or(CE::from_kind(CEK::StoreReadError))) .get_header()
.and_then(|fle| match fle.get_header().read(&query) { .read(&query)
Ok(Some(&Value::String(ref s))) => Ok(Category::from(s.clone())), .chain_err(|| CEK::HeaderReadError)?
Ok(_) => Err(CE::from_kind(CEK::TypeError)), .and_then(Value::as_str)
Err(e) => Err(e).chain_err(|| CEK::HeaderReadError), .map(String::from)
}) .map(Category::from)
.ok_or_else(|| CE::from_kind(CEK::TypeError))
}) })
} }
} }

View file

@ -63,12 +63,11 @@ impl EntryDate for Entry {
.read(&DATE_HEADER_LOCATION) .read(&DATE_HEADER_LOCATION)
.chain_err(|| DEK::ReadDateError) .chain_err(|| DEK::ReadDateError)
.and_then(|v| { .and_then(|v| {
match v { v.ok_or(DE::from_kind(DEK::ReadDateError))?
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>() .as_str()
.chain_err(|| DEK::DateTimeParsingError), .ok_or(DE::from_kind(DEK::DateHeaderFieldTypeError))?
Some(_) => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)), .parse::<NaiveDateTime>()
_ => Err(DE::from_kind(DEK::ReadDateError)), .chain_err(|| DEK::DateTimeParsingError)
}
}) })
} }
@ -94,11 +93,10 @@ 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))
.map(|opt| opt.map(|stri| { .map(|opt| opt.map(|stri| {
match stri { stri.as_str()
Value::String(ref s) => s.parse::<NaiveDateTime>() .ok_or(DE::from_kind(DEK::DateHeaderFieldTypeError))?
.chain_err(|| DEK::DateTimeParsingError), .parse::<NaiveDateTime>()
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)), .chain_err(|| DEK::DateTimeParsingError)
}
})) }))
.chain_err(|| DEK::SetDateError) .chain_err(|| DEK::SetDateError)
} }
@ -129,30 +127,15 @@ impl EntryDate for Entry {
.get_header() .get_header()
.read(&DATE_RANGE_START_HEADER_LOCATION) .read(&DATE_RANGE_START_HEADER_LOCATION)
.chain_err(|| DEK::ReadDateTimeRangeError) .chain_err(|| DEK::ReadDateTimeRangeError)
.and_then(|v| { .and_then(|v| str_to_ndt(v.ok_or(DE::from_kind(DEK::ReadDateError))?))?;
match v {
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
Some(_) => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
_ => Err(DE::from_kind(DEK::ReadDateError)),
}
})?;
let end = self let end = self
.get_header() .get_header()
.read(&DATE_RANGE_START_HEADER_LOCATION) .read(&DATE_RANGE_START_HEADER_LOCATION)
.chain_err(|| DEK::ReadDateTimeRangeError) .chain_err(|| DEK::ReadDateTimeRangeError)
.and_then(|v| { .and_then(|v| str_to_ndt(v.ok_or(DE::from_kind(DEK::ReadDateError))?))?;
match v {
Some(&Value::String(ref s)) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
Some(_) => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
_ => Err(DE::from_kind(DEK::ReadDateError)),
}
})?;
DateTimeRange::new(start, end) DateTimeRange::new(start, end).chain_err(|| DEK::DateTimeRangeError)
.chain_err(|| DEK::DateTimeRangeError)
} }
/// Set the date range /// Set the date range
@ -171,25 +154,13 @@ impl EntryDate for Entry {
let opt_old_start = self let opt_old_start = self
.get_header_mut() .get_header_mut()
.insert(&DATE_RANGE_START_HEADER_LOCATION, Value::String(start)) .insert(&DATE_RANGE_START_HEADER_LOCATION, Value::String(start))
.map(|opt| opt.map(|stri| { .map(|opt| opt.as_ref().map(str_to_ndt))
match stri {
Value::String(ref s) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
}
}))
.chain_err(|| DEK::SetDateTimeRangeError)?; .chain_err(|| DEK::SetDateTimeRangeError)?;
let opt_old_end = self let opt_old_end = self
.get_header_mut() .get_header_mut()
.insert(&DATE_RANGE_END_HEADER_LOCATION, Value::String(end)) .insert(&DATE_RANGE_END_HEADER_LOCATION, Value::String(end))
.map(|opt| opt.map(|stri| { .map(|opt| opt.as_ref().map(str_to_ndt))
match stri {
Value::String(ref s) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
}
}))
.chain_err(|| DEK::SetDateTimeRangeError)?; .chain_err(|| DEK::SetDateTimeRangeError)?;
match (opt_old_start, opt_old_end) { match (opt_old_start, opt_old_end) {
@ -210,6 +181,13 @@ impl EntryDate for Entry {
} }
fn str_to_ndt(v: &Value) -> Result<NaiveDateTime> {
v.as_str()
.ok_or(DE::from_kind(DEK::DateHeaderFieldTypeError))?
.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::path::PathBuf; use std::path::PathBuf;

View file

@ -52,12 +52,7 @@ impl<P: Predicate> Filter<Entry> for FieldPredicate<P> {
fn filter(&self, e: &Entry) -> bool { fn filter(&self, e: &Entry) -> bool {
e.get_header() e.get_header()
.read(&self.header_field_path[..]) .read(&self.header_field_path[..])
.map(|val| { .map(|val| val.map(|v| (*self.predicate).evaluate(v)).unwrap_or(false))
match val {
None => false,
Some(v) => (*self.predicate).evaluate(v),
}
})
.unwrap_or(false) .unwrap_or(false)
} }

View file

@ -18,7 +18,6 @@
// //
use semver::Version; use semver::Version;
use toml::Value;
use libimagstore::store::Entry; use libimagstore::store::Entry;
@ -44,15 +43,9 @@ impl Filter<Entry> for VersionEq {
.read("imag.version") .read("imag.version")
.map(|val| { .map(|val| {
val.map_or(false, |v| { val.map_or(false, |v| {
match *v { v.as_str()
Value::String(ref s) => { .map(|s| Version::parse(s).map(|v| v == self.version).unwrap_or(false))
match Version::parse(&s[..]) { .unwrap_or(false)
Ok(v) => v == self.version,
_ => false
}
},
_ => false,
}
}) })
}) })
.unwrap_or(false) .unwrap_or(false)

View file

@ -18,7 +18,6 @@
// //
use semver::Version; use semver::Version;
use toml::Value;
use libimagstore::store::Entry; use libimagstore::store::Entry;
@ -44,15 +43,9 @@ impl Filter<Entry> for VersionGt {
.read("imag.version") .read("imag.version")
.map(|val| { .map(|val| {
val.map_or(false, |v| { val.map_or(false, |v| {
match *v { v.as_str()
Value::String(ref s) => { .map(|s| Version::parse(s).map(|v| v > self.version).unwrap_or(false))
match Version::parse(&s[..]) { .unwrap_or(false)
Ok(v) => v > self.version,
_ => false
}
},
_ => false,
}
}) })
}) })
.unwrap_or(false) .unwrap_or(false)

View file

@ -18,7 +18,6 @@
// //
use semver::Version; use semver::Version;
use toml::Value;
use libimagstore::store::Entry; use libimagstore::store::Entry;
@ -44,15 +43,9 @@ impl Filter<Entry> for VersionLt {
.read("imag.version") .read("imag.version")
.map(|val| { .map(|val| {
val.map_or(false, |v| { val.map_or(false, |v| {
match *v { v.as_str()
Value::String(ref s) => { .map(|s| Version::parse(s).map(|v| v < self.version).unwrap_or(false))
match Version::parse(&s[..]) { .unwrap_or(false)
Ok(v) => v < self.version,
_ => false
}
},
_ => false,
}
}) })
}) })
.unwrap_or(false) .unwrap_or(false)

View file

@ -64,10 +64,9 @@ impl GPSEntry for Entry {
} }
fn get_coordinates(&self) -> Result<Option<Coordinates>> { fn get_coordinates(&self) -> Result<Option<Coordinates>> {
match self.get_header().read("gps.coordinates").chain_err(|| GPSEK::HeaderWriteError) { match self.get_header().read("gps.coordinates").chain_err(|| GPSEK::HeaderWriteError)? {
Ok(Some(hdr)) => Coordinates::from_value(hdr).map(Some), Some(hdr) => Coordinates::from_value(hdr).map(Some),
Ok(None) => Ok(None), None => Ok(None),
Err(e) => Err(e),
} }
} }

View file

@ -78,31 +78,27 @@ impl Into<Value> for GPSValue {
impl FromValue for GPSValue { impl FromValue for GPSValue {
fn from_value(v: &Value) -> Result<Self> { fn from_value(v: &Value) -> Result<Self> {
let int_to_appropriate_width = |v: &Value| {
v.as_integer()
.ok_or(GPSE::from_kind(GPSEK::HeaderTypeError)).and_then(i64_to_i8)
};
match *v { match *v {
Value::Table(ref map) => { Value::Table(ref map) => {
Ok(GPSValue::new( Ok(GPSValue::new(
map.get("degree") map.get("degree")
.ok_or_else(|| GPSE::from_kind(GPSEK::DegreeMissing)) .ok_or_else(|| GPSE::from_kind(GPSEK::DegreeMissing))
.and_then(|v| match *v { .and_then(&int_to_appropriate_width)?,
Value::Integer(i) => i64_to_i8(i),
_ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
})?,
map map
.get("minutes") .get("minutes")
.ok_or_else(|| GPSE::from_kind(GPSEK::MinutesMissing)) .ok_or_else(|| GPSE::from_kind(GPSEK::MinutesMissing))
.and_then(|v| match *v { .and_then(&int_to_appropriate_width)?,
Value::Integer(i) => i64_to_i8(i),
_ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
})?,
map map
.get("seconds") .get("seconds")
.ok_or_else(|| GPSE::from_kind(GPSEK::SecondsMissing)) .ok_or_else(|| GPSE::from_kind(GPSEK::SecondsMissing))
.and_then(|v| match *v { .and_then(&int_to_appropriate_width)?
Value::Integer(i) => i64_to_i8(i),
_ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
})?
)) ))
} }
_ => Err(GPSE::from_kind(GPSEK::TypeError)) _ => Err(GPSE::from_kind(GPSEK::TypeError))
@ -154,22 +150,18 @@ impl Into<Value> for Coordinates {
impl FromValue for Coordinates { impl FromValue for Coordinates {
fn from_value(v: &Value) -> Result<Self> { fn from_value(v: &Value) -> Result<Self> {
match *v { v.as_table()
Value::Table(ref map) => { .ok_or(GPSE::from_kind(GPSEK::TypeError))
Ok(Coordinates::new( .and_then(|t| {
match map.get("longitude") { let get = |m: &BTreeMap<_, _>, what: &'static str, ek| -> Result<GPSValue> {
Some(v) => GPSValue::from_value(v), m.get(what).ok_or(GPSE::from_kind(ek)).and_then(GPSValue::from_value)
None => Err(GPSE::from_kind(GPSEK::LongitudeMissing)), };
}?,
match map.get("latitude") { Ok(Coordinates::new(
Some(v) => GPSValue::from_value(v), get(t, "longitude", GPSEK::LongitudeMissing)?,
None => Err(GPSE::from_kind(GPSEK::LongitudeMissing)), get(t, "latitude", GPSEK::LatitudeMissing)?
}?
)) ))
} })
_ => Err(GPSE::from_kind(GPSEK::TypeError))
}
} }
} }

View file

@ -30,6 +30,7 @@ error_chain! {
foreign_links { foreign_links {
TomlQueryError(::toml_query::error::Error); TomlQueryError(::toml_query::error::Error);
UrlError(::url::ParseError);
} }
errors { errors {

View file

@ -641,13 +641,9 @@ pub mod store_check {
let mut map = HashMap::new(); let mut map = HashMap::new();
for element in iter { for element in iter {
debug!("Checking element = {:?}", element); debug!("Checking element = {:?}", element);
let entry = match element? { let entry = element?.ok_or_else(|| {
Some(e) => e, LE::from(String::from("TODO: Not yet handled"))
None => { })?;
let e = String::from("TODO: Not yet handled");
return Err(e).map_err(From::from);
},
};
debug!("Checking entry = {:?}", entry.get_location()); debug!("Checking entry = {:?}", entry.get_location());

View file

@ -21,6 +21,7 @@ use std::collections::BTreeMap;
use toml::Value; use toml::Value;
use error::RefError as RE;
use error::RefErrorKind as REK; use error::RefErrorKind as REK;
use error::Result; use error::Result;
@ -39,13 +40,10 @@ impl RefFlags {
fn get_field(v: &Value, key: &str) -> Result<bool> { fn get_field(v: &Value, key: &str) -> Result<bool> {
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
v.read(key) v.read(key)?
.map_err(From::from) .ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
.and_then(|toml| match toml { .as_bool()
Some(&Value::Boolean(b)) => Ok(b), .ok_or(REK::HeaderTypeError.into())
Some(_) => Err(REK::HeaderTypeError.into()),
None => Err(REK::HeaderFieldMissingError.into()),
})
} }
Ok(RefFlags { Ok(RefFlags {

View file

@ -142,20 +142,16 @@ fn check_changed<R: Ref>(r: &R) -> bool {
} }
fn check_changed_content<R: Ref>(r: &R) -> bool { fn check_changed_content<R: Ref>(r: &R) -> bool {
let eq = r.get_current_hash() r.get_current_hash()
.and_then(|hash| r.get_stored_hash().map(|stored| (hash, stored))) .and_then(|hash| r.get_stored_hash().map(|stored| (hash, stored)))
.map(|(hash, stored)| hash == stored); .map(|(hash, stored)| hash == stored)
.unwrap_or_else(|e| {
match eq {
Ok(eq) => eq,
Err(e) => {
warn!("Could not check whether the ref changed on the FS"); warn!("Could not check whether the ref changed on the FS");
trace_error(&e); trace_error(&e);
// We continue here and tell the callee that this reference is unchanged // We continue here and tell the callee that this reference is unchanged
false false
}, })
}
} }
fn check_changed_permiss<R: Ref>(_: &R) -> bool { fn check_changed_permiss<R: Ref>(_: &R) -> bool {

View file

@ -140,17 +140,12 @@ impl Ref for Entry {
/// Get the hahs of the link target which is stored in the ref object, which is hashed with a /// Get the hahs of the link target which is stored in the ref object, which is hashed with a
/// custom Hasher instance. /// custom Hasher instance.
fn get_stored_hash_with_hasher<H: Hasher>(&self, h: &H) -> Result<String> { fn get_stored_hash_with_hasher<H: Hasher>(&self, h: &H) -> Result<String> {
match self.get_header().read(&format!("ref.content_hash.{}", h.hash_name())[..])? { self.get_header()
// content hash stored... .read(&format!("ref.content_hash.{}", h.hash_name())[..])?
Some(&Value::String(ref s)) => Ok(s.clone()), .ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
.as_str()
// content hash header field has wrong type .map(String::from)
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)), .ok_or(RE::from_kind(REK::HeaderTypeError))
// content hash not stored
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
}
} }
/// Get the hash of the link target by reading the link target and hashing the contents /// Get the hash of the link target by reading the link target and hashing the contents
@ -207,11 +202,9 @@ impl Ref for Entry {
.read("ref.permissions.ro") .read("ref.permissions.ro")
.chain_err(|| REK::HeaderFieldReadError) .chain_err(|| REK::HeaderFieldReadError)
.and_then(|ro| { .and_then(|ro| {
match ro { ro.ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
Some(&Value::Boolean(b)) => Ok(b), .as_bool()
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)), .ok_or(RE::from_kind(REK::HeaderTypeError))
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
}
}) })
.and_then(|ro| self.get_current_permissions().map(|perm| ro == perm.readonly())) .and_then(|ro| self.get_current_permissions().map(|perm| ro == perm.readonly()))
.chain_err(|| REK::RefTargetCannotReadPermissions) .chain_err(|| REK::RefTargetCannotReadPermissions)
@ -251,11 +244,12 @@ impl Ref for Entry {
/// Get the path of the file which is reffered to by this Ref /// Get the path of the file which is reffered to by this Ref
fn fs_file(&self) -> Result<PathBuf> { fn fs_file(&self) -> Result<PathBuf> {
match self.get_header().read("ref.path")? { self.get_header()
Some(&Value::String(ref s)) => Ok(PathBuf::from(s)), .read("ref.path")?
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)), .ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
None => Err(RE::from_kind(REK::HeaderFieldMissingError)), .as_str()
} .map(PathBuf::from)
.ok_or(RE::from_kind(REK::HeaderTypeError))
} }
/// Re-find a referenced file /// Re-find a referenced file

View file

@ -25,7 +25,6 @@ use error::Result;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use toml::Value;
use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadExt;
/// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash
@ -34,22 +33,22 @@ pub fn hash_path(pb: &PathBuf) -> Result<String> {
use crypto::sha1::Sha1; use crypto::sha1::Sha1;
use crypto::digest::Digest; use crypto::digest::Digest;
match pb.to_str() { pb.to_str()
Some(s) => { .ok_or(RE::from_kind(REK::PathUTF8Error))
.map(|s| {
let mut hasher = Sha1::new(); let mut hasher = Sha1::new();
hasher.input_str(s); hasher.input_str(s);
Ok(hasher.result_str()) hasher.result_str()
}, })
None => return Err(RE::from_kind(REK::PathUTF8Error)),
}
} }
/// Read the reference from a file /// Read the reference from a file
pub fn read_reference(refentry: &Entry) -> Result<PathBuf> { pub fn read_reference(refentry: &Entry) -> Result<PathBuf> {
match refentry.get_header().read("ref.path")? { refentry.get_header()
Some(&Value::String(ref s)) => Ok(PathBuf::from(s)), .read("ref.path")?
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)), .ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
None => Err(RE::from_kind(REK::HeaderFieldMissingError)), .as_str()
} .ok_or(RE::from_kind(REK::HeaderTypeError))
.map(PathBuf::from)
} }

View file

@ -49,17 +49,23 @@ pub trait Tagable {
impl Tagable for Value { impl Tagable for Value {
fn get_tags(&self) -> Result<Vec<Tag>> { fn get_tags(&self) -> Result<Vec<Tag>> {
let tags = self.read("tag.values").chain_err(|| TagErrorKind::HeaderReadError)?; self.read("tag.values")
.chain_err(|| TagErrorKind::HeaderReadError)?
match tags { .map(|val| {
Some(&Value::Array(ref tags)) => { debug!("Got Value of tags...");
val.as_array()
.map(|tags| {
debug!("Got Array<T> of tags...");
if !tags.iter().all(|t| is_match!(*t, Value::String(_))) { if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
debug!("Got Array<T>, T != String of tags: {:?}", tags);
return Err(TagErrorKind::TagTypeError.into()); return Err(TagErrorKind::TagTypeError.into());
} }
debug!("Got Array<String> of tags...");
if tags.iter().any(|t| match *t { if tags.iter().any(|t| match *t {
Value::String(ref s) => !is_tag_str(s).is_ok(), Value::String(ref s) => !is_tag_str(s).is_ok(),
_ => unreachable!()}) _ => unreachable!()})
{ {
debug!("At least one tag is not a valid tag string");
return Err(TagErrorKind::NotATag.into()); return Err(TagErrorKind::NotATag.into());
} }
@ -72,10 +78,10 @@ impl Tagable for Value {
} }
}) })
.collect()) .collect())
}, })
None => Ok(vec![]), .unwrap_or(Ok(vec![]))
_ => Err(TagErrorKind::TagTypeError.into()), })
} .unwrap_or(Ok(vec![]))
} }
fn set_tags(&mut self, ts: &[Tag]) -> Result<()> { fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {

View file

@ -42,40 +42,36 @@ impl Readline {
let histignspace = c.lookup("ui.cli.readline_history_ignore_space").ok_or(IEK::ConfigError)?; let histignspace = c.lookup("ui.cli.readline_history_ignore_space").ok_or(IEK::ConfigError)?;
let prompt = c.lookup("ui.cli.readline_prompt").ok_or(IEK::ConfigError)?; let prompt = c.lookup("ui.cli.readline_prompt").ok_or(IEK::ConfigError)?;
let histfile = match histfile { let histfile = histfile
Value::String(s) => PathBuf::from(s), .as_str()
_ => Err(IE::from_kind(IEK::ConfigTypeError)) .map(PathBuf::from)
.ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError) .chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError) .chain_err(|| IEK::ReadlineError)?;
}?;
let histsize = match histsize { let histsize = histsize
Value::Integer(i) => i, .as_int()
_ => Err(IE::from_kind(IEK::ConfigTypeError)) .ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError) .chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError) .chain_err(|| IEK::ReadlineError)?;
}?;
let histigndups = match histigndups { let histigndups = histigndups
Value::Boolean(b) => b, .as_bool()
_ => Err(IE::from_kind(IEK::ConfigTypeError)) .ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError) .chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError) .chain_err(|| IEK::ReadlineError)?;
}?;
let histignspace = match histignspace { let histignspace = histignspace
Value::Boolean(b) => b, .as_bool()
_ => Err(IE::from_kind(IEK::ConfigTypeError)) .ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError) .chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError) .chain_err(|| IEK::ReadlineError)?;
}?;
let prompt = match prompt { let prompt = prompt
Value::String(s) => s, .as_str()
_ => Err(IE::from_kind(IEK::ConfigTypeError)) .ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError) .chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError) .chain_err(|| IEK::ReadlineError)?;
}?;
let config = Config::builder(). let config = Config::builder().
.max_history_size(histsize) .max_history_size(histsize)

View file

@ -70,14 +70,13 @@ pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> {
pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Vec<StoreId>> { pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Vec<StoreId>> {
use interactor::{pick_file, default_menu_cmd}; use interactor::{pick_file, default_menu_cmd};
match get_id(matches).chain_err(|| IEK::IdSelectingError) { get_id(matches)
Ok(v) => Ok(v), .chain_err(|| IEK::IdSelectingError)
Err(_) => { .or_else(|_| {
let path = store_path.clone(); let path = store_path.clone();
let p = pick_file(default_menu_cmd, path).chain_err(|| IEK::IdSelectingError)?; let p = pick_file(default_menu_cmd, path).chain_err(|| IEK::IdSelectingError)?;
let id = StoreId::new_baseless(p).chain_err(|| IEK::StoreIdParsingError)?; let id = StoreId::new_baseless(p).chain_err(|| IEK::StoreIdParsingError)?;
Ok(vec![id]) Ok(vec![id])
}, })
}
} }