libimagstore: rewrite error handling code

This commit is contained in:
Matthias Beyer 2017-09-02 23:02:53 +02:00
parent 603808a9fa
commit 2df99524e7
12 changed files with 128 additions and 123 deletions

View file

@ -32,7 +32,7 @@ use log::LogLevelFilter;
use configuration::{Configuration, InternalConfiguration}; use configuration::{Configuration, InternalConfiguration};
use error::RuntimeError; use error::RuntimeError;
use error::RuntimeErrorKind; use error::RuntimeErrorKind;
use error::MapErrInto; use error::ResultExt;
use logger::ImagLogger; use logger::ImagLogger;
use libimagstore::store::Store; use libimagstore::store::Store;

View file

@ -19,9 +19,8 @@
use toml::Value; use toml::Value;
use libimagerror::into::IntoError;
use store::Result; use store::Result;
use error::StoreError as SE;
/// Check whether the configuration is valid for the store /// Check whether the configuration is valid for the store
pub fn config_is_valid(config: &Option<Value>) -> Result<()> { pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
@ -35,7 +34,7 @@ pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
Some(Value::Table(_)) => Ok(()), Some(Value::Table(_)) => Ok(()),
_ => { _ => {
warn!("Store config is no table"); warn!("Store config is no table");
Err(SEK::ConfigTypeError.into_error()) Err(SE::from_kind(SEK::ConfigTypeError))
}, },
} }
} }

View file

