Add context to io errors

This commit is contained in:
Félix Saparelli 2022-01-16 19:46:52 +13:00
parent 93a961abf6
commit bc0fe6be70
No known key found for this signature in database
GPG Key ID: B948C4BAE44FC474
8 changed files with 29 additions and 61 deletions

View File

@ -10,9 +10,3 @@ pub use specialised::*;
mod critical;
mod runtime;
mod specialised;
/// Helper trait to construct specific IO errors from generic ones.
pub trait SpecificIoError<Output> {
/// Add some context to the error or result.
fn about(self, context: &'static str) -> Output;
}

View File

@ -4,7 +4,7 @@ use tokio::{sync::mpsc, task::JoinError};
use crate::event::Event;
use super::{RuntimeError, SpecificIoError};
use super::RuntimeError;
/// Errors which are not recoverable and stop watchexec execution.
#[derive(Debug, Diagnostic, Error)]
@ -63,18 +63,3 @@ pub enum CriticalError {
#[diagnostic(code(watchexec::critical::internal::missing_handler))]
MissingHandler,
}
impl<T> SpecificIoError<Result<T, CriticalError>> for Result<T, std::io::Error> {
fn about(self, context: &'static str) -> Result<T, CriticalError> {
self.map_err(|err| err.about(context))
}
}
impl SpecificIoError<CriticalError> for std::io::Error {
fn about(self, context: &'static str) -> CriticalError {
CriticalError::IoError {
about: context,
err: self,
}
}
}

View File

@ -6,8 +6,6 @@ use tokio::sync::mpsc;
use crate::{event::Event, fs::Watcher, signal::process::SubSignal};
use super::SpecificIoError;
/// Errors which _may_ be recoverable, transient, or only affect a part of the operation, and should
/// be reported to the user and/or acted upon programatically, but will not outright stop watchexec.
#[derive(Debug, Diagnostic, Error)]
@ -227,18 +225,3 @@ pub enum RuntimeError {
#[diagnostic(code(watchexec::runtime::set))]
Set(#[related] Vec<RuntimeError>),
}
impl<T> SpecificIoError<Result<T, RuntimeError>> for Result<T, std::io::Error> {
fn about(self, context: &'static str) -> Result<T, RuntimeError> {
self.map_err(|err| err.about(context))
}
}
impl SpecificIoError<RuntimeError> for std::io::Error {
fn about(self, context: &'static str) -> RuntimeError {
RuntimeError::IoError {
about: context,
err: self,
}
}
}

View File

@ -13,8 +13,6 @@ use crate::{
ignore::IgnoreFilterer,
};
use super::SpecificIoError;
/// Errors occurring from reconfigs.
#[derive(Debug, Diagnostic, Error)]
#[non_exhaustive]
@ -160,18 +158,3 @@ impl From<TaggedFiltererError> for RuntimeError {
}
}
}
impl<T> SpecificIoError<Result<T, TaggedFiltererError>> for Result<T, std::io::Error> {
fn about(self, context: &'static str) -> Result<T, TaggedFiltererError> {
self.map_err(|err| err.about(context))
}
}
impl SpecificIoError<TaggedFiltererError> for std::io::Error {
fn about(self, context: &'static str) -> TaggedFiltererError {
TaggedFiltererError::IoError {
about: context,
err: self,
}
}
}

View File

@ -328,13 +328,19 @@ impl TaggedFilterer {
origin: impl Into<PathBuf>,
workdir: impl Into<PathBuf>,
) -> Result<Arc<Self>, TaggedFiltererError> {
let origin = canonicalize(origin.into())?;
let origin = canonicalize(origin.into()).map_err(|err| TaggedFiltererError::IoError {
about: "canonicalise origin on new tagged filterer",
err,
})?;
Ok(Arc::new(Self {
filters: swaplock::SwapLock::new(HashMap::new()),
ignore_filterer: swaplock::SwapLock::new(IgnoreFilterer::empty(&origin)),
glob_compiled: swaplock::SwapLock::new(None),
not_glob_compiled: swaplock::SwapLock::new(None),
workdir: canonicalize(workdir.into())?,
workdir: canonicalize(workdir.into()).map_err(|err| TaggedFiltererError::IoError {
about: "canonicalise workdir on new tagged filterer",
err,
})?,
origin,
}))
}
@ -662,7 +668,13 @@ impl Filter {
/// Returns the filter with its `in_path` canonicalised.
pub fn canonicalised(mut self) -> Result<Self, TaggedFiltererError> {
if let Some(ctx) = self.in_path {
self.in_path = Some(canonicalize(&ctx)?);
self.in_path =
Some(
canonicalize(&ctx).map_err(|err| TaggedFiltererError::IoError {
about: "canonicalise Filter in_path",
err,
})?,
);
trace!(canon=?ctx, "canonicalised in_path");
}

View File

@ -74,7 +74,13 @@ impl FilterFile {
///
/// This method reads the entire file into memory.
pub async fn load(&self) -> Result<Vec<Filter>, TaggedFiltererError> {
let content = read_to_string(&self.0.path).await?;
let content =
read_to_string(&self.0.path)
.await
.map_err(|err| TaggedFiltererError::IoError {
about: "filter file load",
err,
})?;
let lines = content.lines();
let mut filters = Vec::with_capacity(lines.size_hint().0);

View File

@ -286,7 +286,10 @@ fn process_event(
// possibly pull file_type from whatever notify (or the native driver) returns?
tags.push(Tag::Path {
file_type: metadata(&path).ok().map(|m| m.file_type().into()),
path: dunce::canonicalize(path)?,
path: dunce::canonicalize(path).map_err(|err| RuntimeError::IoError {
about: "canonicalise path in event",
err,
})?,
});
}

View File

@ -281,6 +281,8 @@ pub async fn from_environment() -> (Vec<IgnoreFile>, Vec<Error>) {
(files, errors)
}
// TODO: add context to these errors
#[inline]
pub(crate) async fn discover_file(
files: &mut Vec<IgnoreFile>,