Start implementing a cas in separate crates.

This commit is contained in:
2021-08-01 17:06:50 +02:00
parent 468f81b86c
commit 5664beca57
19 changed files with 1241 additions and 315 deletions

View File

@@ -6,7 +6,7 @@ edition = "2018"
license = "AGPL-3.0-or-later"
[dependencies]
error-chain = "0.12.2"
thiserror = "1.0.25"
serde = { version = "1.0.106", features = ["derive"] }
toml = "0.5.6"
uuid = { version = "0.8.1", features = ["serde", "v4"] }

View File

@@ -17,50 +17,99 @@
use std::path::PathBuf;
error_chain! {
foreign_links {
Io(::std::io::Error);
}
pub type Result<T> = std::result::Result<T, Box<Error>>;
errors {
NoRepositorySpecifiedError {
description("No repository specifed")
display("No repository specifed. Use -r or set BSV_REPOSITORY environment variable.")
}
#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("failed to create repository: {message}")]
RepositoryCreationFailed {
message: String,
source: Option<Box<dyn std::error::Error>>,
},
NonEmptyDirectory(dir: PathBuf) {
description("Non-empty directory")
display("Target directory {:?} must be empty.", dir)
}
#[error("invalid object id: {message}")]
InvalidObjectId {
message: String,
source: Option<Box<dyn std::error::Error>>,
},
InvalidObjectIdSize {
description("Object id has an invalid size")
display("Object id has an invalid size.")
}
#[error("invalid size (got: {size}, expected: {expected})")]
InvalidSize {
size: usize,
expected: usize,
},
InvalidObjectIdCharacter {
description("Object id contains invalid character")
display("Object id contains invalid character.")
}
#[error("non-empty directory ({dir})")]
NonEmptyDirectory {
dir: PathBuf
},
InvalidObjectType(otype: [u8; 4]) {
description("Object has an invalid object type")
display("Object has an invalid object type {:?}.", otype)
}
#[error("invalid character(s) ({characters})")]
InvalidObjectIdCharacter {
characters: String,
},
MismatchingObjectSize(actual: u64, expected: u64) {
description("Mismatching object size")
display("Mismatching object size: expected {}, got {}.", actual, expected)
}
#[error("invalid object type ({otype:?})")]
InvalidObjectType {
otype: [u8; 4],
},
UnsupportedFileType {
description("Unsupported file type")
display("Unsupported file type.")
}
#[error("invalid object size (expected {expected}, got {size})")]
InvalidObjectSize {
size: u64,
expected: u64,
},
InvalidPath(path: PathBuf) {
description("Invalid path")
display("Invalid path: {:?}.", path)
}
#[error("unsupported file type")]
UnsupportedFileType,
#[error("invalid path ({path})")]
InvalidPath { path: PathBuf },
#[error("io error{}", format_optional_path(path))]
IoError {
source: std::io::Error,
path: Option<PathBuf>,
},
#[error("{0}")]
Other(String),
}
pub fn repository_creation_failed<M: Into<String>>(message: M) -> Box<Error> {
Box::new(Error::RepositoryCreationFailed {
message: message.into(),
source: None,
})
}
pub fn repository_creation_failed_from<M: Into<String>>(source: Box<dyn std::error::Error>, message: M) -> Box<Error> {
Box::new(Error::RepositoryCreationFailed {
message: message.into(),
source: Some(source),
})
}
pub fn invalid_object_id<M: Into<String>>(message: M) -> Box<Error> {
Box::new(Error::InvalidObjectId {
message: message.into(),
source: None,
})
}
pub fn invalid_object_id_from<M: Into<String>>(source: Box<dyn std::error::Error>, message: M) -> Box<Error> {
Box::new(Error::InvalidObjectId {
message: message.into(),
source: Some(source),
})
}
fn format_optional_path(maybe_path: &Option<PathBuf>) -> String {
match maybe_path {
Some(path) => { format!(" ({:?})", path) },
None => { String::new() }
}
}

View File

@@ -15,18 +15,18 @@
pub mod error;
pub mod config;
pub mod object_id;
pub mod object;
pub mod repository;
// pub mod config;
// pub mod object_id;
// pub mod object;
// pub mod repository;
pub const NAME: &str = env!("CARGO_PKG_NAME");
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub use error::{Error, Result, ErrorKind};
pub use config::{Config, RepositoryConfig};
pub use object_id::ObjectId;
pub use object::{ObjectType, OTYPE_BLOB, OTYPE_TREE};
pub use repository::Repository;
pub use error::{Error, Result};
// pub use config::{Config, RepositoryConfig};
// pub use object_id::ObjectId;
// pub use object::{ObjectType, OTYPE_BLOB, OTYPE_TREE};
// pub use repository::Repository;

View File

@@ -35,7 +35,7 @@ pub fn object_type_from_metadata(md: &Metadata) -> Result<ObjectType> {
Ok(*OTYPE_TREE)
}
else {
Err(ErrorKind::UnsupportedFileType.into())
Err(Error::UnsupportedFileType)
}
}
@@ -137,7 +137,12 @@ impl TreeItem {
}
pub fn from_file_path_and_id(file_path: &Path, oid: &ObjectId) -> Result<TreeItem> {
let md = file_path.symlink_metadata()?;
let md = file_path.symlink_metadata()
.map_err(|err| Error::IoError {
source: err,
path: Some(file_path.to_path_buf())
})?;
Ok(TreeItem {
otype: object_type_from_metadata(&md)?,
oid: oid.clone(),
@@ -145,7 +150,7 @@ impl TreeItem {
permissions: Permissions::from_unix_mode(md.mode()),
name: file_path.file_name()
.and_then(|n| n.to_str())
.ok_or_else(|| ErrorKind::InvalidPath(file_path.into()))?
.ok_or_else(|| Error::InvalidPath { path: file_path.into() })?
.into(),
})
}

View File

@@ -44,7 +44,7 @@ impl FromStr for ObjectId {
fn from_str(id_str: &str) -> Result<ObjectId> {
if id_str.len() % 2 != 0 {
return Err(ErrorKind::InvalidObjectIdSize.into());
return Err(Error::InvalidObjectIdSize);
}
let byte_count = id_str.len() / 2;
@@ -53,9 +53,9 @@ impl FromStr for ObjectId {
for byte_index in 0..byte_count {
let str_index = byte_index * 2;
let byte_str = id_str.get(str_index..(str_index + 2))
.ok_or(ErrorKind::InvalidObjectIdCharacter)?;
.ok_or(Error::InvalidObjectIdCharacter)?;
id.push(u8::from_str_radix(byte_str, 16)
.or(Err(ErrorKind::InvalidObjectIdCharacter))?);
.or(Err(Error::InvalidObjectIdCharacter))?);
}
Ok(ObjectId {

View File

@@ -39,14 +39,14 @@ pub struct Repository {
impl Repository {
pub fn create(path: &Path, device_name: &str) -> Result<Repository> {
if path.exists() {
bail!(ErrorKind::NonEmptyDirectory(path.into()))
return Err(Error::NonEmptyDirectory { dir: path.to_path_buf() });
}
if device_name.is_empty() {
bail!("Device name must not be empty.")
return Err(Error::RepositoryCreationFailed("Device name must not be empty.".to_string()));
}
create_dir(&path).chain_err(|| "Failed to create repository.")?;
create_dir(&path).map_err(|err| Error::IoError("Failed to create repository.")?;
let config = Rc::new(
Config {

View File

@@ -14,20 +14,20 @@
// along with cdb. If not, see <https://www.gnu.org/licenses/>.
#[macro_use]
extern crate error_chain;
// #[macro_use]
extern crate thiserror;
extern crate serde;
pub mod core;
pub mod simple_db;
// pub mod simple_db;
pub use crate::core::{
Error, Result, ErrorKind,
Config, RepositoryConfig,
ObjectId, ObjectType,
Repository,
// pub use crate::core::{
// Error, Result,
// Config, RepositoryConfig,
// ObjectId, ObjectType,
// Repository,
OTYPE_BLOB, OTYPE_TREE,
};
// OTYPE_BLOB, OTYPE_TREE,
// };