feat(status): add error context
This commit was merged in pull request #70.
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
pub type Result<T> = std::result::Result<T, Status>;
|
||||
|
||||
pub trait ResultExt<T> {
|
||||
fn with_context<C, F>(self, context: F) -> Result<T>
|
||||
where
|
||||
C: Into<String>,
|
||||
F: FnOnce() -> C;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Code {
|
||||
InvalidArgument,
|
||||
@@ -48,6 +55,10 @@ impl Status {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_context(self, context: impl Into<String>) -> Self {
|
||||
Self::new(self.code, context).with_source(self)
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Code {
|
||||
self.code
|
||||
}
|
||||
@@ -82,3 +93,16 @@ impl From<std::io::Error> for Status {
|
||||
Self::new(code, error.to_string()).with_source(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> ResultExt<T> for std::result::Result<T, E>
|
||||
where
|
||||
E: Into<Status>,
|
||||
{
|
||||
fn with_context<C, F>(self, context: F) -> Result<T>
|
||||
where
|
||||
C: Into<String>,
|
||||
F: FnOnce() -> C,
|
||||
{
|
||||
self.map_err(|error| error.into().with_context(context()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::error::Error;
|
||||
|
||||
use status::{Code, Status};
|
||||
use status::{Code, ResultExt, Status};
|
||||
|
||||
#[test]
|
||||
fn constructors_set_code_and_message() {
|
||||
@@ -34,6 +34,29 @@ fn with_source_preserves_source_error() {
|
||||
assert_eq!("denied", status.source().unwrap().to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_context_preserves_code_and_wraps_status() {
|
||||
let status = Status::not_found("missing input").with_context("failed to load config");
|
||||
|
||||
assert_eq!(Code::NotFound, status.code());
|
||||
assert_eq!("failed to load config", status.message());
|
||||
assert_eq!("NotFound: missing input", status.source().unwrap().to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn result_ext_adds_lazy_context() {
|
||||
let result: status::Result<()> = Err(std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
"denied",
|
||||
))
|
||||
.with_context(|| "failed to read input");
|
||||
|
||||
let status = result.unwrap_err();
|
||||
assert_eq!(Code::PermissionDenied, status.code());
|
||||
assert_eq!("failed to read input", status.message());
|
||||
assert_eq!("PermissionDenied: denied", status.source().unwrap().to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn io_error_maps_not_found() {
|
||||
let status = Status::from(std::io::Error::new(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use clap::Parser;
|
||||
use status::ResultExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use xatu::SourceFile;
|
||||
|
||||
@@ -26,7 +27,8 @@ fn is_excluded_dir(path: &Path) -> bool {
|
||||
}
|
||||
|
||||
fn collect_source_files(path: &Path) -> status::Result<Vec<SourceFile>> {
|
||||
let metadata = std::fs::symlink_metadata(path)?;
|
||||
let metadata = std::fs::symlink_metadata(path)
|
||||
.with_context(|| format!("failed to read metadata for {}", path.display()))?;
|
||||
|
||||
if metadata.file_type().is_dir() {
|
||||
if is_excluded_dir(path) {
|
||||
@@ -35,8 +37,11 @@ fn collect_source_files(path: &Path) -> status::Result<Vec<SourceFile>> {
|
||||
|
||||
let mut files = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(path)? {
|
||||
let entry = entry?;
|
||||
for entry in std::fs::read_dir(path)
|
||||
.with_context(|| format!("failed to read directory {}", path.display()))?
|
||||
{
|
||||
let entry =
|
||||
entry.with_context(|| format!("failed to read entry in {}", path.display()))?;
|
||||
files.extend(collect_source_files(&entry.path())?);
|
||||
}
|
||||
|
||||
@@ -46,7 +51,8 @@ fn collect_source_files(path: &Path) -> status::Result<Vec<SourceFile>> {
|
||||
if metadata.file_type().is_file() && is_nix_file(path) {
|
||||
return Ok(vec![SourceFile {
|
||||
path: path.to_path_buf(),
|
||||
source: std::fs::read_to_string(path)?,
|
||||
source: std::fs::read_to_string(path)
|
||||
.with_context(|| format!("failed to read source file {}", path.display()))?,
|
||||
}]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user