Split fs watcher errors into their own enum

This commit is contained in:
Félix Saparelli 2022-02-12 19:37:24 +13:00
parent 56380154d3
commit 3b64a41d80
No known key found for this signature in database
GPG Key ID: B948C4BAE44FC474
3 changed files with 72 additions and 63 deletions

View File

@ -37,65 +37,16 @@ pub enum RuntimeError {
err: std::io::Error,
},
/// Error received when creating a filesystem watcher fails.
#[error("{kind:?} watcher failed to instantiate: {err}")]
#[diagnostic(
code(watchexec::runtime::fs_watcher_error),
help("perhaps retry with the poll watcher")
)]
FsWatcherCreate {
/// Events from the filesystem watcher event source.
#[error("{kind:?} fs watcher error")]
#[diagnostic(code(watchexec::runtime::fs_watcher))]
FsWatcher {
/// The kind of watcher that failed to instantiate.
kind: Watcher,
/// The underlying error.
#[source]
err: notify::Error,
/// A hint to the user about resolving the error.
#[source_code]
help: String,
},
/// Error received when reading a filesystem event fails.
#[error("{kind:?} watcher received an event that we could not read: {err}")]
#[diagnostic(code(watchexec::runtime::fs_watcher_event))]
FsWatcherEvent {
/// The kind of watcher that failed to read an event.
kind: Watcher,
/// The underlying error.
#[source]
err: notify::Error,
},
/// Error received when adding to the pathset for the filesystem watcher fails.
#[error("while adding {path:?} to the {kind:?} watcher: {err}")]
#[diagnostic(code(watchexec::runtime::fs_watcher_path_add))]
FsWatcherPathAdd {
/// The path that was attempted to be added.
path: PathBuf,
/// The kind of watcher that failed to add a path.
kind: Watcher,
/// The underlying error.
#[source]
err: notify::Error,
},
/// Error received when removing from the pathset for the filesystem watcher fails.
#[error("while removing {path:?} from the {kind:?} watcher: {err}")]
#[diagnostic(code(watchexec::runtime::fs_watcher_path_remove))]
FsWatcherPathRemove {
/// The path that was attempted to be removed.
path: PathBuf,
/// The kind of watcher that failed to remove a path.
kind: Watcher,
/// The underlying error.
#[source]
err: notify::Error,
err: super::FsWatcherError,
},
/// Opaque internal error from a command supervisor.

View File

@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, path::PathBuf};
use ignore::gitignore::Gitignore;
use miette::Diagnostic;
@ -126,3 +126,54 @@ impl From<TaggedFiltererError> for RuntimeError {
}
}
}
/// Errors emitted by the filesystem watcher.
#[derive(Debug, Diagnostic, Error)]
#[non_exhaustive]
#[diagnostic(url(docsrs))]
pub enum FsWatcherError {
/// Error received when creating a filesystem watcher fails.
#[error("failed to instantiate")]
#[diagnostic(
code(watchexec::fs_watcher::create),
help("perhaps retry with the poll watcher")
)]
Create {
/// The underlying error.
#[source]
err: notify::Error,
/// A hint to the user about resolving the error.
#[source_code]
help: String,
},
/// Error received when reading a filesystem event fails.
#[error("received an event that we could not read")]
#[diagnostic(code(watchexec::fs_watcher::event))]
Event(#[source] notify::Error),
/// Error received when adding to the pathset for the filesystem watcher fails.
#[error("while adding {path:?}")]
#[diagnostic(code(watchexec::fs_watcher::path_add))]
PathAdd {
/// The path that was attempted to be added.
path: PathBuf,
/// The underlying error.
#[source]
err: notify::Error,
},
/// Error received when removing from the pathset for the filesystem watcher fails.
#[error("while removing {path:?}")]
#[diagnostic(code(watchexec::fs_watcher::path_remove))]
PathRemove {
/// The path that was attempted to be removed.
path: PathBuf,
/// The underlying error.
#[source]
err: notify::Error,
},
}

View File

@ -14,7 +14,7 @@ use tokio::sync::{mpsc, watch};
use tracing::{debug, error, trace, warn};
use crate::{
error::{CriticalError, RuntimeError},
error::{CriticalError, FsWatcherError, RuntimeError},
event::{Event, Source, Tag},
};
@ -51,8 +51,9 @@ impl Watcher {
Self::Poll(delay) => notify::PollWatcher::with_delay(Arc::new(Mutex::new(f)), delay)
.map(|w| Box::new(w) as _),
}
.map_err(|err| RuntimeError::FsWatcherCreate {
.map_err(|err| RuntimeError::FsWatcher {
kind: self,
err: FsWatcherError::Create {
help: if cfg!(target_os = "linux") && (matches!(err.kind, notify::ErrorKind::MaxFilesWatch) || matches!(err.kind, notify::ErrorKind::Io(ref ioerr) if ioerr.raw_os_error() == Some(28))) {
"you will want to increase your inotify.max_user_watches, see inotify(7) and https://watchexec.github.io/docs/inotify-limits.html"
} else if cfg!(target_os = "linux") && matches!(err.kind, notify::ErrorKind::Io(ref ioerr) if ioerr.raw_os_error() == Some(24)) {
@ -61,7 +62,7 @@ impl Watcher {
"you may want to try again with the polling watcher"
}.into(),
err,
})
}})
}
}
@ -271,10 +272,13 @@ fn notify_multi_path_errors(
.unwrap_or_else(|| notify::Error::generic(&generic))
.add_path(path.clone());
errs.push(if rm {
RuntimeError::FsWatcherPathRemove { path, kind, err: e }
} else {
RuntimeError::FsWatcherPathAdd { path, kind, err: e }
errs.push(RuntimeError::FsWatcher {
kind,
err: if rm {
FsWatcherError::PathRemove { path, err: e }
} else {
FsWatcherError::PathAdd { path, err: e }
},
});
}
@ -286,7 +290,10 @@ fn process_event(
kind: Watcher,
n_events: mpsc::Sender<Event>,
) -> Result<(), RuntimeError> {
let nev = nev.map_err(|err| RuntimeError::FsWatcherEvent { kind, err })?;
let nev = nev.map_err(|err| RuntimeError::FsWatcher {
kind,
err: FsWatcherError::Event(err),
})?;
let mut tags = Vec::with_capacity(4);
tags.push(Tag::Source(Source::Filesystem));