Merge pull request #1108 from matthiasbeyer/libimagentryref/refactor-errors
Refactor errors to use error-chain linking functionality
This commit is contained in:
commit
046eb5eca3
8 changed files with 51 additions and 86 deletions
|
@ -51,7 +51,7 @@ impl Hasher for MailHasher {
|
||||||
use email::Header;
|
use email::Header;
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
try!(c.read_to_string(&mut s).chain_err(|| REK::UTF8Error).chain_err(|| REK::IOError));
|
try!(c.read_to_string(&mut s));
|
||||||
|
|
||||||
MimeMessage::parse(&s)
|
MimeMessage::parse(&s)
|
||||||
.chain_err(|| REK::RefHashingError)
|
.chain_err(|| REK::RefHashingError)
|
||||||
|
|
|
@ -24,43 +24,24 @@ error_chain! {
|
||||||
|
|
||||||
links {
|
links {
|
||||||
ListError(::libimagentrylist::error::ListError, ::libimagentrylist::error::ListErrorKind);
|
ListError(::libimagentrylist::error::ListError, ::libimagentrylist::error::ListErrorKind);
|
||||||
|
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
|
||||||
|
TomlQueryError(::toml_query::error::Error, ::toml_query::error::ErrorKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreign_links {
|
foreign_links {
|
||||||
Io(::std::io::Error);
|
Io(::std::io::Error);
|
||||||
|
Utf8Error(::std::string::FromUtf8Error);
|
||||||
|
TomlDeError(::toml::de::Error);
|
||||||
|
TomlSerError(::toml::ser::Error);
|
||||||
|
WalkDirError(::walkdir::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
errors {
|
errors {
|
||||||
StoreReadError {
|
|
||||||
description("Store read error")
|
|
||||||
display("Store read error")
|
|
||||||
}
|
|
||||||
|
|
||||||
StoreWriteError {
|
|
||||||
description("Store write error")
|
|
||||||
display("Store write error")
|
|
||||||
}
|
|
||||||
|
|
||||||
IOError {
|
|
||||||
description("IO Error")
|
|
||||||
display("IO Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
UTF8Error {
|
UTF8Error {
|
||||||
description("UTF8 Error")
|
description("UTF8 Error")
|
||||||
display("UTF8 Error")
|
display("UTF8 Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreIdError {
|
|
||||||
description("Error with storeid")
|
|
||||||
display("Error with storeid")
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderTomlError {
|
|
||||||
description("Error while working with TOML Header")
|
|
||||||
display("Error while working with TOML Header")
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderTypeError {
|
HeaderTypeError {
|
||||||
description("Header type error")
|
description("Header type error")
|
||||||
display("Header type error")
|
display("Header type error")
|
||||||
|
|
|
@ -22,7 +22,6 @@ use std::collections::BTreeMap;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use error::RefErrorKind as REK;
|
use error::RefErrorKind as REK;
|
||||||
use error::ResultExt;
|
|
||||||
use error::Result;
|
use error::Result;
|
||||||
|
|
||||||
pub struct RefFlags {
|
pub struct RefFlags {
|
||||||
|
@ -41,7 +40,7 @@ impl RefFlags {
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
||||||
v.read(key)
|
v.read(key)
|
||||||
.chain_err(|| REK::HeaderTomlError)
|
.map_err(From::from)
|
||||||
.and_then(|toml| match toml {
|
.and_then(|toml| match toml {
|
||||||
Some(&Value::Boolean(b)) => Ok(b),
|
Some(&Value::Boolean(b)) => Ok(b),
|
||||||
Some(_) => Err(REK::HeaderTypeError.into()),
|
Some(_) => Err(REK::HeaderTypeError.into()),
|
||||||
|
|
|
@ -20,9 +20,6 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use error::RefErrorKind as REK;
|
|
||||||
use error::ResultExt;
|
|
||||||
|
|
||||||
use crypto::sha1::Sha1;
|
use crypto::sha1::Sha1;
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
|
|
||||||
|
@ -58,7 +55,7 @@ impl Hasher for DefaultHasher {
|
||||||
|
|
||||||
fn create_hash<R: Read>(&mut self, _: &PathBuf, c: &mut R) -> Result<String> {
|
fn create_hash<R: Read>(&mut self, _: &PathBuf, c: &mut R) -> Result<String> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
try!(c.read_to_string(&mut s).chain_err(|| REK::UTF8Error).chain_err(|| REK::IOError));
|
try!(c.read_to_string(&mut s));
|
||||||
self.hasher.input_str(&s[..]);
|
self.hasher.input_str(&s[..]);
|
||||||
Ok(self.hasher.result_str())
|
Ok(self.hasher.result_str())
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,7 @@ use crypto::digest::Digest;
|
||||||
|
|
||||||
use hasher::Hasher;
|
use hasher::Hasher;
|
||||||
use error::Result;
|
use error::Result;
|
||||||
use error::RefErrorKind as REK;
|
use error::RefError as RE;
|
||||||
use error::ResultExt;
|
|
||||||
|
|
||||||
pub struct NBytesHasher {
|
pub struct NBytesHasher {
|
||||||
hasher: Sha1,
|
hasher: Sha1,
|
||||||
|
@ -52,12 +51,13 @@ impl Hasher for NBytesHasher {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_hash<R: Read>(&mut self, _: &PathBuf, contents: &mut R) -> Result<String> {
|
fn create_hash<R: Read>(&mut self, _: &PathBuf, contents: &mut R) -> Result<String> {
|
||||||
let s = try!(contents
|
let s : String = try!(contents
|
||||||
.bytes()
|
.bytes()
|
||||||
.take(self.n)
|
.take(self.n)
|
||||||
.collect::<RResult<Vec<u8>, _>>()
|
.collect::<RResult<Vec<u8>, _>>()
|
||||||
.chain_err(|| REK::IOError)
|
.map_err(From::from)
|
||||||
.and_then(|v| String::from_utf8(v).chain_err(|| REK::UTF8Error)));
|
.and_then(|v| String::from_utf8(v).map_err(RE::from)));
|
||||||
|
|
||||||
self.hasher.input_str(&s[..]);
|
self.hasher.input_str(&s[..]);
|
||||||
Ok(self.hasher.result_str())
|
Ok(self.hasher.result_str())
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,13 +121,14 @@ impl Ref for Entry {
|
||||||
self.get_location()
|
self.get_location()
|
||||||
.clone()
|
.clone()
|
||||||
.into_pathbuf()
|
.into_pathbuf()
|
||||||
.chain_err(|| REK::StoreIdError)
|
.map_err(From::from)
|
||||||
.and_then(|pb| {
|
.and_then(|pb| {
|
||||||
pb.file_name()
|
pb.file_name()
|
||||||
.and_then(|osstr| osstr.to_str())
|
.and_then(|osstr| osstr.to_str())
|
||||||
.and_then(|s| s.split("~").next())
|
.and_then(|s| s.split("~").next())
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.ok_or(RE::from_kind(REK::StoreIdError))
|
.ok_or(String::from("String splitting error"))
|
||||||
|
.map_err(From::from)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,18 +140,16 @@ impl Ref for Entry {
|
||||||
/// Get the hahs of the link target which is stored in the ref object, which is hashed with a
|
/// Get the hahs of the link target which is stored in the ref object, which is hashed with a
|
||||||
/// custom Hasher instance.
|
/// custom Hasher instance.
|
||||||
fn get_stored_hash_with_hasher<H: Hasher>(&self, h: &H) -> Result<String> {
|
fn get_stored_hash_with_hasher<H: Hasher>(&self, h: &H) -> Result<String> {
|
||||||
match self.get_header().read(&format!("ref.content_hash.{}", h.hash_name())[..]) {
|
match self.get_header().read(&format!("ref.content_hash.{}", h.hash_name())[..])? {
|
||||||
// content hash stored...
|
// content hash stored...
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
|
Some(&Value::String(ref s)) => Ok(s.clone()),
|
||||||
|
|
||||||
// content hash header field has wrong type
|
// content hash header field has wrong type
|
||||||
Ok(Some(_)) => Err(RE::from_kind(REK::HeaderTypeError)),
|
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)),
|
||||||
|
|
||||||
// content hash not stored
|
// content hash not stored
|
||||||
Ok(None) => Err(RE::from_kind(REK::HeaderFieldMissingError)),
|
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
|
||||||
|
|
||||||
// Error
|
|
||||||
Err(e) => Err(e).chain_err(|| REK::StoreReadError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,11 +162,7 @@ impl Ref for Entry {
|
||||||
/// custom hasher
|
/// custom hasher
|
||||||
fn get_current_hash_with_hasher<H: Hasher>(&self, mut h: H) -> Result<String> {
|
fn get_current_hash_with_hasher<H: Hasher>(&self, mut h: H) -> Result<String> {
|
||||||
self.fs_file()
|
self.fs_file()
|
||||||
.and_then(|pb| {
|
.and_then(|pb| File::open(pb.clone()).map(|f| (pb, f)).map_err(From::from))
|
||||||
File::open(pb.clone())
|
|
||||||
.map(|f| (pb, f))
|
|
||||||
.chain_err(|| REK::IOError)
|
|
||||||
})
|
|
||||||
.and_then(|(path, mut file)| h.create_hash(&path, &mut file))
|
.and_then(|(path, mut file)| h.create_hash(&path, &mut file))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,13 +239,11 @@ impl Ref for Entry {
|
||||||
try!(self
|
try!(self
|
||||||
.get_header_mut()
|
.get_header_mut()
|
||||||
.set("ref.permissions.ro", Value::Boolean(current_perm.readonly()))
|
.set("ref.permissions.ro", Value::Boolean(current_perm.readonly()))
|
||||||
.chain_err(|| REK::StoreWriteError)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
try!(self
|
try!(self
|
||||||
.get_header_mut()
|
.get_header_mut()
|
||||||
.set(&format!("ref.content_hash.{}", h.hash_name())[..], Value::String(current_hash))
|
.set(&format!("ref.content_hash.{}", h.hash_name())[..], Value::String(current_hash))
|
||||||
.chain_err(|| REK::StoreWriteError)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -258,11 +251,10 @@ impl Ref for Entry {
|
||||||
|
|
||||||
/// Get the path of the file which is reffered to by this Ref
|
/// Get the path of the file which is reffered to by this Ref
|
||||||
fn fs_file(&self) -> Result<PathBuf> {
|
fn fs_file(&self) -> Result<PathBuf> {
|
||||||
match self.get_header().read("ref.path") {
|
match self.get_header().read("ref.path")? {
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(PathBuf::from(s)),
|
Some(&Value::String(ref s)) => Ok(PathBuf::from(s)),
|
||||||
Ok(Some(_)) => Err(RE::from_kind(REK::HeaderTypeError)),
|
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)),
|
||||||
Ok(None) => Err(RE::from_kind(REK::HeaderFieldMissingError)),
|
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
|
||||||
Err(e) => Err(e).chain_err(|| REK::StoreReadError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,14 +292,18 @@ impl Ref for Entry {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
entry
|
entry
|
||||||
.chain_err(|| REK::IOError)
|
.map_err(From::from)
|
||||||
.and_then(|entry| {
|
.and_then(|entry| {
|
||||||
let pb = PathBuf::from(entry.path());
|
let pb = PathBuf::from(entry.path());
|
||||||
File::open(entry.path())
|
File::open(entry.path())
|
||||||
.chain_err(|| REK::IOError)
|
|
||||||
.map(|f| (pb, f))
|
.map(|f| (pb, f))
|
||||||
|
.map_err(From::from)
|
||||||
|
})
|
||||||
|
.and_then(|(p, mut f)| {
|
||||||
|
h.create_hash(&p, &mut f)
|
||||||
|
.map(|h| (p, h))
|
||||||
|
.map_err(From::from)
|
||||||
})
|
})
|
||||||
.and_then(|(p, mut f)| h.create_hash(&p, &mut f).map(|h| (p, h)))
|
|
||||||
.map(|(path, hash)| {
|
.map(|(path, hash)| {
|
||||||
if hash == stored_hash {
|
if hash == stored_hash {
|
||||||
Some(path)
|
Some(path)
|
||||||
|
@ -315,9 +311,8 @@ impl Ref for Entry {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.chain_err(|| REK::IOError)
|
|
||||||
})
|
})
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(Result::ok)
|
||||||
.filter_map(|e| e)
|
.filter_map(|e| e)
|
||||||
.next()
|
.next()
|
||||||
})
|
})
|
||||||
|
|
|
@ -72,9 +72,7 @@ impl RefStore for Store {
|
||||||
.and_then(|c| hash_path(&c))
|
.and_then(|c| hash_path(&c))
|
||||||
.chain_err(|| REK::PathHashingError)
|
.chain_err(|| REK::PathHashingError)
|
||||||
.and_then(|hash| {
|
.and_then(|hash| {
|
||||||
self.retrieve_for_module("ref")
|
self.retrieve_for_module("ref").map(|iter| (hash, iter)).map_err(From::from)
|
||||||
.map(|iter| (hash, iter))
|
|
||||||
.chain_err(|| REK::StoreReadError)
|
|
||||||
})
|
})
|
||||||
.and_then(|(hash, possible_refs)| {
|
.and_then(|(hash, possible_refs)| {
|
||||||
// This is kind of a manual Iterator::filter() call what we do here, but with the
|
// This is kind of a manual Iterator::filter() call what we do here, but with the
|
||||||
|
@ -91,15 +89,17 @@ impl RefStore for Store {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.get(r) {
|
match self.get(r.clone())? {
|
||||||
Ok(Some(fle)) => {
|
Some(fle) => {
|
||||||
if read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
|
if read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
|
||||||
return Ok(true)
|
return Ok(true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Ok(None) => return Err(RE::from_kind(REK::StoreReadError)),
|
None => {
|
||||||
Err(e) => return Err(e).chain_err(|| REK::StoreReadError)
|
let e = format!("Failed to get from store: {}", r);
|
||||||
|
return Err(e).map_err(From::from)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,10 +109,9 @@ impl RefStore for Store {
|
||||||
|
|
||||||
/// Try to get `si` as Ref object from the store
|
/// Try to get `si` as Ref object from the store
|
||||||
fn get<'a>(&'a self, si: StoreId) -> Result<FileLockEntry<'a>> {
|
fn get<'a>(&'a self, si: StoreId) -> Result<FileLockEntry<'a>> {
|
||||||
match self.get(si) {
|
match self.get(si)? {
|
||||||
Err(e) => return Err(e).chain_err(|| REK::StoreReadError),
|
None => return Err(RE::from_kind(REK::RefNotInStore)),
|
||||||
Ok(None) => return Err(RE::from_kind(REK::RefNotInStore)),
|
Some(fle) => Ok(fle),
|
||||||
Ok(Some(fle)) => Ok(fle),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ impl RefStore for Store {
|
||||||
ModuleEntryPath::new(hash)
|
ModuleEntryPath::new(hash)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| self.get(id))
|
.and_then(|id| self.get(id))
|
||||||
.chain_err(|| REK::StoreReadError)
|
.map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a ref by hash
|
/// Delete a ref by hash
|
||||||
|
@ -133,7 +132,7 @@ impl RefStore for Store {
|
||||||
ModuleEntryPath::new(hash)
|
ModuleEntryPath::new(hash)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.and_then(|id| self.delete(id))
|
.and_then(|id| self.delete(id))
|
||||||
.chain_err(|| REK::StoreWriteError)
|
.map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a Ref object which refers to `pb`
|
/// Create a Ref object which refers to `pb`
|
||||||
|
@ -218,11 +217,7 @@ impl RefStore for Store {
|
||||||
// and then we create the FileLockEntry in the Store
|
// and then we create the FileLockEntry in the Store
|
||||||
// and return (filelockentry, content hash, permissions, canonicalized path)
|
// and return (filelockentry, content hash, permissions, canonicalized path)
|
||||||
.and_then(|(opt_conhash, opt_perm, can, path_hash)| {
|
.and_then(|(opt_conhash, opt_perm, can, path_hash)| {
|
||||||
let fle = try!(self
|
let fle = try!(self.create(ModuleEntryPath::new(path_hash)));
|
||||||
.create(ModuleEntryPath::new(path_hash))
|
|
||||||
.chain_err(|| REK::StoreWriteError)
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok((fle, opt_conhash, opt_perm, can))
|
Ok((fle, opt_conhash, opt_perm, can))
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,7 +22,6 @@ use std::path::PathBuf;
|
||||||
use error::RefErrorKind as REK;
|
use error::RefErrorKind as REK;
|
||||||
use error::RefError as RE;
|
use error::RefError as RE;
|
||||||
use error::Result;
|
use error::Result;
|
||||||
use error::ResultExt;
|
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
|
|
||||||
|
@ -47,11 +46,10 @@ pub fn hash_path(pb: &PathBuf) -> Result<String> {
|
||||||
|
|
||||||
/// Read the reference from a file
|
/// Read the reference from a file
|
||||||
pub fn read_reference(refentry: &Entry) -> Result<PathBuf> {
|
pub fn read_reference(refentry: &Entry) -> Result<PathBuf> {
|
||||||
match refentry.get_header().read("ref.path") {
|
match refentry.get_header().read("ref.path")? {
|
||||||
Ok(Some(&Value::String(ref s))) => Ok(PathBuf::from(s)),
|
Some(&Value::String(ref s)) => Ok(PathBuf::from(s)),
|
||||||
Ok(Some(_)) => Err(RE::from_kind(REK::HeaderTypeError)),
|
Some(_) => Err(RE::from_kind(REK::HeaderTypeError)),
|
||||||
Ok(None) => Err(RE::from_kind(REK::HeaderFieldMissingError)),
|
None => Err(RE::from_kind(REK::HeaderFieldMissingError)),
|
||||||
Err(e) => Err(e).chain_err(|| REK::StoreReadError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue