Add graceful exit support

This commit is contained in:
Félix Saparelli 2021-08-23 02:32:08 +12:00
parent f4a8a9fc6a
commit 17b09d8798
No known key found for this signature in database
GPG Key ID: B948C4BAE44FC474
3 changed files with 26 additions and 2 deletions

View File

@ -105,6 +105,9 @@ pub enum Outcome {
/// Clear the screen.
Clear,
/// Exit watchexec.
Exit,
/// When command is running, do the first, otherwise the second.
IfRunning(Box<Outcome>, Box<Outcome>),
@ -224,6 +227,9 @@ async fn apply_outcome(
) -> Result<(), RuntimeError> {
match (process.as_mut(), outcome) {
(_, Outcome::DoNothing) => {}
(_, Outcome::Exit) => {
return Err(RuntimeError::Exit);
}
(Some(p), Outcome::Stop) => {
p.kill().await?;
p.wait().await?;

View File

@ -19,6 +19,11 @@ use crate::{
#[derive(Debug, Diagnostic, Error)]
#[non_exhaustive]
pub enum CriticalError {
/// Pseudo-error used to signal a graceful exit.
#[error("this should never be printed (exit)")]
#[diagnostic(code(watchexec::runtime::exit))]
Exit,
/// A critical I/O error occurred.
#[error(transparent)]
#[diagnostic(code(watchexec::critical::io_error))]
@ -36,7 +41,7 @@ pub enum CriticalError {
/// Error received when a handler is missing on initialisation.
///
/// This is a critical bug and unlikely to be recoverable in any way.
/// This is a **bug** and should be reported.
#[error("internal: missing handler on init")]
#[diagnostic(code(watchexec::critical::internal::missing_handler))]
MissingHandler,
@ -47,6 +52,11 @@ pub enum CriticalError {
#[derive(Debug, Diagnostic, Error)]
#[non_exhaustive]
pub enum RuntimeError {
/// Pseudo-error used to signal a graceful exit.
#[error("this should never be printed (exit)")]
#[diagnostic(code(watchexec::runtime::exit))]
Exit,
/// Generic I/O error, with no additional context.
#[error(transparent)]
#[diagnostic(code(watchexec::runtime::io_error))]

View File

@ -77,7 +77,10 @@ impl Watchexec {
let error_hook = subtask!(error_hook, error_hook(er_r, eh));
try_join!(action, error_hook, fs, signal).map(drop)
try_join!(action, error_hook, fs, signal).map(drop).or_else(|e| if matches!(e, CriticalError::Exit) {
trace!("got graceful exit request via critical error, erasing the error");
Ok(())
} else { Err(e) })
});
trace!("done with setup");
@ -126,6 +129,11 @@ async fn error_hook(
mut handler: Box<dyn Handler<RuntimeError> + Send>,
) -> Result<(), CriticalError> {
while let Some(err) = errors.recv().await {
if matches!(err, RuntimeError::Exit) {
trace!("got graceful exit request via runtime error, upgrading to crit");
return Err(CriticalError::Exit);
}
error!(%err, "runtime error");
if let Err(err) = handler.handle(err) {
error!(%err, "error while handling error");