2022-06-16 18:07:27 +02:00
|
|
|
use std::time::Duration;
|
|
|
|
|
2021-10-15 14:21:52 +02:00
|
|
|
use crate::signal::process::SubSignal;
|
2021-09-18 07:20:05 +02:00
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The outcome to execute when an action is triggered.
|
|
|
|
///
|
|
|
|
/// Logic against the state of the command should be expressed using these variants, rather than
|
|
|
|
/// inside the action handler, as it ensures the state of the command is always the latest available
|
|
|
|
/// when the outcome is executed.
|
2021-09-18 07:20:05 +02:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum Outcome {
|
|
|
|
/// Stop processing this action silently.
|
|
|
|
DoNothing,
|
|
|
|
|
|
|
|
/// If the command is running, stop it.
|
2021-10-16 14:12:04 +02:00
|
|
|
///
|
|
|
|
/// This should be used with an `IfRunning`, and will warn if the command is not running.
|
2021-09-18 07:20:05 +02:00
|
|
|
Stop,
|
|
|
|
|
|
|
|
/// If the command isn't running, start it.
|
2021-10-16 14:12:04 +02:00
|
|
|
///
|
|
|
|
/// This should be used with an `IfRunning`, and will warn if the command is running.
|
2021-09-18 07:20:05 +02:00
|
|
|
Start,
|
|
|
|
|
|
|
|
/// Wait for command completion.
|
2021-10-16 14:12:04 +02:00
|
|
|
///
|
|
|
|
/// Does nothing if the command isn't running.
|
2021-09-18 07:20:05 +02:00
|
|
|
Wait,
|
|
|
|
|
2022-06-16 18:07:27 +02:00
|
|
|
/// Sleep for some duration.
|
|
|
|
Sleep(Duration),
|
|
|
|
|
2021-09-18 07:20:05 +02:00
|
|
|
/// Send this signal to the command.
|
2021-10-16 14:12:04 +02:00
|
|
|
///
|
|
|
|
/// This does not wait for the command to complete.
|
2021-10-15 14:21:52 +02:00
|
|
|
Signal(SubSignal),
|
2021-09-18 07:20:05 +02:00
|
|
|
|
|
|
|
/// Clear the (terminal) screen.
|
|
|
|
Clear,
|
|
|
|
|
|
|
|
/// Reset the (terminal) screen.
|
|
|
|
///
|
2021-10-16 16:06:08 +02:00
|
|
|
/// This invokes (in order): [`WindowsCooked`][clearscreen::ClearScreen::WindowsCooked],
|
|
|
|
/// [`WindowsVt`][clearscreen::ClearScreen::WindowsVt],
|
|
|
|
/// [`VtLeaveAlt`][clearscreen::ClearScreen::VtLeaveAlt],
|
|
|
|
/// [`VtWellDone`][clearscreen::ClearScreen::VtWellDone],
|
|
|
|
/// and [the default clear][clearscreen::ClearScreen::default()].
|
2021-09-18 07:20:05 +02:00
|
|
|
Reset,
|
|
|
|
|
|
|
|
/// Exit watchexec.
|
|
|
|
Exit,
|
|
|
|
|
|
|
|
/// When command is running, do the first, otherwise the second.
|
|
|
|
IfRunning(Box<Outcome>, Box<Outcome>),
|
|
|
|
|
|
|
|
/// Do both outcomes in order.
|
|
|
|
Both(Box<Outcome>, Box<Outcome>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Outcome {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::DoNothing
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Outcome {
|
2021-10-16 14:12:04 +02:00
|
|
|
/// Convenience function to create an outcome conditional on the state of the subprocess.
|
2023-01-06 14:53:49 +01:00
|
|
|
#[must_use]
|
|
|
|
pub fn if_running(then: Self, otherwise: Self) -> Self {
|
2021-09-18 07:20:05 +02:00
|
|
|
Self::IfRunning(Box::new(then), Box::new(otherwise))
|
|
|
|
}
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// Convenience function to create a sequence of outcomes.
|
2023-01-06 14:53:49 +01:00
|
|
|
#[must_use]
|
|
|
|
pub fn both(one: Self, two: Self) -> Self {
|
2021-09-18 07:20:05 +02:00
|
|
|
Self::Both(Box::new(one), Box::new(two))
|
|
|
|
}
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// Convenience function to wait for the subprocess to complete before executing the outcome.
|
2023-01-06 14:53:49 +01:00
|
|
|
#[must_use]
|
|
|
|
pub fn wait(and_then: Self) -> Self {
|
|
|
|
Self::Both(Box::new(Self::Wait), Box::new(and_then))
|
2021-09-18 07:20:05 +02:00
|
|
|
}
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// Resolves the outcome given the current state of the subprocess.
|
2023-01-06 14:53:49 +01:00
|
|
|
#[must_use]
|
2021-09-18 07:20:05 +02:00
|
|
|
pub fn resolve(self, is_running: bool) -> Self {
|
|
|
|
match (is_running, self) {
|
|
|
|
(true, Self::IfRunning(then, _)) => then.resolve(true),
|
|
|
|
(false, Self::IfRunning(_, otherwise)) => otherwise.resolve(false),
|
|
|
|
(ir, Self::Both(one, two)) => Self::both(one.resolve(ir), two.resolve(ir)),
|
|
|
|
(_, other) => other,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-08 10:07:58 +01:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn simple_if_running() {
|
|
|
|
assert_eq!(
|
|
|
|
Outcome::if_running(Outcome::Stop, Outcome::Start).resolve(true),
|
|
|
|
Outcome::Stop
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Outcome::if_running(Outcome::Stop, Outcome::Start).resolve(false),
|
|
|
|
Outcome::Start
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn simple_passthrough() {
|
|
|
|
assert_eq!(Outcome::Wait.resolve(true), Outcome::Wait);
|
|
|
|
assert_eq!(Outcome::Clear.resolve(false), Outcome::Clear);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nested_if_runnings() {
|
|
|
|
assert_eq!(
|
|
|
|
Outcome::both(
|
|
|
|
Outcome::if_running(Outcome::Stop, Outcome::Start),
|
|
|
|
Outcome::if_running(Outcome::Wait, Outcome::Exit)
|
|
|
|
)
|
|
|
|
.resolve(true),
|
|
|
|
Outcome::Both(Box::new(Outcome::Stop), Box::new(Outcome::Wait))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|