@ -17,11 +17,19 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::error::Error;
use libimagerror::into::IntoError;
error_chain! { error_chain! {
types { types {
StoreError, StoreErrorKind, ResultExt, Result; StoreError, StoreErrorKind, ResultExt, Result;
} }
foreign_links {
Io(::std::io::Error);
TomlDeserError(::toml::de::Error);
}
errors { errors {
ConfigurationError { ConfigurationError {
@ -294,13 +302,13 @@ error_chain! {
} }
impl IntoError for StoreErrorKind { impl IntoError for StoreErrorKind {
type Target: StoreError; type Target = StoreError;
fn into_error(self) -> Self::Target { fn into_error(self) -> Self::Target {
StoreError::from_kind(self) StoreError::from_kind(self)
} }
fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target { fn into_error_with_cause(self, _: Box<Error>) -> Self::Target {
StoreError::from_kind(self) StoreError::from_kind(self)
} }
} }

View file

@ -21,7 +21,8 @@ use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
use std::io::{Seek, SeekFrom, Read}; use std::io::{Seek, SeekFrom, Read};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK}; use error::{StoreError as SE, StoreErrorKind as SEK};
use error::ResultExt;
use super::FileAbstraction; use super::FileAbstraction;
use super::FileAbstractionInstance; use super::FileAbstractionInstance;
@ -47,22 +48,22 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
// We seek to the beginning of the file since we expect each // We seek to the beginning of the file since we expect each
// access to the file to be in a different context // access to the file to be in a different context
try!(f.seek(SeekFrom::Start(0)) try!(f.seek(SeekFrom::Start(0))
.map_err_into(SEK::FileNotSeeked)); .chain_err(|| SEK::FileNotSeeked));
let mut s = String::new(); let mut s = String::new();
f.read_to_string(&mut s) f.read_to_string(&mut s)
.map_err_into(SEK::IoError) .chain_err(|| SEK::IoError)
.map(|_| s) .map(|_| s)
.and_then(|s| Entry::from_str(id, &s)) .and_then(|s| Entry::from_str(id, &s))
}, },
FSFileAbstractionInstance::Absent(ref p) => FSFileAbstractionInstance::Absent(ref p) =>
(try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()), (try!(open_file(p).chain_err(|| SEK::FileNotFound)), p.clone()),
}; };
*self = FSFileAbstractionInstance::File(file, path); *self = FSFileAbstractionInstance::File(file, path);
if let FSFileAbstractionInstance::File(ref mut f, _) = *self { if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
let mut s = String::new(); let mut s = String::new();
f.read_to_string(&mut s) f.read_to_string(&mut s)
.map_err_into(SEK::IoError) .chain_err(|| SEK::IoError)
.map(|_| s) .map(|_| s)
.and_then(|s| Entry::from_str(id, &s)) .and_then(|s| Entry::from_str(id, &s))
} else { } else {
@ -83,18 +84,18 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
// We seek to the beginning of the file since we expect each // We seek to the beginning of the file since we expect each
// access to the file to be in a different context // access to the file to be in a different context
try!(f.seek(SeekFrom::Start(0)) try!(f.seek(SeekFrom::Start(0))
.map_err_into(SEK::FileNotCreated)); .chain_err(|| SEK::FileNotCreated));
try!(f.set_len(buf.len() as u64).map_err_into(SEK::FileNotWritten)); try!(f.set_len(buf.len() as u64).chain_err(|| SEK::FileNotWritten));
f.write_all(&buf).map_err_into(SEK::FileNotWritten) f.write_all(&buf).chain_err(|| SEK::FileNotWritten)
}, },
FSFileAbstractionInstance::Absent(ref p) => FSFileAbstractionInstance::Absent(ref p) =>
(try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()), (try!(create_file(p).chain_err(|| SEK::FileNotCreated)), p.clone()),
}; };
*self = FSFileAbstractionInstance::File(file, path); *self = FSFileAbstractionInstance::File(file, path);
if let FSFileAbstractionInstance::File(ref mut f, _) = *self { if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
return f.write_all(&buf).map_err_into(SEK::FileNotWritten); return f.write_all(&buf).chain_err(|| SEK::FileNotWritten);
} }
unreachable!(); unreachable!();
} }
@ -117,19 +118,19 @@ impl FSFileAbstraction {
impl FileAbstraction for FSFileAbstraction { impl FileAbstraction for FSFileAbstraction {
fn remove_file(&self, path: &PathBuf) -> Result<(), SE> { fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
remove_file(path).map_err_into(SEK::FileNotRemoved) remove_file(path).chain_err(|| SEK::FileNotRemoved)
} }
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> { fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ()) copy(from, to).chain_err(|| SEK::FileNotCopied).map(|_| ())
} }
fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> { fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
rename(from, to).map_err_into(SEK::FileNotRenamed) rename(from, to).chain_err(|| SEK::FileNotRenamed)
} }
fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> { fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
create_dir_all(path).map_err_into(SEK::DirNotCreated) create_dir_all(path).chain_err(|| SEK::DirNotCreated)
} }
fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> { fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {

View file

@ -17,23 +17,24 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::path::PathBuf;
use error::StoreError as SE; use error::StoreError as SE;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use std::path::PathBuf;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::Arc; use std::sync::Arc;
use std::ops::Deref; use std::ops::Deref;
use libimagerror::into::IntoError;
use super::FileAbstraction; use super::FileAbstraction;
use super::FileAbstractionInstance; use super::FileAbstractionInstance;
use super::Drain; use super::Drain;
use store::Entry; use store::Entry;
use storeid::StoreId; use storeid::StoreId;
use libimagerror::into::IntoError;
type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Entry>>>>; type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Entry>>>>;
/// `FileAbstraction` type, this is the Test version! /// `FileAbstraction` type, this is the Test version!
@ -64,16 +65,15 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
fn get_file_content(&mut self, _: StoreId) -> Result<Entry, SE> { fn get_file_content(&mut self, _: StoreId) -> Result<Entry, SE> {
debug!("Getting lazy file: {:?}", self); debug!("Getting lazy file: {:?}", self);
match self.fs_abstraction.lock() { self.fs_abstraction
Ok(mut mtx) => { .lock()
.map_err(|_| SEK::LockError.into_error())
.and_then(|mut mtx| {
mtx.get_mut() mtx.get_mut()
.get(&self.absent_path) .get(&self.absent_path)
.cloned() .cloned()
.ok_or(SEK::FileNotFound.into_error()) .ok_or(SEK::FileNotFound.into_error())
} })
Err(_) => Err(SEK::LockError.into_error())
}
} }
fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> { fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
@ -163,7 +163,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
fn fill<'a>(&'a mut self, mut d: Drain) -> Result<(), SE> { fn fill<'a>(&'a mut self, mut d: Drain) -> Result<(), SE> {
debug!("Draining into : {:?}", self); debug!("Draining into : {:?}", self);
let mut mtx = try!(self.backend().lock().map_err(|_| SEK::LockError.into_error())); let mut mtx = try!(self.backend().lock().map_err(|_| SEK::LockError));
let backend = mtx.get_mut(); let backend = mtx.get_mut();
for (path, element) in d.iter() { for (path, element) in d.iter() {

View file

@ -25,14 +25,13 @@ use serde_json;
use toml; use toml;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use error::MapErrInto; use error::StoreError as SE;
use error::ResultExt;
use super::Mapper; use super::Mapper;
use store::Result; use store::Result;
use store::Entry; use store::Entry;
use storeid::StoreId; use storeid::StoreId;
use libimagerror::into::IntoError;
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct BackendEntry { struct BackendEntry {
header: serde_json::Value, header: serde_json::Value,
@ -43,7 +42,7 @@ impl BackendEntry {
fn to_string(self) -> Result<String> { fn to_string(self) -> Result<String> {
toml::to_string(&self.header) toml::to_string(&self.header)
.map_err_into(SEK::IoError) .chain_err(|| SEK::IoError)
.map(|hdr| { .map(|hdr| {
format!("---\n{header}---\n{content}", format!("---\n{header}---\n{content}",
header = hdr, header = hdr,
@ -74,16 +73,16 @@ impl Mapper for JsonMapper {
let mut document = { let mut document = {
debug!("Reading Document"); debug!("Reading Document");
let mut s = String::new(); let mut s = String::new();
try!(r.read_to_string(&mut s).map_err_into(SEK::IoError)); try!(r.read_to_string(&mut s).chain_err(|| SEK::IoError));
debug!("Document = {:?}", s); debug!("Document = {:?}", s);
debug!("Parsing Document"); debug!("Parsing Document");
let doc : Document = try!(serde_json::from_str(&s).map_err_into(SEK::IoError)); let doc : Document = try!(serde_json::from_str(&s).chain_err(|| SEK::IoError));
debug!("Document = {:?}", doc); debug!("Document = {:?}", doc);
doc doc
}; };
let _ = try!(::semver::Version::parse(&document.version) let _ = try!(::semver::Version::parse(&document.version)
.map_err_into(SEK::VersionError) .chain_err(|| SEK::VersionError)
.and_then(|doc_vers| { .and_then(|doc_vers| {
// safe because cargo does not compile if crate version is not valid // safe because cargo does not compile if crate version is not valid
let crate_version = ::semver::Version::parse(version!()).unwrap(); let crate_version = ::semver::Version::parse(version!()).unwrap();
@ -93,7 +92,7 @@ impl Mapper for JsonMapper {
crate_vers = crate_version); crate_vers = crate_version);
if doc_vers > crate_version { if doc_vers > crate_version {
Err(SEK::VersionError.into_error()) Err(SE::from_kind(SEK::VersionError))
} else { } else {
Ok(()) Ok(())
} }
@ -150,9 +149,9 @@ impl Mapper for JsonMapper {
}; };
serde_json::to_string(&doc) serde_json::to_string(&doc)
.map_err_into(SEK::IoError) .chain_err(|| SEK::IoError)
.and_then(|json| out.write(&json.into_bytes()).map_err_into(SEK::IoError)) .and_then(|json| out.write(&json.into_bytes()).chain_err(|| SEK::IoError))
.and_then(|_| out.flush().map_err_into(SEK::IoError)) .and_then(|_| out.flush().chain_err(|| SEK::IoError))
.map(|_| ()) .map(|_| ())
} }
} }

View file

@ -29,8 +29,6 @@ use std::fmt::Debug;
use std::fmt::Error as FmtError; use std::fmt::Error as FmtError;
use std::fmt::Formatter; use std::fmt::Formatter;
use libimagerror::into::IntoError;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use error::StoreError as SE; use error::StoreError as SE;
use super::FileAbstraction; use super::FileAbstraction;
@ -39,6 +37,8 @@ use super::Drain;
use super::InMemoryFileAbstraction; use super::InMemoryFileAbstraction;
use store::Entry; use store::Entry;
use libimagerror::into::IntoError;
pub mod mapper; pub mod mapper;
pub mod out; pub mod out;
use self::mapper::Mapper; use self::mapper::Mapper;
@ -57,11 +57,11 @@ impl<W, M> StdIoFileAbstraction<W, M>
pub fn new<R: Read>(in_stream: &mut R, out_stream: Rc<RefCell<W>>, mapper: M) -> Result<StdIoFileAbstraction<W, M>, SE> { pub fn new<R: Read>(in_stream: &mut R, out_stream: Rc<RefCell<W>>, mapper: M) -> Result<StdIoFileAbstraction<W, M>, SE> {
StdoutFileAbstraction::new(out_stream, mapper) StdoutFileAbstraction::new(out_stream, mapper)
.and_then(|out| { .and_then(|out| {
let fill_res = match out.backend().lock() { let _ = try!(out
Err(_) => Err(SEK::LockError.into_error()), .backend()
Ok(mut mtx) => out.mapper().read_to_fs(in_stream, mtx.get_mut()) .lock()
}; .map_err(|_| SEK::LockError.into_error())
let _ = try!(fill_res); .map(|mut mtx| out.mapper().read_to_fs(in_stream, mtx.get_mut())));
Ok(StdIoFileAbstraction(out)) Ok(StdIoFileAbstraction(out))
}) })

View file

@ -31,8 +31,8 @@ use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::ops::Deref; use std::ops::Deref;
use libimagerror::into::IntoError;
use libimagerror::trace::*; use libimagerror::trace::*;
use libimagerror::into::IntoError;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use error::StoreError as SE; use error::StoreError as SE;
@ -101,7 +101,7 @@ impl<W, M> Drop for StdoutFileAbstraction<W, M>
use std::ops::DerefMut; use std::ops::DerefMut;
let fill_res = match self.mem.backend().lock() { let fill_res = match self.mem.backend().lock() {
Err(_) => Err(SEK::LockError.into_error()), Err(_) => Err(SE::from_kind(SEK::LockError)),
Ok(mut mtx) => { Ok(mut mtx) => {
self.mapper.fs_to_write(mtx.get_mut(), self.out.borrow_mut().deref_mut()) self.mapper.fs_to_write(mtx.get_mut(), self.out.borrow_mut().deref_mut())
}, },

View file

@ -49,7 +49,7 @@ extern crate serde_json;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain; #[macro_use] extern crate error_chain;
#[macro_use] extern crate libimagerror; extern crate libimagerror;
extern crate libimagutil; extern crate libimagutil;
#[macro_use] mod util; #[macro_use] mod util;

View file

@ -38,8 +38,8 @@ use glob::glob;
use walkdir::WalkDir; use walkdir::WalkDir;
use walkdir::Iter as WalkDirIter; use walkdir::Iter as WalkDirIter;
use error::{StoreError as SE, StoreErrorKind as SEK, ParserError, ParserErrorKind}; use error::{StoreError as SE, StoreErrorKind as SEK};
use error::MapErrInto; use error::ResultExt;
use storeid::{IntoStoreId, StoreId, StoreIdIterator}; use storeid::{IntoStoreId, StoreId, StoreIdIterator};
use file_abstraction::FileAbstractionInstance; use file_abstraction::FileAbstractionInstance;
@ -48,8 +48,8 @@ pub use file_abstraction::FileAbstraction;
pub use file_abstraction::FSFileAbstraction; pub use file_abstraction::FSFileAbstraction;
pub use file_abstraction::InMemoryFileAbstraction; pub use file_abstraction::InMemoryFileAbstraction;
use libimagerror::into::IntoError;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use libimagerror::into::IntoError;
use libimagutil::debug_result::*; use libimagutil::debug_result::*;
use self::glob_store_iter::*; use self::glob_store_iter::*;
@ -147,8 +147,8 @@ impl StoreEntry {
#[cfg(feature = "fs-lock")] #[cfg(feature = "fs-lock")]
{ {
try!(open_file(pb.clone()) try!(open_file(pb.clone())
.and_then(|f| f.lock_exclusive().map_err_into(SEK::FileError)) .and_then(|f| f.lock_exclusive().chain_err(|| SEK::FileError))
.map_err_into(SEK::IoError)); .chain_err(|| SEK::IoError));
} }
Ok(StoreEntry { Ok(StoreEntry {
@ -168,13 +168,13 @@ impl StoreEntry {
if !self.is_borrowed() { if !self.is_borrowed() {
self.file self.file
.get_file_content(self.id.clone()) .get_file_content(self.id.clone())
.or_else(|err| if err.err_type() == SEK::FileNotFound { .or_else(|err| if is_match!(err.kind(), &SEK::FileNotFound) {
Ok(Entry::new(self.id.clone())) Ok(Entry::new(self.id.clone()))
} else { } else {
Err(err) Err(err)
}) })
} else { } else {
Err(SE::new(SEK::EntryAlreadyBorrowed, None)) Err(SE::from_kind(SEK::EntryAlreadyBorrowed))
} }
} }
@ -182,7 +182,7 @@ impl StoreEntry {
if self.is_borrowed() { if self.is_borrowed() {
assert_eq!(self.id, entry.location); assert_eq!(self.id, entry.location);
self.file.write_file_content(entry) self.file.write_file_content(entry)
.map_err_into(SEK::FileError) .chain_err(|| SEK::FileError)
.map(|_| ()) .map(|_| ())
} else { } else {
Ok(()) Ok(())
@ -195,9 +195,9 @@ impl Drop for StoreEntry {
fn drop(self) { fn drop(self) {
self.get_entry() self.get_entry()
.and_then(|entry| open_file(entry.get_location().clone()).map_err_into(SEK::IoError)) .and_then(|entry| open_file(entry.get_location().clone()).chain_err(|| SEK::IoError))
.and_then(|f| f.unlock().map_err_into(SEK::FileError)) .and_then(|f| f.unlock().chain_err(|| SEK::FileError))
.map_err_into(SEK::IoError) .chain_err(|| SEK::IoError)
} }
} }
@ -266,7 +266,7 @@ impl Store {
use configuration::*; use configuration::*;
debug!("Validating Store configuration"); debug!("Validating Store configuration");
let _ = try!(config_is_valid(&store_config).map_err_into(SEK::ConfigurationError)); let _ = try!(config_is_valid(&store_config).chain_err(|| SEK::ConfigurationError));
debug!("Building new Store object"); debug!("Building new Store object");
if !location.exists() { if !location.exists() {
@ -275,12 +275,12 @@ impl Store {
warn!(" -> Either because configuration does not allow it"); warn!(" -> Either because configuration does not allow it");
warn!(" -> or because there is no configuration"); warn!(" -> or because there is no configuration");
return Err(SEK::CreateStoreDirDenied.into_error()) return Err(SEK::CreateStoreDirDenied.into_error())
.map_err_into(SEK::FileError) .chain_err(|| SEK::FileError)
.map_err_into(SEK::IoError); .chain_err(|| SEK::IoError);
} }
try!(backend.create_dir_all(&location) try!(backend.create_dir_all(&location)
.map_err_into(SEK::StorePathCreate) .chain_err(|| SEK::StorePathCreate)
.map_dbg_err_str("Failed")); .map_dbg_err_str("Failed"));
} else if location.is_file() { } else if location.is_file() {
debug!("Store path exists as file"); debug!("Store path exists as file");
@ -408,13 +408,13 @@ impl Store {
{ {
let mut hsmap = match self.entries.write() { let mut hsmap = match self.entries.write() {
Err(_) => return Err(SEK::LockPoisoned.into_error()).map_err_into(SEK::CreateCallError), Err(_) => return Err(SEK::LockPoisoned.into_error()).chain_err(|| SEK::CreateCallError),
Ok(s) => s, Ok(s) => s,
}; };
if hsmap.contains_key(&id) { if hsmap.contains_key(&id) {
debug!("Cannot create, internal cache already contains: '{}'", id); debug!("Cannot create, internal cache already contains: '{}'", id);
return Err(SEK::EntryAlreadyExists.into_error()).map_err_into(SEK::CreateCallError); return Err(SEK::EntryAlreadyExists.into_error()).chain_err(|| SEK::CreateCallError);
} }
hsmap.insert(id.clone(), { hsmap.insert(id.clone(), {
debug!("Creating: '{}'", id); debug!("Creating: '{}'", id);
@ -449,7 +449,7 @@ impl Store {
let entry = try!({ let entry = try!({
self.entries self.entries
.write() .write()
.map_err(|_| SE::new(SEK::LockPoisoned, None)) .map_err(|_| SE::from_kind(SEK::LockPoisoned))
.and_then(|mut es| { .and_then(|mut es| {
let new_se = try!(StoreEntry::new(id.clone(), &self.backend)); let new_se = try!(StoreEntry::new(id.clone(), &self.backend));
let se = es.entry(id.clone()).or_insert(new_se); let se = es.entry(id.clone()).or_insert(new_se);
@ -457,7 +457,7 @@ impl Store {
se.status = StoreEntryStatus::Borrowed; se.status = StoreEntryStatus::Borrowed;
entry entry
}) })
.map_err_into(SEK::RetrieveCallError) .chain_err(|| SEK::RetrieveCallError)
}); });
debug!("Constructing FileLockEntry: '{}'", id); debug!("Constructing FileLockEntry: '{}'", id);
@ -482,8 +482,8 @@ impl Store {
let exists = try!(id.exists()) || try!(self.entries let exists = try!(id.exists()) || try!(self.entries
.read() .read()
.map(|map| map.contains_key(&id)) .map(|map| map.contains_key(&id))
.map_err(|_| SE::new(SEK::LockPoisoned, None)) .map_err(|_| SE::from_kind(SEK::LockPoisoned))
.map_err_into(SEK::GetCallError) .chain_err(|| SEK::GetCallError)
); );
if !exists { if !exists {
@ -491,7 +491,7 @@ impl Store {
return Ok(None); return Ok(None);
} }
self.retrieve(id).map(Some).map_err_into(SEK::GetCallError) self.retrieve(id).map(Some).chain_err(|| SEK::GetCallError)
} }
/// Iterate over all StoreIds for one module name /// Iterate over all StoreIds for one module name
@ -512,15 +512,15 @@ impl Store {
debug!("Retrieving for module: '{}'", mod_name); debug!("Retrieving for module: '{}'", mod_name);
path.to_str() path.to_str()
.ok_or(SE::new(SEK::EncodingError, None)) .ok_or(SE::from_kind(SEK::EncodingError))
.and_then(|path| { .and_then(|path| {
let path = [ path, "/**/*" ].join(""); let path = [ path, "/**/*" ].join("");
debug!("glob()ing with '{}'", path); debug!("glob()ing with '{}'", path);
glob(&path[..]).map_err_into(SEK::GlobError) glob(&path[..]).chain_err(|| SEK::GlobError)
}) })
.map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into()) .map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into())
.map_err_into(SEK::GlobError) .chain_err(|| SEK::GlobError)
.map_err_into(SEK::RetrieveForModuleCallError) .chain_err(|| SEK::RetrieveForModuleCallError)
} }
/// Walk the store tree for the module /// Walk the store tree for the module
@ -538,7 +538,7 @@ impl Store {
/// ///
pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> { pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> {
debug!("Updating FileLockEntry at '{}'", entry.get_location()); debug!("Updating FileLockEntry at '{}'", entry.get_location());
self._update(entry, false).map_err_into(SEK::UpdateCallError) self._update(entry, false).chain_err(|| SEK::UpdateCallError)
} }
/// Internal method to write to the filesystem store. /// Internal method to write to the filesystem store.
@ -560,11 +560,11 @@ impl Store {
/// ///
fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> { fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
let mut hsmap = match self.entries.write() { let mut hsmap = match self.entries.write() {
Err(_) => return Err(SE::new(SEK::LockPoisoned, None)), Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
Ok(e) => e, Ok(e) => e,
}; };
let se = try!(hsmap.get_mut(&entry.location).ok_or(SE::new(SEK::IdNotFound, None))); let se = try!(hsmap.get_mut(&entry.location).ok_or(SE::from_kind(SEK::IdNotFound)));
assert!(se.is_borrowed(), "Tried to update a non borrowed entry."); assert!(se.is_borrowed(), "Tried to update a non borrowed entry.");
@ -597,15 +597,15 @@ impl Store {
debug!("Retrieving copy of '{}'", id); debug!("Retrieving copy of '{}'", id);
let entries = match self.entries.write() { let entries = match self.entries.write() {
Err(_) => { Err(_) => {
return Err(SE::new(SEK::LockPoisoned, None)) return Err(SE::from_kind(SEK::LockPoisoned))
.map_err_into(SEK::RetrieveCopyCallError); .chain_err(|| SEK::RetrieveCopyCallError);
}, },
Ok(e) => e, Ok(e) => e,
}; };
// if the entry is currently modified by the user, we cannot drop it // if the entry is currently modified by the user, we cannot drop it
if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) { if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) {
return Err(SE::new(SEK::IdLocked, None)).map_err_into(SEK::RetrieveCopyCallError); return Err(SE::from_kind(SEK::IdLocked)).chain_err(|| SEK::RetrieveCopyCallError);
} }
try!(StoreEntry::new(id, &self.backend)).get_entry() try!(StoreEntry::new(id, &self.backend)).get_entry()
@ -629,18 +629,18 @@ impl Store {
{ {
let mut entries = match self.entries.write() { let mut entries = match self.entries.write() {
Err(_) => return Err(SE::new(SEK::LockPoisoned, None)) Err(_) => return Err(SE::from_kind(SEK::LockPoisoned))
.map_err_into(SEK::DeleteCallError), .chain_err(|| SEK::DeleteCallError),
Ok(e) => e, Ok(e) => e,
}; };
// if the entry is currently modified by the user, we cannot drop it // if the entry is currently modified by the user, we cannot drop it
match entries.get(&id) { match entries.get(&id) {
None => { None => {
return Err(SEK::FileNotFound.into_error()).map_err_into(SEK::DeleteCallError) return Err(SEK::FileNotFound.into_error()).chain_err(|| SEK::DeleteCallError)
}, },
Some(e) => if e.is_borrowed() { Some(e) => if e.is_borrowed() {
return Err(SE::new(SEK::IdLocked, None)).map_err_into(SEK::DeleteCallError) return Err(SE::from_kind(SEK::IdLocked)).chain_err(|| SEK::DeleteCallError)
} }
} }
@ -648,8 +648,9 @@ impl Store {
entries.remove(&id); entries.remove(&id);
let pb = try!(id.clone().with_base(self.path().clone()).into_pathbuf()); let pb = try!(id.clone().with_base(self.path().clone()).into_pathbuf());
if let Err(e) = self.backend.remove_file(&pb) { if let Err(e) = self.backend.remove_file(&pb) {
return Err(SEK::FileError.into_error_with_cause(Box::new(e))) return Err(e)
.map_err_into(SEK::DeleteCallError); .chain_err(|| SEK::FileError)
.chain_err(|| SEK::DeleteCallError);
} }
} }
@ -678,11 +679,11 @@ impl Store {
self.entries self.entries
.write() .write()
.map_err(|_| SEK::LockPoisoned.into_error()) .map_err(|_| SEK::LockPoisoned.into_error())
.map_err_into(SEK::MoveCallError) .chain_err(|| SEK::MoveCallError)
); );
if hsmap.contains_key(&new_id) { if hsmap.contains_key(&new_id) {
return Err(SEK::EntryAlreadyExists.into_error()).map_err_into(SEK::MoveCallError) return Err(SEK::EntryAlreadyExists.into_error()).chain_err(|| SEK::MoveCallError)
} }
let old_id = entry.get_location().clone(); let old_id = entry.get_location().clone();
@ -698,8 +699,8 @@ impl Store {
Ok(()) Ok(())
} }
}) })
.map_err_into(SEK::FileError) .chain_err(|| SEK::FileError)
.map_err_into(SEK::MoveCallError) .chain_err(|| SEK::MoveCallError)
} }
/// Move an entry without loading /// Move an entry without loading
@ -743,26 +744,26 @@ impl Store {
{ {
let mut hsmap = match self.entries.write() { let mut hsmap = match self.entries.write() {
Err(_) => return Err(SE::new(SEK::LockPoisoned, None)), Err(_) => return Err(SE::from_kind(SEK::LockPoisoned)),
Ok(m) => m, Ok(m) => m,
}; };
if hsmap.contains_key(&new_id) { if hsmap.contains_key(&new_id) {
return Err(SEK::EntryAlreadyExists.into_error()); return Err(SE::from_kind(SEK::EntryAlreadyExists));
} }
// if we do not have an entry here, we fail in `FileAbstraction::rename()` below. // if we do not have an entry here, we fail in `FileAbstraction::rename()` below.
// if we have one, but it is borrowed, we really should not rename it, as this might // if we have one, but it is borrowed, we really should not rename it, as this might
// lead to strange errors // lead to strange errors
if hsmap.get(&old_id).map(|e| e.is_borrowed()).unwrap_or(false) { if hsmap.get(&old_id).map(|e| e.is_borrowed()).unwrap_or(false) {
return Err(SEK::EntryAlreadyBorrowed.into_error()); return Err(SE::from_kind(SEK::EntryAlreadyBorrowed));
} }
let old_id_pb = try!(old_id.clone().with_base(self.path().clone()).into_pathbuf()); let old_id_pb = try!(old_id.clone().with_base(self.path().clone()).into_pathbuf());
let new_id_pb = try!(new_id.clone().with_base(self.path().clone()).into_pathbuf()); let new_id_pb = try!(new_id.clone().with_base(self.path().clone()).into_pathbuf());
match self.backend.rename(&old_id_pb, &new_id_pb) { match self.backend.rename(&old_id_pb, &new_id_pb) {
Err(e) => return Err(SEK::EntryRenameError.into_error_with_cause(Box::new(e))), Err(e) => return Err(e).chain_err(|| SEK::EntryRenameError),
Ok(_) => { Ok(_) => {
debug!("Rename worked on filesystem"); debug!("Rename worked on filesystem");
@ -1035,7 +1036,7 @@ mod glob_store_iter {
use storeid::StoreIdIterator; use storeid::StoreIdIterator;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use error::MapErrInto; use error::ResultExt;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
@ -1088,7 +1089,7 @@ mod glob_store_iter {
fn next(&mut self) -> Option<StoreId> { fn next(&mut self) -> Option<StoreId> {
while let Some(o) = self.paths.next() { while let Some(o) = self.paths.next() {
debug!("GlobStoreIdIterator::next() => {:?}", o); debug!("GlobStoreIdIterator::next() => {:?}", o);
match o.map_err_into(SEK::StoreIdHandlingError) { match o.chain_err(|| SEK::StoreIdHandlingError) {
Ok(path) => { Ok(path) => {
if path.exists() && path.is_file() { if path.exists() && path.is_file() {
return match StoreId::from_full_path(&self.store_path, path) { return match StoreId::from_full_path(&self.store_path, path) {
@ -1121,7 +1122,7 @@ mod glob_store_iter {
/// top-level Value::Table, but not on intermediate tables. /// top-level Value::Table, but not on intermediate tables.
pub trait Header { pub trait Header {
fn verify(&self) -> Result<()>; fn verify(&self) -> Result<()>;
fn parse(s: &str) -> RResult<Value, ParserError>; fn parse(s: &str) -> Result<Value>;
fn default_header() -> Value; fn default_header() -> Value;
} }
@ -1130,15 +1131,15 @@ impl Header for Value {
fn verify(&self) -> Result<()> { fn verify(&self) -> Result<()> {
match *self { match *self {
Value::Table(ref t) => verify_header(&t), Value::Table(ref t) => verify_header(&t),
_ => Err(SE::new(SEK::HeaderTypeFailure, None)), _ => Err(SE::from_kind(SEK::HeaderTypeFailure)),
} }
} }
fn parse(s: &str) -> RResult<Value, ParserError> { fn parse(s: &str) -> Result<Value> {
use toml::de::from_str; use toml::de::from_str;
from_str(s) from_str(s)
.map_err(|_| ParserErrorKind::TOMLParserErrors.into()) .chain_err(|| SEK::TOMLParserErrors)
.and_then(verify_header_consistency) .and_then(verify_header_consistency)
.map(Value::Table) .map(Value::Table)
} }
@ -1160,21 +1161,18 @@ impl Header for Value {
} }
fn verify_header_consistency(t: Table) -> RResult<Table, ParserError> { fn verify_header_consistency(t: Table) -> Result<Table> {
verify_header(&t) verify_header(&t).chain_err(|| SEK::HeaderInconsistency).map(|_| t)
.map_err(Box::new)
.map_err(|e| ParserErrorKind::HeaderInconsistency.into_error_with_cause(e))
.map(|_| t)
} }
fn verify_header(t: &Table) -> Result<()> { fn verify_header(t: &Table) -> Result<()> {
if !has_main_section(t) { if !has_main_section(t) {
Err(SE::from(ParserErrorKind::MissingMainSection.into_error())) Err(SE::from_kind(SEK::MissingMainSection))
} else if !has_imag_version_in_main_section(t) { } else if !has_imag_version_in_main_section(t) {
Err(SE::from(ParserErrorKind::MissingVersionInfo.into_error())) Err(SE::from_kind(SEK::MissingVersionInfo))
} else if !has_only_tables(t) { } else if !has_only_tables(t) {
debug!("Could not verify that it only has tables in its base table"); debug!("Could not verify that it only has tables in its base table");
Err(SE::from(ParserErrorKind::NonTableInBaseTable.into_error())) Err(SE::from_kind(SEK::NonTableInBaseTable))
} else { } else {
Ok(()) Ok(())
} }
@ -1518,7 +1516,7 @@ mod store_tests {
for n in 1..100 { for n in 1..100 {
let s = format!("test-{}", n % 50); let s = format!("test-{}", n % 50);
store.create(PathBuf::from(s.clone())) store.create(PathBuf::from(s.clone()))
.map_err(|e| assert!(is_match!(e.err_type(), SEK::CreateCallError) && n >= 50)) .map_err(|e| assert!(is_match!(e.kind(), &SEK::CreateCallError) && n >= 50))
.ok() .ok()
.map(|entry| { .map(|entry| {
assert!(entry.verify().is_ok()); assert!(entry.verify().is_ok());

View file

@ -26,12 +26,13 @@ use std::fmt::Error as FmtError;
use std::result::Result as RResult; use std::result::Result as RResult;
use std::path::Components; use std::path::Components;
use libimagerror::into::IntoError;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use error::MapErrInto; use error::StoreError as SE;
use error::ResultExt;
use store::Result; use store::Result;
use libimagerror::into::IntoError;
/// The Index into the Store /// The Index into the Store
#[derive(Debug, Clone, Hash, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId { pub struct StoreId {
@ -61,7 +62,7 @@ impl StoreId {
where D: Deref<Target = Path> where D: Deref<Target = Path>
{ {
let p = try!( let p = try!(
full_path.strip_prefix(store_part).map_err_into(SEK::StoreIdBuildFromFullPathError) full_path.strip_prefix(store_part).chain_err(|| SEK::StoreIdBuildFromFullPathError)
); );
StoreId::new(Some(store_part.clone()), PathBuf::from(p)) StoreId::new(Some(store_part.clone()), PathBuf::from(p))
} }
@ -69,7 +70,7 @@ impl StoreId {
pub fn new_baseless(id: PathBuf) -> Result<StoreId> { pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
debug!("Trying to get a new baseless id from: {:?}", id); debug!("Trying to get a new baseless id from: {:?}", id);
if id.is_absolute() { if id.is_absolute() {
Err(SEK::StoreIdLocalPartAbsoluteError.into_error()) Err(SE::from_kind(SEK::StoreIdLocalPartAbsoluteError))
} else { } else {
Ok(StoreId { Ok(StoreId {
base: None, base: None,
@ -91,7 +92,7 @@ impl StoreId {
/// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
/// specified. /// specified.
pub fn into_pathbuf(self) -> Result<PathBuf> { pub fn into_pathbuf(self) -> Result<PathBuf> {
let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError.into_error())); let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError));
base.push(self.id); base.push(self.id);
Ok(base) Ok(base)
} }
@ -347,7 +348,7 @@ mod test {
let pb = id.unwrap().into_pathbuf(); let pb = id.unwrap().into_pathbuf();
assert!(pb.is_err()); assert!(pb.is_err());
assert_eq!(pb.unwrap_err().err_type(), SEK::StoreIdHasNoBaseError); assert!(is_match!(pb.unwrap_err().kind(), &SEK::StoreIdHasNoBaseError));
} }
#[test] #[test]

View file

@ -20,11 +20,10 @@
use regex::Regex; use regex::Regex;
use toml::Value; use toml::Value;
use libimagerror::into::IntoError;
use store::Result; use store::Result;
use store::Header; use store::Header;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use error::StoreError as SE;
#[cfg(feature = "early-panic")] #[cfg(feature = "early-panic")]
#[macro_export] #[macro_export]
@ -54,12 +53,12 @@ pub fn entry_buffer_to_header_content(buf: &str) -> Result<(Value, String)> {
} }
let matches = match RE.captures(buf) { let matches = match RE.captures(buf) {
None => return Err(SEK::MalformedEntry.into_error()), None => return Err(SE::from_kind(SEK::MalformedEntry)),
Some(s) => s, Some(s) => s,
}; };
let header = match matches.name("header") { let header = match matches.name("header") {
None => return Err(SEK::MalformedEntry.into_error()), None => return Err(SE::from_kind(SEK::MalformedEntry)),
Some(s) => s Some(s) => s
}; };