2021-09-18 07:20:05 +02:00
|
|
|
use std::{
|
|
|
|
fmt,
|
|
|
|
sync::{Arc, Weak},
|
2021-09-22 13:39:41 +02:00
|
|
|
time::Duration,
|
2021-09-18 07:20:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
use once_cell::sync::OnceCell;
|
|
|
|
use tokio::{
|
2022-06-16 17:36:08 +02:00
|
|
|
process::Command as TokioCommand,
|
2021-09-18 07:20:05 +02:00
|
|
|
sync::{Mutex, OwnedMutexGuard},
|
|
|
|
};
|
|
|
|
|
2022-06-16 17:36:08 +02:00
|
|
|
use crate::{command::Command, event::Event, filter::Filterer, handler::HandlerLock};
|
2021-09-18 07:20:05 +02:00
|
|
|
|
|
|
|
use super::Outcome;
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The configuration of the [action][crate::action] worker.
|
2021-10-16 14:22:55 +02:00
|
|
|
///
|
|
|
|
/// This is marked non-exhaustive so new configuration can be added without breaking.
|
2021-09-18 07:20:05 +02:00
|
|
|
#[derive(Clone)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct WorkingData {
|
2021-10-16 14:12:04 +02:00
|
|
|
/// How long to wait for events to build up before executing an action.
|
|
|
|
///
|
|
|
|
/// This is sometimes called "debouncing." We debounce on the trailing edge: an action is
|
|
|
|
/// triggered only after that amount of time has passed since the first event in the cycle. The
|
|
|
|
/// action is called with all the collected events in the cycle.
|
2021-09-18 07:20:05 +02:00
|
|
|
pub throttle: Duration,
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The main handler to define: what to do when an action is triggered.
|
|
|
|
///
|
|
|
|
/// This handler is called with the [`Action`] environment, which has a certain way of returning
|
|
|
|
/// the desired outcome, check out the [`Action::outcome()`] method. The handler checks for the
|
|
|
|
/// outcome as soon as the handler returns, which means that if the handler returns before the
|
|
|
|
/// outcome is set, you'll get unexpected results. For this reason, it's a bad idea to use ex. a
|
|
|
|
/// channel as the handler.
|
|
|
|
///
|
|
|
|
/// If this handler is not provided, it defaults to a no-op, which does absolutely nothing, not
|
|
|
|
/// even quit. Hence, you really need to provide a handler.
|
|
|
|
///
|
|
|
|
/// It is possible to change the handler or any other configuration inside the previous handler.
|
|
|
|
/// It's useful to know that the handlers are updated from this working data before any of them
|
|
|
|
/// run in any given cycle, so changing the pre-spawn and post-spawn handlers from this handler
|
|
|
|
/// will not affect the running action.
|
2022-01-28 13:57:28 +01:00
|
|
|
pub action_handler: HandlerLock<Action>,
|
2021-10-16 14:12:04 +02:00
|
|
|
|
|
|
|
/// A handler triggered before a command is spawned.
|
|
|
|
///
|
|
|
|
/// This handler is called with the [`PreSpawn`] environment, which provides mutable access to
|
2022-06-16 17:36:08 +02:00
|
|
|
/// the [`Command`](TokioCommand) which is about to be run. See the notes on the
|
|
|
|
/// [`PreSpawn::command()`] method for important information on what you can do with it.
|
2021-10-16 14:12:04 +02:00
|
|
|
///
|
|
|
|
/// Returning an error from the handler will stop the action from processing further, and issue
|
|
|
|
/// a [`RuntimeError`][crate::error::RuntimeError] to the error channel.
|
2022-01-28 13:57:28 +01:00
|
|
|
pub pre_spawn_handler: HandlerLock<PreSpawn>,
|
2021-10-16 14:12:04 +02:00
|
|
|
|
|
|
|
/// A handler triggered immediately after a command is spawned.
|
|
|
|
///
|
|
|
|
/// This handler is called with the [`PostSpawn`] environment, which provides details on the
|
|
|
|
/// spawned command, including its PID.
|
|
|
|
///
|
|
|
|
/// Returning an error from the handler will drop the [`Child`][tokio::process::Child], which
|
|
|
|
/// will terminate the command without triggering any of the normal Watchexec behaviour, and
|
|
|
|
/// issue a [`RuntimeError`][crate::error::RuntimeError] to the error channel.
|
2022-01-28 13:57:28 +01:00
|
|
|
pub post_spawn_handler: HandlerLock<PostSpawn>,
|
2021-09-18 07:20:05 +02:00
|
|
|
|
2022-06-16 17:36:08 +02:00
|
|
|
/// Commands to execute.
|
2021-10-16 14:12:04 +02:00
|
|
|
///
|
2022-06-16 17:36:08 +02:00
|
|
|
/// These will be run in order, and an error will stop early.
|
|
|
|
pub commands: Vec<Command>,
|
2021-10-16 14:12:04 +02:00
|
|
|
|
|
|
|
/// Whether to use process groups (on Unix) or job control (on Windows) to run the command.
|
|
|
|
///
|
|
|
|
/// This makes use of [command_group] under the hood.
|
|
|
|
///
|
|
|
|
/// If you want to known whether a spawned command was run in a process group, you should use
|
|
|
|
/// the value in [`PostSpawn`] instead of reading this one, as it may have changed in the
|
|
|
|
/// meantime.
|
2021-09-18 07:20:05 +02:00
|
|
|
pub grouped: bool,
|
2021-10-16 14:12:04 +02:00
|
|
|
|
|
|
|
/// The filterer implementation to use when filtering events.
|
|
|
|
///
|
|
|
|
/// The default is a no-op, which will always pass every event.
|
2021-09-22 13:39:41 +02:00
|
|
|
pub filterer: Arc<dyn Filterer>,
|
2021-09-18 07:20:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for WorkingData {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("WorkingData")
|
|
|
|
.field("throttle", &self.throttle)
|
2022-06-16 17:36:08 +02:00
|
|
|
.field("commands", &self.commands)
|
2021-09-18 07:20:05 +02:00
|
|
|
.field("grouped", &self.grouped)
|
2021-09-29 17:03:46 +02:00
|
|
|
.field("filterer", &self.filterer)
|
2021-09-18 07:20:05 +02:00
|
|
|
.finish_non_exhaustive()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for WorkingData {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
throttle: Duration::from_millis(50),
|
2022-01-28 13:57:28 +01:00
|
|
|
action_handler: Default::default(),
|
|
|
|
pre_spawn_handler: Default::default(),
|
|
|
|
post_spawn_handler: Default::default(),
|
2022-06-16 17:36:08 +02:00
|
|
|
commands: Vec::new(),
|
2021-09-18 07:20:05 +02:00
|
|
|
grouped: true,
|
2021-09-22 13:39:41 +02:00
|
|
|
filterer: Arc::new(()),
|
2021-09-18 07:20:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The environment given to the action handler.
|
|
|
|
///
|
|
|
|
/// This deliberately does not implement Clone to make it hard to move it out of the handler, which
|
|
|
|
/// you should not do.
|
|
|
|
///
|
|
|
|
/// The [`Action::outcome()`] method is the only way to set the outcome of the action, and it _must_
|
|
|
|
/// be called before the handler returns.
|
2022-01-28 14:17:23 +01:00
|
|
|
#[derive(Debug)]
|
2021-09-18 07:20:05 +02:00
|
|
|
pub struct Action {
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The collected events which triggered the action.
|
2022-01-28 14:17:23 +01:00
|
|
|
pub events: Arc<[Event]>,
|
2021-09-18 07:20:05 +02:00
|
|
|
pub(super) outcome: Arc<OnceCell<Outcome>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Action {
|
2022-01-28 14:17:23 +01:00
|
|
|
pub(super) fn new(events: Arc<[Event]>) -> Self {
|
2021-09-18 07:20:05 +02:00
|
|
|
Self {
|
|
|
|
events,
|
2022-01-28 14:17:23 +01:00
|
|
|
outcome: Default::default(),
|
2021-09-18 07:20:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the action's outcome.
|
|
|
|
///
|
|
|
|
/// This takes `self` and `Action` is not `Clone`, so it's only possible to call it once.
|
|
|
|
/// Regardless, if you _do_ manage to call it twice, it will do nothing beyond the first call.
|
|
|
|
///
|
|
|
|
/// See the [`Action`] documentation about handlers to learn why it's a bad idea to clone or
|
|
|
|
/// send it elsewhere, and what kind of handlers you cannot use.
|
|
|
|
pub fn outcome(self, outcome: Outcome) {
|
|
|
|
self.outcome.set(outcome).ok();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The environment given to the pre-spawn handler.
|
|
|
|
///
|
|
|
|
/// This deliberately does not implement Clone to make it hard to move it out of the handler, which
|
|
|
|
/// you should not do.
|
|
|
|
///
|
|
|
|
/// The [`PreSpawn::command()`] method is the only way to mutate the command, and the mutex guard it
|
|
|
|
/// returns _must_ be dropped before the handler returns.
|
2021-09-18 07:20:05 +02:00
|
|
|
#[derive(Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct PreSpawn {
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The command which is about to be spawned.
|
2022-06-16 17:36:08 +02:00
|
|
|
pub command: Command,
|
2021-12-29 08:40:12 +01:00
|
|
|
|
|
|
|
/// The collected events which triggered the action this command issues from.
|
2022-01-28 14:17:23 +01:00
|
|
|
pub events: Arc<[Event]>,
|
2021-12-29 08:40:12 +01:00
|
|
|
|
2022-06-16 17:36:08 +02:00
|
|
|
to_spawn_w: Weak<Mutex<TokioCommand>>,
|
2021-09-18 07:20:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PreSpawn {
|
2022-06-16 17:36:08 +02:00
|
|
|
pub(crate) fn new(
|
2021-12-29 08:40:12 +01:00
|
|
|
command: Command,
|
2022-06-16 17:36:08 +02:00
|
|
|
to_spawn: TokioCommand,
|
2022-01-28 14:17:23 +01:00
|
|
|
events: Arc<[Event]>,
|
2022-06-16 17:36:08 +02:00
|
|
|
) -> (Self, Arc<Mutex<TokioCommand>>) {
|
|
|
|
let arc = Arc::new(Mutex::new(to_spawn));
|
2021-09-18 07:20:05 +02:00
|
|
|
(
|
|
|
|
Self {
|
2022-06-16 17:36:08 +02:00
|
|
|
command,
|
2021-12-29 08:40:12 +01:00
|
|
|
events,
|
2022-06-16 17:36:08 +02:00
|
|
|
to_spawn_w: Arc::downgrade(&arc),
|
2021-09-18 07:20:05 +02:00
|
|
|
},
|
|
|
|
arc.clone(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get write access to the command that will be spawned.
|
|
|
|
///
|
|
|
|
/// Keeping the lock alive beyond the end of the handler may cause the command to be cancelled,
|
|
|
|
/// but note no guarantees are made on this behaviour. Just don't do it. See the [`Action`]
|
|
|
|
/// documentation about handlers for more.
|
|
|
|
///
|
|
|
|
/// This will always return `Some()` under normal circumstances.
|
2022-06-16 17:36:08 +02:00
|
|
|
pub async fn command(&self) -> Option<OwnedMutexGuard<TokioCommand>> {
|
|
|
|
if let Some(arc) = self.to_spawn_w.upgrade() {
|
2021-09-18 07:20:05 +02:00
|
|
|
Some(arc.lock_owned().await)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The environment given to the post-spawn handler.
|
|
|
|
///
|
|
|
|
/// This is Clone, as there's nothing (except returning an error) that can be done to the command
|
|
|
|
/// now that it's spawned, as far as Watchexec is concerned. Nevertheless, you should return from
|
|
|
|
/// this handler quickly, to avoid holding up anything else.
|
|
|
|
#[derive(Clone, Debug)]
|
2021-09-18 07:20:05 +02:00
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct PostSpawn {
|
2022-06-16 17:36:08 +02:00
|
|
|
/// The command the process was spawned with.
|
|
|
|
pub command: Command,
|
2021-10-16 14:12:04 +02:00
|
|
|
|
2021-12-29 08:40:12 +01:00
|
|
|
/// The collected events which triggered the action the command issues from.
|
2022-01-28 14:17:23 +01:00
|
|
|
pub events: Arc<[Event]>,
|
2021-12-29 08:40:12 +01:00
|
|
|
|
2021-10-16 14:12:04 +02:00
|
|
|
/// The process ID or the process group ID.
|
2021-09-18 07:20:05 +02:00
|
|
|
pub id: u32,
|
2021-10-16 14:12:04 +02:00
|
|
|
|
|
|
|
/// Whether the command was run in a process group.
|
2021-09-18 07:20:05 +02:00
|
|
|
pub grouped: bool,
|
|
|
|
}
|