Merge pull request #1062 from matthiasbeyer/libimagstore/error-opt
libimagstore: Optimize errors
This commit is contained in:
commit
53c7d602eb
4 changed files with 48 additions and 88 deletions
|
@ -17,6 +17,10 @@
|
||||||
// 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 storeid::StoreId;
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
types {
|
types {
|
||||||
StoreError, StoreErrorKind, ResultExt, Result;
|
StoreError, StoreErrorKind, ResultExt, Result;
|
||||||
|
@ -25,6 +29,7 @@ error_chain! {
|
||||||
foreign_links {
|
foreign_links {
|
||||||
Io(::std::io::Error);
|
Io(::std::io::Error);
|
||||||
TomlDeserError(::toml::de::Error);
|
TomlDeserError(::toml::de::Error);
|
||||||
|
GlobPatternError(::glob::PatternError);
|
||||||
}
|
}
|
||||||
|
|
||||||
errors {
|
errors {
|
||||||
|
@ -69,14 +74,9 @@ error_chain! {
|
||||||
display("ID locked")
|
display("ID locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
IdNotFound {
|
IdNotFound(sid: StoreId) {
|
||||||
description("ID not found")
|
description("ID not found")
|
||||||
display("ID not found")
|
display("ID not found: {}", sid)
|
||||||
}
|
|
||||||
|
|
||||||
OutOfMemory {
|
|
||||||
description("Out of Memory")
|
|
||||||
display("Out of Memory")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNotFound {
|
FileNotFound {
|
||||||
|
@ -119,14 +119,14 @@ error_chain! {
|
||||||
display("Directory/Directories could not be created")
|
display("Directory/Directories could not be created")
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathExists {
|
StorePathExists(pb: PathBuf) {
|
||||||
description("Store path exists")
|
description("Store path exists")
|
||||||
display("Store path exists")
|
display("Store path exists: {:?}", pb)
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathCreate {
|
StorePathCreate(pb: PathBuf) {
|
||||||
description("Store path create")
|
description("Store path create")
|
||||||
display("Store path create")
|
display("Store path create: {:?}", pb)
|
||||||
}
|
}
|
||||||
|
|
||||||
LockError {
|
LockError {
|
||||||
|
@ -139,14 +139,14 @@ error_chain! {
|
||||||
display("The internal Store Lock has been poisoned")
|
display("The internal Store Lock has been poisoned")
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryAlreadyBorrowed {
|
EntryAlreadyBorrowed(id: StoreId) {
|
||||||
description("Entry is already borrowed")
|
description("Entry is already borrowed")
|
||||||
display("Entry is already borrowed")
|
display("Entry is already borrowed: {:?}", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryAlreadyExists {
|
EntryAlreadyExists(id: StoreId) {
|
||||||
description("Entry already exists")
|
description("Entry already exists")
|
||||||
display("Entry already exists")
|
display("Entry already exists: {:?}", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
MalformedEntry {
|
MalformedEntry {
|
||||||
|
@ -154,49 +154,19 @@ error_chain! {
|
||||||
display("Entry has invalid formatting, missing header")
|
display("Entry has invalid formatting, missing header")
|
||||||
}
|
}
|
||||||
|
|
||||||
HeaderPathSyntaxError {
|
|
||||||
description("Syntax error in accessor string")
|
|
||||||
display("Syntax error in accessor string")
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderPathTypeFailure {
|
|
||||||
description("Header has wrong type for path")
|
|
||||||
display("Header has wrong type for path")
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderKeyNotFound {
|
|
||||||
description("Header Key not found")
|
|
||||||
display("Header Key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderTypeFailure {
|
HeaderTypeFailure {
|
||||||
description("Header type is wrong")
|
description("Header type is wrong")
|
||||||
display("Header type is wrong")
|
display("Header type is wrong")
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathLacksVersion {
|
|
||||||
description("The supplied store path has no version part")
|
|
||||||
display("The supplied store path has no version part")
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobError {
|
|
||||||
description("glob() error")
|
|
||||||
display("glob() error")
|
|
||||||
}
|
|
||||||
|
|
||||||
EncodingError {
|
EncodingError {
|
||||||
description("Encoding error")
|
description("Encoding error")
|
||||||
display("Encoding error")
|
display("Encoding error")
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathError {
|
EntryRenameError(old: PathBuf, new: PathBuf) {
|
||||||
description("Store Path error")
|
|
||||||
display("Store Path error")
|
|
||||||
}
|
|
||||||
|
|
||||||
EntryRenameError {
|
|
||||||
description("Entry rename error")
|
description("Entry rename error")
|
||||||
display("Entry rename error")
|
display("Entry rename error: {:?} -> {:?}", old, new)
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreIdHandlingError {
|
StoreIdHandlingError {
|
||||||
|
@ -204,9 +174,9 @@ error_chain! {
|
||||||
display("StoreId handling error")
|
display("StoreId handling error")
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreIdLocalPartAbsoluteError {
|
StoreIdLocalPartAbsoluteError(pb: PathBuf) {
|
||||||
description("StoreId 'id' part is absolute (starts with '/') which is not allowed")
|
description("StoreId 'id' part is absolute (starts with '/') which is not allowed")
|
||||||
display("StoreId 'id' part is absolute (starts with '/') which is not allowed")
|
display("StoreId 'id' part is absolute (starts with '/') which is not allowed: {:?}", pb)
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreIdBuildFromFullPathError {
|
StoreIdBuildFromFullPathError {
|
||||||
|
@ -214,9 +184,9 @@ error_chain! {
|
||||||
display("Building StoreId from full file path failed")
|
display("Building StoreId from full file path failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreIdHasNoBaseError {
|
StoreIdHasNoBaseError(pb: PathBuf) {
|
||||||
description("StoreId has no 'base' part")
|
description("StoreId has no 'base' part")
|
||||||
display("StoreId has no 'base' part")
|
display("StoreId has no 'base' part: {:?}", pb)
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateCallError {
|
CreateCallError {
|
||||||
|
@ -271,11 +241,6 @@ error_chain! {
|
||||||
|
|
||||||
// Parser-related errors
|
// Parser-related errors
|
||||||
|
|
||||||
TOMLParserErrors {
|
|
||||||
description("Several TOML-Parser-Errors")
|
|
||||||
display("Several TOML-Parser-Errors")
|
|
||||||
}
|
|
||||||
|
|
||||||
MissingMainSection {
|
MissingMainSection {
|
||||||
description("Missing main section")
|
description("Missing main section")
|
||||||
display("Missing main section")
|
display("Missing main section")
|
||||||
|
|
|
@ -146,7 +146,7 @@ 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().chain_err(|| SEK::FileError))
|
.and_then(|f| f.lock_exclusive())
|
||||||
.chain_err(|| SEK::IoError));
|
.chain_err(|| SEK::IoError));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,15 +173,15 @@ impl StoreEntry {
|
||||||
Err(err)
|
Err(err)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(SE::from_kind(SEK::EntryAlreadyBorrowed))
|
Err(SE::from_kind(SEK::EntryAlreadyBorrowed(self.id.clone())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_entry(&mut self, entry: &Entry) -> Result<()> {
|
fn write_entry(&mut self, entry: &Entry) -> Result<()> {
|
||||||
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
|
||||||
.chain_err(|| SEK::FileError)
|
.write_file_content(entry)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -194,9 +194,8 @@ 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()).chain_err(|| SEK::IoError))
|
.and_then(|entry| open_file(entry.get_location().clone()))
|
||||||
.and_then(|f| f.unlock().chain_err(|| SEK::FileError))
|
.and_then(|f| f.unlock())
|
||||||
.chain_err(|| SEK::IoError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -244,12 +243,7 @@ impl Store {
|
||||||
/// # Return values
|
/// # Return values
|
||||||
///
|
///
|
||||||
/// - On success: Store object
|
/// - On success: Store object
|
||||||
/// - On Failure:
|
///
|
||||||
/// - ConfigurationError if config is faulty
|
|
||||||
/// - IoError(FileError(CreateStoreDirDenied())) if store location does not exist and creating
|
|
||||||
/// is denied
|
|
||||||
/// - StorePathCreate(_) if creating the store directory failed
|
|
||||||
/// - StorePathExists() if location exists but is a file
|
|
||||||
pub fn new(location: PathBuf, store_config: Option<Value>) -> Result<Store> {
|
pub fn new(location: PathBuf, store_config: Option<Value>) -> Result<Store> {
|
||||||
let backend = Box::new(FSFileAbstraction::new());
|
let backend = Box::new(FSFileAbstraction::new());
|
||||||
Store::new_with_backend(location, store_config, backend)
|
Store::new_with_backend(location, store_config, backend)
|
||||||
|
@ -270,20 +264,17 @@ impl Store {
|
||||||
debug!("Building new Store object");
|
debug!("Building new Store object");
|
||||||
if !location.exists() {
|
if !location.exists() {
|
||||||
if !config_implicit_store_create_allowed(store_config.as_ref()) {
|
if !config_implicit_store_create_allowed(store_config.as_ref()) {
|
||||||
warn!("Implicitely creating store directory is denied");
|
|
||||||
warn!(" -> Either because configuration does not allow it");
|
|
||||||
warn!(" -> or because there is no configuration");
|
|
||||||
return Err(SE::from_kind(SEK::CreateStoreDirDenied))
|
return Err(SE::from_kind(SEK::CreateStoreDirDenied))
|
||||||
.chain_err(|| SEK::FileError)
|
.chain_err(|| SEK::FileError)
|
||||||
.chain_err(|| SEK::IoError);
|
.chain_err(|| SEK::IoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(backend.create_dir_all(&location)
|
try!(backend.create_dir_all(&location)
|
||||||
.chain_err(|| SEK::StorePathCreate)
|
.chain_err(|| SEK::StorePathCreate(location.clone()))
|
||||||
.map_dbg_err_str("Failed"));
|
.map_dbg_err_str("Failed"));
|
||||||
} else if location.is_file() {
|
} else if location.is_file() {
|
||||||
debug!("Store path exists as file");
|
debug!("Store path exists as file");
|
||||||
return Err(SE::from_kind(SEK::StorePathExists));
|
return Err(SE::from_kind(SEK::StorePathExists(location)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let store = Store {
|
let store = Store {
|
||||||
|
@ -413,7 +404,8 @@ impl Store {
|
||||||
|
|
||||||
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(SE::from_kind(SEK::EntryAlreadyExists)).chain_err(|| SEK::CreateCallError);
|
return Err(SE::from_kind(SEK::EntryAlreadyExists(id.clone())))
|
||||||
|
.chain_err(|| SEK::CreateCallError);
|
||||||
}
|
}
|
||||||
hsmap.insert(id.clone(), {
|
hsmap.insert(id.clone(), {
|
||||||
debug!("Creating: '{}'", id);
|
debug!("Creating: '{}'", id);
|
||||||
|
@ -515,10 +507,9 @@ impl Store {
|
||||||
.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[..]).chain_err(|| SEK::GlobError)
|
glob(&path[..]).map_err(From::from)
|
||||||
})
|
})
|
||||||
.map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into())
|
.map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into())
|
||||||
.chain_err(|| SEK::GlobError)
|
|
||||||
.chain_err(|| SEK::RetrieveForModuleCallError)
|
.chain_err(|| SEK::RetrieveForModuleCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,7 +554,9 @@ impl Store {
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
};
|
};
|
||||||
|
|
||||||
let se = try!(hsmap.get_mut(&entry.location).ok_or(SE::from_kind(SEK::IdNotFound)));
|
let se = try!(hsmap.get_mut(&entry.location).ok_or_else(|| {
|
||||||
|
SE::from_kind(SEK::IdNotFound(entry.location.clone()))
|
||||||
|
}));
|
||||||
|
|
||||||
assert!(se.is_borrowed(), "Tried to update a non borrowed entry.");
|
assert!(se.is_borrowed(), "Tried to update a non borrowed entry.");
|
||||||
|
|
||||||
|
@ -682,7 +675,8 @@ impl Store {
|
||||||
);
|
);
|
||||||
|
|
||||||
if hsmap.contains_key(&new_id) {
|
if hsmap.contains_key(&new_id) {
|
||||||
return Err(SE::from_kind(SEK::EntryAlreadyExists)).chain_err(|| SEK::MoveCallError)
|
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone())))
|
||||||
|
.chain_err(|| SEK::MoveCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_id = entry.get_location().clone();
|
let old_id = entry.get_location().clone();
|
||||||
|
@ -748,21 +742,21 @@ impl Store {
|
||||||
};
|
};
|
||||||
|
|
||||||
if hsmap.contains_key(&new_id) {
|
if hsmap.contains_key(&new_id) {
|
||||||
return Err(SE::from_kind(SEK::EntryAlreadyExists));
|
return Err(SE::from_kind(SEK::EntryAlreadyExists(new_id.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(SE::from_kind(SEK::EntryAlreadyBorrowed));
|
return Err(SE::from_kind(SEK::EntryAlreadyBorrowed(old_id.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
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(e).chain_err(|| SEK::EntryRenameError),
|
Err(e) => return Err(e).chain_err(|| SEK::EntryRenameError(old_id_pb, new_id_pb)),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
debug!("Rename worked on filesystem");
|
debug!("Rename worked on filesystem");
|
||||||
|
|
||||||
|
@ -1146,7 +1140,7 @@ impl Header for Value {
|
||||||
use toml::de::from_str;
|
use toml::de::from_str;
|
||||||
|
|
||||||
from_str(s)
|
from_str(s)
|
||||||
.chain_err(|| SEK::TOMLParserErrors)
|
.map_err(From::from)
|
||||||
.and_then(verify_header_consistency)
|
.and_then(verify_header_consistency)
|
||||||
.map(Value::Table)
|
.map(Value::Table)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ impl StoreId {
|
||||||
pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
|
pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
|
||||||
debug!("Trying to get a new baseless id from: {:?}", id);
|
debug!("Trying to get a new baseless id from: {:?}", id);
|
||||||
if id.is_absolute() {
|
if id.is_absolute() {
|
||||||
Err(SE::from_kind(SEK::StoreIdLocalPartAbsoluteError))
|
Err(SE::from_kind(SEK::StoreIdLocalPartAbsoluteError(id)))
|
||||||
} else {
|
} else {
|
||||||
Ok(StoreId {
|
Ok(StoreId {
|
||||||
base: None,
|
base: None,
|
||||||
|
@ -89,8 +89,9 @@ 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(mut self) -> Result<PathBuf> {
|
||||||
let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError));
|
let base = self.base.take();
|
||||||
|
let mut base = try!(base.ok_or_else(|| SEK::StoreIdHasNoBaseError(self.id.clone())));
|
||||||
base.push(self.id);
|
base.push(self.id);
|
||||||
Ok(base)
|
Ok(base)
|
||||||
}
|
}
|
||||||
|
@ -346,7 +347,7 @@ mod test {
|
||||||
let pb = id.unwrap().into_pathbuf();
|
let pb = id.unwrap().into_pathbuf();
|
||||||
assert!(pb.is_err());
|
assert!(pb.is_err());
|
||||||
|
|
||||||
assert!(is_match!(pb.unwrap_err().kind(), &SEK::StoreIdHasNoBaseError));
|
assert!(is_match!(pb.unwrap_err().kind(), &SEK::StoreIdHasNoBaseError(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl CategoryRegister for Store {
|
||||||
.chain_err(|| CEK::HeaderWriteError)
|
.chain_err(|| CEK::HeaderWriteError)
|
||||||
.chain_err(|| CEK::StoreWriteError)
|
.chain_err(|| CEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
Err(store_error) => if is_match!(store_error.kind(), &SEK::EntryAlreadyExists) {
|
Err(store_error) => if is_match!(store_error.kind(), &SEK::EntryAlreadyExists(_)) {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
} else {
|
} else {
|
||||||
Err(store_error).chain_err(|| CEK::StoreWriteError)
|
Err(store_error).chain_err(|| CEK::StoreWriteError)
|
||||||
|
|
Loading…
Reference in a new issue