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
};
match ::toml::de::from_str::<::toml::Value>(&content[..]) {
Ok(res) => Some(res),
Err(e) => {
::toml::de::from_str::<::toml::Value>(&content[..])
.map(Some)
.unwrap_or_else(|e| {
let line_col = e
.line_col()
.map(|(line, col)| {
format!("Line {}, Column {}", line, col)
})
.map(|(line, col)| format!("Line {}, Column {}", line, col))
.unwrap_or_else(|| String::from("Line unknown, Column unknown"));
let _ = write!(stderr(), "Config file parser error at {}", line_col);
trace_error(&e);
None
}
}
})
})
.nth(0)
.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()
.map(|s| { debug!("Trying to process '{}'", s); s })
.filter_map(|s| match s.into_kv() {
Some(kv) => Some(kv.into()),
None => {
warn!("Could split at '=' - will be ignore override");
None
}
})
.map(|(k, v)| val
.read(&k[..])
.chain_err(|| REK::ConfigTOMLParserError)
.map(|toml| match toml {
Some(value) => match into_value(value, v) {
Some(v) => {
info!("Successfully overridden: {} = {}", k, v);
Ok(())
},
None => Err(RE::from_kind(REK::ConfigOverrideTypeNotMatching)),
},
None => Err(RE::from_kind(REK::ConfigOverrideKeyNotAvailable)),
})
);
.filter_map(|s| s.into_kv().map(Into::into).or_else(|| {
warn!("Could split at '=' - will be ignore override");
None
}))
.map(|(k, v)| {
let value = val
.read(&k)
.chain_err(|| REK::ConfigTOMLParserError)?
.ok_or(RE::from_kind(REK::ConfigOverrideKeyNotAvailable))?;
into_value(value, v)
.map(|v| info!("Successfully overridden: {} = {}", k, v))
.ok_or_else(|| RE::from_kind(REK::ConfigOverrideTypeNotMatching))
});
for elem in iter {
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 {
let cfg_loglevel = match cfg.read("imag.logging.level") {
Ok(Some(&Value::String(ref s))) => match_log_level_str(s),
Ok(Some(_)) => {
let cfg_loglevel = cfg
.read("imag.logging.level")?
.ok_or(RE::from_kind(EK::GlobalLogLevelConfigMissing))?
.as_str()
.ok_or_else(|| {
let path = "imag.logging.level".to_owned();
let ty = "String";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
},
Ok(None) => return Err(RE::from_kind(EK::GlobalLogLevelConfigMissing)),
Err(e) => return Err(e).map_err(From::from),
}?;
RE::from_kind(EK::ConfigTypeError(path, ty))
})
.and_then(match_log_level_str)?;
if let Some(cli_loglevel) = get_arg_loglevel(matches)? {
if cli_loglevel > cfg_loglevel {
@ -285,14 +285,13 @@ fn translate_destinations(raw: &Vec<Value>) -> Result<Vec<LogDestination>> {
raw.iter()
.fold(Ok(vec![]), |acc, val| {
acc.and_then(|mut v| {
let dest = match *val {
Value::String(ref s) => translate_destination(s)?,
_ => {
let dest = val.as_str()
.ok_or_else(|| {
let path = "imag.logging.modules.<mod>.destinations".to_owned();
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);
Ok(v)
})
@ -304,16 +303,16 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
{
match config {
Some(cfg) => match cfg.read("imag.logging.destinations") {
Ok(Some(&Value::Array(ref a))) => translate_destinations(a),
Ok(Some(_)) => {
Some(cfg) => cfg
.read("imag.logging.destinations")?
.ok_or_else(|| RE::from_kind(EK::GlobalDestinationConfigMissing))?
.as_array()
.ok_or_else(|| {
let path = "imag.logging.destinations".to_owned();
let ty = "Array";
Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
},
Ok(None) => Err(RE::from_kind(EK::GlobalDestinationConfigMissing)),
Err(e) => Err(e).map_err(From::from),
},
RE::from_kind(EK::ConfigTypeError(path, ty))
})
.and_then(translate_destinations),
None => {
if let Some(values) = matches.value_of(Runtime::arg_logdest_name()) {
// parse logdest specification from commandline
@ -334,12 +333,12 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
macro_rules! aggregate_global_format {
($read_str:expr, $error_kind_if_missing:expr, $config:expr) => {
match try!($config.ok_or(RE::from_kind($error_kind_if_missing))).read($read_str) {
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
Ok(Some(_)) => Err(RE::from_kind(EK::ConfigTypeError($read_str.to_owned(), "String"))),
Ok(None) => Err(RE::from_kind($error_kind_if_missing)),
Err(e) => Err(e).map_err(From::from),
}
try!($config.ok_or(RE::from_kind($error_kind_if_missing)))
.read($read_str)?
.ok_or_else(|| RE::from_kind($error_kind_if_missing))?
.as_str()
.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>)
-> 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 {
Some(cfg) => match cfg.read("imag.logging.modules") {
Ok(Some(&Value::Table(ref t))) => {
@ -393,35 +404,39 @@ fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
let mut settings = BTreeMap::new();
for (module_name, v) in t {
let destinations = match v.read("destinations")? {
Some(&Value::Array(ref a)) => Some(translate_destinations(a)?),
None => None,
Some(_) => {
let path = "imag.logging.modules.<mod>.destinations".to_owned();
let ty = "Array";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
},
let destinations = inner_try! {
v.read("destinations")?
.map(|val| {
val.as_array()
.ok_or_else(|| {
let path = "imag.logging.modules.<mod>.destinations".to_owned();
let ty = "Array";
RE::from_kind(EK::ConfigTypeError(path, ty))
})
.and_then(translate_destinations)
})
};
let level = match v.read("level")? {
Some(&Value::String(ref s)) => Some(match_log_level_str(s)?),
None => None,
Some(_) => {
let path = "imag.logging.modules.<mod>.level".to_owned();
let ty = "String";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
},
let level = inner_try! {
v.read("level")?
.map(|val| {
val.as_str()
.ok_or_else(|| {
let path = "imag.logging.modules.<mod>.level".to_owned();
let ty = "String";
RE::from_kind(EK::ConfigTypeError(path, ty))
})
.and_then(match_log_level_str)
})
};
let enabled = match v.read("enabled")? {
Some(&Value::Boolean(b)) => b,
None => false,
Some(_) => {
let enabled = v.read("enabled")?
.map(|v| v.as_bool().unwrap_or(false))
.ok_or_else(|| {
let path = "imag.logging.modules.<mod>.enabled".to_owned();
let ty = "Boolean";
return Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
},
};
RE::from_kind(EK::ConfigTypeError(path, ty))
})?;
let module_settings = ModuleSettings {
enabled: enabled,

View file

@ -325,10 +325,11 @@ impl Store {
debug!("Creating id: '{}'", id);
{
let mut hsmap = match self.entries.write() {
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)).chain_err(|| SEK::CreateCallError),
Ok(s) => s,
};
let mut hsmap = self
.entries
.write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
.chain_err(|| SEK::CreateCallError)?;
if hsmap.contains_key(&id) {
debug!("Cannot create, internal cache already contains: '{}'", id);
@ -480,10 +481,7 @@ impl Store {
/// - Errors StoreEntry::write_entry() might return
///
fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
let mut hsmap = match self.entries.write() {
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
Ok(e) => e,
};
let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?;
let se = hsmap.get_mut(&entry.location).ok_or_else(|| {
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> {
let id = id.into_storeid()?.with_base(self.path().clone());
debug!("Retrieving copy of '{}'", id);
let entries = match self.entries.write() {
Err(_) => {
return Err(SE::from_kind(SEK::LockPoisoned))
.chain_err(|| SEK::RetrieveCopyCallError);
},
Ok(e) => e,
};
let entries = self.entries.write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
.chain_err(|| SEK::RetrieveCopyCallError)?;
// 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) {
@ -552,11 +546,11 @@ impl Store {
debug!("Deleting id: '{}'", id);
{
let mut entries = match self.entries.write() {
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned))
.chain_err(|| SEK::DeleteCallError),
Ok(e) => e,
};
let mut entries = self
.entries
.write()
.map_err(|_| SE::from_kind(SEK::LockPoisoned))
.chain_err(|| SEK::DeleteCallError)?;
// if the entry is currently modified by the user, we cannot drop it
match entries.get(&id) {
@ -588,11 +582,11 @@ impl Store {
// remove the entry first, then the file
entries.remove(&id);
let pb = id.clone().with_base(self.path().clone()).into_pathbuf()?;
if let Err(e) = self.backend.remove_file(&pb) {
return Err(e)
.chain_err(|| SEK::FileError)
.chain_err(|| SEK::DeleteCallError);
}
let _ = self
.backend
.remove_file(&pb)
.chain_err(|| SEK::FileError)
.chain_err(|| SEK::DeleteCallError)?;
}
debug!("Deleted");
@ -631,14 +625,13 @@ impl Store {
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()?;
self.backend.copy(&old_id_as_path, &new_id_as_path)
.and_then(|_| {
if remove_old {
debug!("Removing old '{:?}'", old_id_as_path);
self.backend.remove_file(&old_id_as_path)
} else {
Ok(())
}
self.backend
.copy(&old_id_as_path, &new_id_as_path)
.and_then(|_| if remove_old {
debug!("Removing old '{:?}'", old_id_as_path);
self.backend.remove_file(&old_id_as_path)
} else {
Ok(())
})
.chain_err(|| SEK::FileError)
.chain_err(|| SEK::MoveCallError)
@ -684,10 +677,7 @@ impl Store {
debug!("Moving '{}' to '{}'", old_id, new_id);
{
let mut hsmap = match self.entries.write() {
Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
Ok(m) => m,
};
let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?;
if hsmap.contains_key(&new_id) {
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone())));
@ -711,22 +701,21 @@ impl Store {
}
debug!("New entry does not yet exist on filesystem. Good.");
match self.backend.rename(&old_id_pb, &new_id_pb) {
Err(e) => return Err(e).chain_err(|| SEK::EntryRenameError(old_id_pb, new_id_pb)),
Ok(_) => {
debug!("Rename worked on filesystem");
let _ = self
.backend
.rename(&old_id_pb, &new_id_pb)
.chain_err(|| SEK::EntryRenameError(old_id_pb, new_id_pb))?;
// assert enforced through check hsmap.contains_key(&new_id) above.
// Should therefor never fail
assert!(hsmap
.remove(&old_id)
.and_then(|mut entry| {
entry.id = new_id.clone();
hsmap.insert(new_id.clone(), entry)
}).is_none())
}
}
debug!("Rename worked on filesystem");
// assert enforced through check hsmap.contains_key(&new_id) above.
// Should therefor never fail
assert!(hsmap
.remove(&old_id)
.and_then(|mut entry| {
entry.id = new_id.clone();
hsmap.insert(new_id.clone(), entry)
}).is_none())
}
debug!("Moved");
@ -1035,16 +1024,11 @@ mod glob_store_iter {
while let Some(o) = self.paths.next() {
debug!("GlobStoreIdIterator::next() => {:?}", o);
match o.chain_err(|| SEK::StoreIdHandlingError) {
Err(e) => return Some(Err(e)),
Ok(path) => {
if path.exists() && path.is_file() {
return match StoreId::from_full_path(&self.store_path, path) {
Ok(id) => Some(Ok(id)),
Err(e) => Some(Err(e)),
}
/* } else { */
/* continue */
}
Err(e) => return Some(Err(e)),
Ok(path) => if path.exists() && path.is_file() {
return Some(StoreId::from_full_path(&self.store_path, path));
/* } else { */
/* continue */
}
}
}

View file

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

View file

@ -30,6 +30,7 @@ use error::*;
use iter::HabitInstanceStoreIdIterator;
use util::date_to_string;
use util::IsHabitCheck;
use util::get_string_header_from_entry;
use libimagentrylink::internal::InternalLinker;
use libimagstore::store::Store;
@ -202,27 +203,26 @@ impl HabitTemplate for Entry {
}
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> {
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> {
get_string_header_from_habit(self, "habit.template.recurspec")
get_string_header_from_entry(self, "habit.template.recurspec")
}
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>> {
match self.get_header().read("habit.template.until")? {
Some(&Value::String(ref s)) => Ok(Some(s.clone())),
Some(_) => Err(HEK::HeaderTypeError("habit.template.until", "String").into()),
None => Ok(None),
}
self.get_header()
.read("habit.template.until")?
.map(|v| v.as_str().map(String::from))
.ok_or(HEK::HeaderTypeError("habit.template.until", "String").into())
}
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)
}
#[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 {
use toml::Value;
use toml_query::insert::TomlValueInsertExt;

View file

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

View file

@ -34,8 +34,8 @@ pub fn date_to_string(ndt: &NaiveDate) -> String {
ndt.format(NAIVE_DATE_STRING_FORMAT).to_string()
}
pub fn date_from_string(s: &str) -> Result<NaiveDate> {
NaiveDate::parse_from_str(s, NAIVE_DATE_STRING_FORMAT).map_err(From::from)
pub fn date_from_string(s: String) -> Result<NaiveDate> {
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
@ -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 {
fn is_log(&self) -> Result<bool> {
let location = "log.is_log";
match self.get_header().read(location)? {
Some(&Value::Boolean(b)) => Ok(b),
Some(_) => Err(LE::from_kind(LEK::HeaderTypeError("boolean", location))),
None => Ok(false)
}
self.get_header()
.read(location)?
.ok_or(LE::from_kind(LEK::HeaderTypeError("boolean", location)))
.map(|v| v.as_bool().unwrap_or(false))
}
fn make_log_entry(&mut self) -> Result<()> {

View file

@ -46,13 +46,12 @@ impl Note for Entry {
}
fn get_name(&self) -> Result<String> {
match self.get_header().read("note.name") {
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
Ok(_) => {
Err(NE::from_kind(NEK::HeaderTypeError)).chain_err(|| NEK::StoreReadError)
},
Err(e) => Err(e).chain_err(|| NEK::StoreReadError)
}
self.get_header()
.read("note.name")
.chain_err(|| NEK::StoreReadError)?
.and_then(Value::as_str)
.map(String::from)
.ok_or(NE::from_kind(NEK::HeaderTypeError))
}
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> {
self.inner.next().map(|sid| {
match self.store.get(sid).chain_err(|| TTEK::StoreReadError) {
Ok(None) => Err(TTE::from_kind(TTEK::StoreReadError)),
Ok(Some(s)) => Ok(s),
Err(e) => Err(e)
}
self.store
.get(sid)
.chain_err(|| TTEK::StoreReadError)?
.ok_or(TTE::from_kind(TTEK::StoreReadError))
})
}
}

View file

@ -65,11 +65,13 @@ impl TimeTracking for Entry {
fn get_timetrack_tag(&self) -> Result<TTT> {
self.get_header()
.read(DATE_TIME_TAG_HEADER_PATH)
.chain_err(|| TTEK::HeaderReadError)
.and_then(|value| match value {
Some(&Value::String(ref s)) => Ok(s.clone().into()),
Some(_) => Err(TTE::from_kind(TTEK::HeaderFieldTypeError)),
_ => Err(TTE::from_kind(TTEK::HeaderReadError))
.chain_err(|| TTEK::HeaderReadError)?
.ok_or(TTE::from_kind(TTEK::HeaderReadError))
.and_then(|v| {
v.as_str()
.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 uuid::Uuid;
use toml::Value;
use toml_query::read::TomlValueReadExt;
pub trait Task {
@ -34,14 +33,13 @@ pub trait Task {
impl Task for Entry {
fn get_uuid(&self) -> Result<Uuid> {
match self.get_header().read("todo.uuid") {
Ok(Some(&Value::String(ref uuid))) => {
Uuid::parse_str(uuid).chain_err(|| TEK::UuidParserError)
},
Ok(Some(_)) => Err(TE::from_kind(TEK::HeaderTypeError)),
Ok(None) => Err(TE::from_kind(TEK::HeaderFieldMissing)),
Err(e) => Err(e).chain_err(|| TEK::StoreError),
}
self.get_header()
.read("todo.uuid")
.chain_err(|| TEK::StoreError)?
.ok_or(TE::from_kind(TEK::HeaderFieldMissing))?
.as_str()
.ok_or(TE::from_kind(TEK::HeaderTypeError))
.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> {
self.get_header()
.read("annotation.is_annotation")
.map_err(From::from)
.and_then(|res| match res {
Some(&Value::Boolean(b)) => Ok(b),
None => Ok(false),
_ => Err(AE::from_kind(AEK::HeaderTypeError)),
})
.read("annotation.is_annotation")?
.map(|val| val.as_bool().unwrap_or(false))
.ok_or(AE::from_kind(AEK::HeaderTypeError))
}
}

View file

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

View file

@ -22,6 +22,14 @@ error_chain! {
CategoryError, CategoryErrorKind, ResultExt, Result;
}
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
}
foreign_links {
TomlQueryError(::toml_query::error::Error);
}
errors {
StoreReadError {
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)
.and_then(|fle| {
if let Some(fle) = fle {
match fle.get_header()
fle.get_header()
.read(&String::from(CATEGORY_REGISTER_NAME_FIELD_PATH))
.chain_err(|| CEK::HeaderReadError)
{
Ok(Some(&Value::String(ref s))) => Ok(s == name),
Ok(_) => Err(CE::from_kind(CEK::TypeError)),
Err(e) => Err(e).chain_err(|| CEK::HeaderReadError),
}
.chain_err(|| CEK::HeaderReadError)?
.ok_or(CE::from_kind(CEK::TypeError))?
.as_str()
.map(|s| s == name)
.ok_or(CE::from_kind(CEK::TypeError))
} else {
Ok(false)
}
@ -276,14 +275,15 @@ impl<'a> Iterator for CategoryNameIter<'a> {
.next()
.map(|sid| {
self.0
.get(sid)
.chain_err(|| CEK::StoreReadError)
.and_then(|fle| fle.ok_or(CE::from_kind(CEK::StoreReadError)))
.and_then(|fle| match fle.get_header().read(&query) {
Ok(Some(&Value::String(ref s))) => Ok(Category::from(s.clone())),
Ok(_) => Err(CE::from_kind(CEK::TypeError)),
Err(e) => Err(e).chain_err(|| CEK::HeaderReadError),
})
.get(sid)?
.ok_or_else(|| CE::from_kind(CEK::StoreReadError))?
.get_header()
.read(&query)
.chain_err(|| CEK::HeaderReadError)?
.and_then(Value::as_str)
.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)
.chain_err(|| DEK::ReadDateError)
.and_then(|v| {
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)),
}
v.ok_or(DE::from_kind(DEK::ReadDateError))?
.as_str()
.ok_or(DE::from_kind(DEK::DateHeaderFieldTypeError))?
.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError)
})
}
@ -94,11 +93,10 @@ impl EntryDate for Entry {
self.get_header_mut()
.insert(&DATE_HEADER_LOCATION, Value::String(date))
.map(|opt| opt.map(|stri| {
match stri {
Value::String(ref s) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
}
stri.as_str()
.ok_or(DE::from_kind(DEK::DateHeaderFieldTypeError))?
.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError)
}))
.chain_err(|| DEK::SetDateError)
}
@ -129,30 +127,15 @@ impl EntryDate for Entry {
.get_header()
.read(&DATE_RANGE_START_HEADER_LOCATION)
.chain_err(|| DEK::ReadDateTimeRangeError)
.and_then(|v| {
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)),
}
})?;
.and_then(|v| str_to_ndt(v.ok_or(DE::from_kind(DEK::ReadDateError))?))?;
let end = self
.get_header()
.read(&DATE_RANGE_START_HEADER_LOCATION)
.chain_err(|| DEK::ReadDateTimeRangeError)
.and_then(|v| {
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)),
}
})?;
.and_then(|v| str_to_ndt(v.ok_or(DE::from_kind(DEK::ReadDateError))?))?;
DateTimeRange::new(start, end)
.chain_err(|| DEK::DateTimeRangeError)
DateTimeRange::new(start, end).chain_err(|| DEK::DateTimeRangeError)
}
/// Set the date range
@ -171,25 +154,13 @@ impl EntryDate for Entry {
let opt_old_start = self
.get_header_mut()
.insert(&DATE_RANGE_START_HEADER_LOCATION, Value::String(start))
.map(|opt| opt.map(|stri| {
match stri {
Value::String(ref s) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
}
}))
.map(|opt| opt.as_ref().map(str_to_ndt))
.chain_err(|| DEK::SetDateTimeRangeError)?;
let opt_old_end = self
.get_header_mut()
.insert(&DATE_RANGE_END_HEADER_LOCATION, Value::String(end))
.map(|opt| opt.map(|stri| {
match stri {
Value::String(ref s) => s.parse::<NaiveDateTime>()
.chain_err(|| DEK::DateTimeParsingError),
_ => Err(DE::from_kind(DEK::DateHeaderFieldTypeError)),
}
}))
.map(|opt| opt.as_ref().map(str_to_ndt))
.chain_err(|| DEK::SetDateTimeRangeError)?;
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)]
mod tests {
use std::path::PathBuf;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,6 +21,7 @@ use std::collections::BTreeMap;
use toml::Value;
use error::RefError as RE;
use error::RefErrorKind as REK;
use error::Result;
@ -39,13 +40,10 @@ impl RefFlags {
fn get_field(v: &Value, key: &str) -> Result<bool> {
use toml_query::read::TomlValueReadExt;
v.read(key)
.map_err(From::from)
.and_then(|toml| match toml {
Some(&Value::Boolean(b)) => Ok(b),
Some(_) => Err(REK::HeaderTypeError.into()),
None => Err(REK::HeaderFieldMissingError.into()),
})
v.read(key)?
.ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
.as_bool()
.ok_or(REK::HeaderTypeError.into())
}
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 {
let eq = r.get_current_hash()
r.get_current_hash()
.and_then(|hash| r.get_stored_hash().map(|stored| (hash, stored)))
.map(|(hash, stored)| hash == stored);
match eq {
Ok(eq) => eq,
Err(e) => {
.map(|(hash, stored)| hash == stored)
.unwrap_or_else(|e| {
warn!("Could not check whether the ref changed on the FS");
trace_error(&e);
// We continue here and tell the callee that this reference is unchanged
false
},
}
})
}
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
/// custom Hasher instance.
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())[..])? {
// content hash stored...
Some(&Value::String(ref s)) => Ok(s.clone()),
// content hash header field has wrong type
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)),
// content hash not stored
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
}
self.get_header()
.read(&format!("ref.content_hash.{}", h.hash_name())[..])?
.ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
.as_str()
.map(String::from)
.ok_or(RE::from_kind(REK::HeaderTypeError))
}
/// 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")
.chain_err(|| REK::HeaderFieldReadError)
.and_then(|ro| {
match ro {
Some(&Value::Boolean(b)) => Ok(b),
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)),
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
}
ro.ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
.as_bool()
.ok_or(RE::from_kind(REK::HeaderTypeError))
})
.and_then(|ro| self.get_current_permissions().map(|perm| ro == perm.readonly()))
.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
fn fs_file(&self) -> Result<PathBuf> {
match self.get_header().read("ref.path")? {
Some(&Value::String(ref s)) => Ok(PathBuf::from(s)),
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)),
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
}
self.get_header()
.read("ref.path")?
.ok_or(RE::from_kind(REK::HeaderFieldMissingError))?
.as_str()
.map(PathBuf::from)
.ok_or(RE::from_kind(REK::HeaderTypeError))
}
/// Re-find a referenced file

View file

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

View file

@ -49,33 +49,39 @@ pub trait Tagable {
impl Tagable for Value {
fn get_tags(&self) -> Result<Vec<Tag>> {
let tags = self.read("tag.values").chain_err(|| TagErrorKind::HeaderReadError)?;
match tags {
Some(&Value::Array(ref tags)) => {
if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
return Err(TagErrorKind::TagTypeError.into());
}
if tags.iter().any(|t| match *t {
Value::String(ref s) => !is_tag_str(s).is_ok(),
_ => unreachable!()})
{
return Err(TagErrorKind::NotATag.into());
}
Ok(tags.iter()
.cloned()
.map(|t| {
match t {
Value::String(s) => s,
_ => unreachable!(),
self.read("tag.values")
.chain_err(|| TagErrorKind::HeaderReadError)?
.map(|val| {
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(_))) {
debug!("Got Array<T>, T != String of tags: {:?}", tags);
return Err(TagErrorKind::TagTypeError.into());
}
debug!("Got Array<String> of tags...");
if tags.iter().any(|t| match *t {
Value::String(ref s) => !is_tag_str(s).is_ok(),
_ => unreachable!()})
{
debug!("At least one tag is not a valid tag string");
return Err(TagErrorKind::NotATag.into());
}
Ok(tags.iter()
.cloned()
.map(|t| {
match t {
Value::String(s) => s,
_ => unreachable!(),
}
})
.collect())
})
.collect())
},
None => Ok(vec![]),
_ => Err(TagErrorKind::TagTypeError.into()),
}
.unwrap_or(Ok(vec![]))
})
.unwrap_or(Ok(vec![]))
}
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 prompt = c.lookup("ui.cli.readline_prompt").ok_or(IEK::ConfigError)?;
let histfile = match histfile {
Value::String(s) => PathBuf::from(s),
_ => Err(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)
}?;
let histfile = histfile
.as_str()
.map(PathBuf::from)
.ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)?;
let histsize = match histsize {
Value::Integer(i) => i,
_ => Err(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)
}?;
let histsize = histsize
.as_int()
.ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)?;
let histigndups = match histigndups {
Value::Boolean(b) => b,
_ => Err(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)
}?;
let histigndups = histigndups
.as_bool()
.ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)?;
let histignspace = match histignspace {
Value::Boolean(b) => b,
_ => Err(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)
}?;
let histignspace = histignspace
.as_bool()
.ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)?;
let prompt = match prompt {
Value::String(s) => s,
_ => Err(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)
}?;
let prompt = prompt
.as_str()
.ok_or(IE::from_kind(IEK::ConfigTypeError))
.chain_err(|| IEK::ConfigError)
.chain_err(|| IEK::ReadlineError)?;
let config = Config::builder().
.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>> {
use interactor::{pick_file, default_menu_cmd};
match get_id(matches).chain_err(|| IEK::IdSelectingError) {
Ok(v) => Ok(v),
Err(_) => {
get_id(matches)
.chain_err(|| IEK::IdSelectingError)
.or_else(|_| {
let path = store_path.clone();
let p = pick_file(default_menu_cmd, path).chain_err(|| IEK::IdSelectingError)?;
let id = StoreId::new_baseless(p).chain_err(|| IEK::StoreIdParsingError)?;
let p = pick_file(default_menu_cmd, path).chain_err(|| IEK::IdSelectingError)?;
let id = StoreId::new_baseless(p).chain_err(|| IEK::StoreIdParsingError)?;
Ok(vec![id])
},
}
})
}