Add option to exit when stdin ends (#449)

Co-authored-by: Félix Saparelli <felix@passcod.name>
This commit is contained in:
Michael Jones 2022-12-01 23:19:04 +00:00 committed by GitHub
parent db287c49f7
commit f613ba1a79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 307 additions and 63 deletions

156
Cargo.lock generated
View File

@ -282,9 +282,19 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
]
[[package]]
name = "bstr"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
dependencies = [
"memchr",
"once_cell",
"regex-automata",
"serde",
]
[[package]]
@ -764,11 +774,11 @@ checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
[[package]]
name = "git-actor"
version = "0.11.4"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f71e800c934ad4cb177a1a396a6ea57e4cb493bd5278d350752205570863478"
checksum = "ac9fb99c934ed45a62d9ae1e7b21949f2d869d1b82a07dcbf16ed61daa665870"
dependencies = [
"bstr",
"bstr 1.0.1",
"btoi",
"git-date",
"itoa",
@ -778,41 +788,55 @@ dependencies = [
[[package]]
name = "git-config"
version = "0.7.1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d533a785dd345fb133acde7a88ac264de96a1982cecad7f0e8a644ff4c39dcc5"
checksum = "bd1d13179bcf3dd68e83404f91a8d01c618f54eb97ef36c68ee5e6f30183a681"
dependencies = [
"bitflags",
"bstr",
"bstr 1.0.1",
"git-config-value",
"git-features",
"git-glob",
"git-path",
"git-ref",
"git-sec",
"libc",
"memchr",
"nom 7.1.1",
"once_cell",
"smallvec",
"thiserror",
"unicode-bom",
]
[[package]]
name = "git-date"
version = "0.1.0"
name = "git-config-value"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d58ccaaf783384a6ad68a6abf84942a3f88e34970ced3b34dc68183be50996d"
checksum = "64561e9700f1fc737fa3c1c4ea55293be70dba98e45c54cf3715cb180f37a566"
dependencies = [
"bstr",
"bitflags",
"bstr 1.0.1",
"git-path",
"libc",
"thiserror",
]
[[package]]
name = "git-date"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33db9f4462b565a33507aee113f3383bf16b988d2c573f07691e34302b7aa0a"
dependencies = [
"bstr 1.0.1",
"itoa",
"thiserror",
"time",
]
[[package]]
name = "git-features"
version = "0.22.4"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50af1af32068e5fb709ee479afc414ae98216869dfb1238ca99894a9073be34a"
checksum = "d7bdbe755d2129bc609437b6b18af1116f146128dda6070c15c0aa50201ac17c"
dependencies = [
"git-hash",
"libc",
@ -822,19 +846,19 @@ dependencies = [
[[package]]
name = "git-glob"
version = "0.3.2"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1879e27b5cb57bee828ea57a1ce9a004e9ae51fa71a2d4fb031175386df246"
checksum = "ef858611602fce54b51e45671ca72f07fe6a3c0e24a0539c66b75dfd4d84bd77"
dependencies = [
"bitflags",
"bstr",
"bstr 1.0.1",
]
[[package]]
name = "git-hash"
version = "0.9.9"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fafbe250292836c26f0e447f661789771c433ed50e49bc3d55b9fbc7c667213"
checksum = "d74d271e8194956dcb6f8bf94b6bc1f403acf34c81d9371c15e4145e6d059795"
dependencies = [
"hex",
"thiserror",
@ -842,9 +866,9 @@ dependencies = [
[[package]]
name = "git-lock"
version = "2.1.1"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ff6ad736a93573e219cb9b81c2edb6df0ced812f886e8003df375d96e650e73"
checksum = "89e4f05b8a68c3a5dd83a6651c76be384e910fe283072184fdab9d77f87ccec2"
dependencies = [
"fastrand",
"git-tempfile",
@ -853,11 +877,11 @@ dependencies = [
[[package]]
name = "git-object"
version = "0.20.3"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd987a3518738c902bd654f9b6ae7aa24934bf5a80b1614f8afb3a02c9bb16d3"
checksum = "ce0f14f9cd8f0782e843898a2fb7b0c2f5a6e37bd4cdff4409bb8ec698597dad"
dependencies = [
"bstr",
"bstr 1.0.1",
"btoi",
"git-actor",
"git-features",
@ -866,25 +890,25 @@ dependencies = [
"hex",
"itoa",
"nom 7.1.1",
"quick-error",
"smallvec",
"thiserror",
]
[[package]]
name = "git-path"
version = "0.4.2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05c3657d6f51d4d29b47812a77c0bb4df705d4d5bcd4fa41fd45729265e3420"
checksum = "5f60cbc13bc0fdd95df5f4b80437197e2853116792894b1bf38d1a6b4a64f8c9"
dependencies = [
"bstr",
"bstr 1.0.1",
"thiserror",
]
[[package]]
name = "git-ref"
version = "0.15.4"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c5926938f4732a200a5897f512234bf6d23e4bc5f23a6d371aae4a66c51020"
checksum = "22484043921e699edc170415789f1b882c8f3546e1fbbc447a0043ef07e088c4"
dependencies = [
"git-actor",
"git-features",
@ -896,27 +920,27 @@ dependencies = [
"git-validate",
"memmap2",
"nom 7.1.1",
"quick-error",
"thiserror",
]
[[package]]
name = "git-sec"
version = "0.3.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0073a138d171b64d5251726620c2232f695f7fbcfa7e5678dc62c1c19846f0e5"
checksum = "1ecb370efde58da72827909292284b5c5b885e0621a342515a36976b0b3bf660"
dependencies = [
"bitflags",
"dirs 4.0.0",
"git-path",
"libc",
"windows 0.37.0",
"windows 0.40.0",
]
[[package]]
name = "git-tempfile"
version = "2.0.4"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baed392d47397d32d29be06bc09824a259a44df85614fd301ef98e69770a15b9"
checksum = "a6bb4dee86c8cae5a078cfaac3b004ef99c31548ed86218f23a7ff9b4b74f3be"
dependencies = [
"dashmap",
"libc",
@ -928,12 +952,12 @@ dependencies = [
[[package]]
name = "git-validate"
version = "0.5.5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7af1453adfe6011f0ef71824591b7cdd85850c27bbf3dc8fa855574bed2fe107"
checksum = "cdf83bae632fc064ca938ebfb987364d9083b7f98b1476805f0a2d5eebb48686"
dependencies = [
"bstr",
"quick-error",
"bstr 1.0.1",
"thiserror",
]
[[package]]
@ -943,7 +967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
dependencies = [
"aho-corasick",
"bstr",
"bstr 0.2.17",
"fnv",
"log",
"regex",
@ -2786,15 +2810,17 @@ dependencies = [
[[package]]
name = "windows"
version = "0.37.0"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
checksum = "e30acc718a52fb130fec72b1cb5f55ffeeec9253e1b785e94db222178a6acaa1"
dependencies = [
"windows_aarch64_msvc 0.37.0",
"windows_i686_gnu 0.37.0",
"windows_i686_msvc 0.37.0",
"windows_x86_64_gnu 0.37.0",
"windows_x86_64_msvc 0.37.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.40.0",
"windows_i686_gnu 0.40.0",
"windows_i686_msvc 0.40.0",
"windows_x86_64_gnu 0.40.0",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.40.0",
]
[[package]]
@ -2810,6 +2836,12 @@ dependencies = [
"windows_x86_64_msvc 0.36.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3caa4a1a16561b714323ca6b0817403738583033a6a92e04c5d10d4ba37ca10"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
@ -2818,9 +2850,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.37.0"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
checksum = "328973c62dfcc50fb1aaa8e7100676e0b642fe56bac6bafff3327902db843ab4"
[[package]]
name = "windows_i686_gnu"
@ -2836,9 +2868,9 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.37.0"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
checksum = "aa5b09fad70f0df85dea2ac2a525537e415e2bf63ee31cf9b8e263645ee9f3c1"
[[package]]
name = "windows_i686_msvc"
@ -2854,9 +2886,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.37.0"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
checksum = "2a1ad4031c1a98491fa195d8d43d7489cb749f135f2e5c4eed58da094bd0d876"
[[package]]
name = "windows_x86_64_gnu"
@ -2872,9 +2904,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.37.0"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
checksum = "520ff37edd72da8064b49d2281182898e17f0688ae9f4070bca27e4b5c162ac7"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046e5b82215102c44fd75f488f1b9158973d02aa34d06ed85c23d6f5520a2853"
[[package]]
name = "windows_x86_64_msvc"
@ -2890,9 +2928,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.37.0"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
checksum = "2a0c9c6df55dd1bfa76e131cef44bdd8ec9c819ef3611f04dfe453fd5bfeda28"
[[package]]
name = "winreg"

View File

@ -71,6 +71,10 @@ pub fn get_args(tagged_filterer: bool) -> Result<ArgMatches> {
.value_name("milliseconds")
.short('d')
.long("debounce"))
.arg(Arg::new("stdin-quit")
.help_heading(Some(OPTSET_BEHAVIOUR))
.help("Stop watching when stdin closes")
.long("stdin-quit"))
.arg(Arg::new("verbose")
.help_heading(Some(OPTSET_DEBUGGING))
.help("Print debugging messages (-v, -vv, -vvv, -vvvv; use -vvv for bug reports)")

View File

@ -12,9 +12,10 @@ use watchexec::{
command::{Command, Shell},
config::RuntimeConfig,
error::RuntimeError,
event::ProcessEnd,
event::{ProcessEnd, Tag},
fs::Watcher,
handler::SyncFnHandler,
keyboard::Keyboard,
paths::summarise_events_to_env,
signal::{process::SubSignal, source::MainSignal},
};
@ -37,6 +38,8 @@ pub fn runtime(args: &ArgMatches) -> Result<RuntimeConfig> {
.into_diagnostic()?,
));
config.keyboard_emit_eof(args.is_present("stdin-quit"));
if let Some(interval) = args.value_of("poll") {
config.file_watcher(Watcher::Poll(Duration::from_millis(
interval.parse().into_diagnostic()?,
@ -120,6 +123,16 @@ pub fn runtime(args: &ArgMatches) -> Result<RuntimeConfig> {
return fut;
}
let is_keyboard_eof = action
.events
.iter()
.any(|e| e.tags.contains(&Tag::Keyboard(Keyboard::Eof)));
if is_keyboard_eof {
action.outcome(Outcome::both(Outcome::Stop, Outcome::Exit));
return fut;
}
if !has_paths {
if !signals.is_empty() {
let mut out = Outcome::DoNothing;

View File

@ -36,6 +36,9 @@ pub struct RuntimeConfig {
/// This notably includes the path set to be watched.
pub fs: crate::fs::WorkingData,
/// Working data for keyboard event sources.
pub keyboard: crate::keyboard::WorkingData,
/// Working data for the action processing.
///
/// This is the task responsible for scheduling the actions in response to events, applying the
@ -62,6 +65,12 @@ impl RuntimeConfig {
self
}
/// Enable monitoring of 'end of file' from stdin
pub fn keyboard_emit_eof(&mut self, enable: bool) -> &mut Self {
self.keyboard.eof = enable;
self
}
/// Set the action throttle.
pub fn action_throttle(&mut self, throttle: impl Into<Duration>) -> &mut Self {
self.action.throttle = throttle.into();

View File

@ -50,6 +50,15 @@ pub enum RuntimeError {
err: super::FsWatcherError,
},
/// Events from the keyboard event source
#[error("keyboard watcher error")]
#[diagnostic(code(watchexec::runtime::keyboard_watcher))]
KeyboardWatcher {
/// The underlying error.
#[source]
err: super::KeyboardWatcherError,
},
/// Opaque internal error from a command supervisor.
#[error("internal: command supervisor: {0}")]
#[diagnostic(code(watchexec::runtime::internal_supervisor))]

View File

@ -4,7 +4,7 @@ use miette::Diagnostic;
use thiserror::Error;
use tokio::sync::watch;
use crate::{action, fs};
use crate::{action, fs, keyboard};
/// Errors occurring from reconfigs.
#[derive(Debug, Diagnostic, Error)]
@ -20,6 +20,11 @@ pub enum ReconfigError {
#[error("reconfig: fs watch: {0}")]
#[diagnostic(code(watchexec::reconfig::fs_watch))]
FsWatch(#[from] watch::error::SendError<fs::WorkingData>),
/// Error received when the keyboard event source cannot be updated.
#[error("reconfig: keyboard watch: {0}")]
#[diagnostic(code(watchexec::reconfig::keyboard_watch))]
KeyboardWatch(#[from] watch::error::SendError<keyboard::WorkingData>),
}
/// Error when parsing a signal from string.
@ -117,3 +122,14 @@ pub enum FsWatcherError {
err: notify::Error,
},
}
/// Errors emitted by the keyboard watcher.
#[derive(Debug, Diagnostic, Error)]
#[non_exhaustive]
#[diagnostic(url(docsrs))]
pub enum KeyboardWatcherError {
/// Error received when shutting down stdin watcher fails.
#[error("failed to shut down stdin watcher")]
#[diagnostic(code(watchexec::keyboard_watcher))]
StdinShutdown,
}

View File

@ -16,6 +16,7 @@ use std::{
use filekind::FileEventKind;
use crate::keyboard::Keyboard;
use crate::signal::{process::SubSignal, source::MainSignal};
/// Re-export of the Notify file event types.
@ -55,6 +56,9 @@ pub enum Tag {
/// The general source of the event.
Source(Source),
/// The event was caused by specific keyboard input
Keyboard(Keyboard),
/// The event was caused by a particular process.
Process(u32),
@ -72,6 +76,7 @@ impl Tag {
Tag::Path { .. } => "Path",
Tag::FileEventKind(_) => "FileEventKind",
Tag::Source(_) => "Source",
Tag::Keyboard(_) => "Keyboard",
Tag::Process(_) => "Process",
Tag::Signal(_) => "Signal",
Tag::ProcessCompletion(_) => "ProcessCompletion",
@ -346,6 +351,7 @@ impl fmt::Display for Event {
}
Tag::FileEventKind(kind) => write!(f, " kind={:?}", kind)?,
Tag::Source(s) => write!(f, " source={:?}", s)?,
Tag::Keyboard(k) => write!(f, " keyboard={:?}", k)?,
Tag::Process(p) => write!(f, " process={}", p)?,
Tag::Signal(s) => write!(f, " signal={:?}", s)?,
Tag::ProcessCompletion(None) => write!(f, " command-completed")?,

132
crates/lib/src/keyboard.rs Normal file
View File

@ -0,0 +1,132 @@
//! Event source for keyboard input and related events
use async_priority_channel as priority;
use tokio::{
io::AsyncReadExt,
sync::{mpsc, oneshot, watch},
};
use tracing::trace;
use crate::{
error::{CriticalError, KeyboardWatcherError, RuntimeError},
event::{Event, Priority, Source, Tag},
};
/// The configuration of the [keyboard][self] worker.
///
/// This is marked non-exhaustive so new configuration can be added without breaking.
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct WorkingData {
/// Whether or not to watch for 'end of file' on stdin
pub eof: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
/// Enumeration of different keyboard events
pub enum Keyboard {
/// Event representing an 'end of file' on stdin
Eof,
}
/// Launch the filesystem event worker.
///
/// While you can run several, you should only have one.
///
/// Sends keyboard events via to the provided 'events' channel
pub async fn worker(
mut working: watch::Receiver<WorkingData>,
errors: mpsc::Sender<RuntimeError>,
events: priority::Sender<Event, Priority>,
) -> Result<(), CriticalError> {
let mut send_close = None;
while working.changed().await.is_ok() {
let watch_for_eof = { working.borrow().eof };
match (watch_for_eof, &send_close) {
// If we want to watch stdin and we're not already watching it then spawn a task to watch it
(true, None) => {
let (close_s, close_r) = tokio::sync::oneshot::channel::<()>();
send_close = Some(close_s);
tokio::spawn(watch_stdin(errors.clone(), events.clone(), close_r));
}
// If we don't want to watch stdin but we are already watching it then send a close signal to end the
// watching
(false, Some(_)) => {
// Repeat match using 'take'
if let Some(close_s) = send_close.take() {
if close_s.send(()).is_err() {
errors
.send(RuntimeError::KeyboardWatcher {
err: KeyboardWatcherError::StdinShutdown,
})
.await?;
}
}
}
// Otherwise no action is required
_ => {}
}
}
Ok(())
}
async fn watch_stdin(
errors: mpsc::Sender<RuntimeError>,
events: priority::Sender<Event, Priority>,
mut close_r: oneshot::Receiver<()>,
) -> Result<(), CriticalError> {
let mut stdin = tokio::io::stdin();
let mut buffer = [0; 10];
loop {
tokio::select! {
result = stdin.read(&mut buffer[..]) => {
// Read from stdin and if we've read 0 bytes then we assume stdin has received an 'eof' so
// we send that event into the system and break out of the loop as 'eof' means that there will
// be no more information on stdin.
match result {
Ok(0) => {
send_event(errors, events, Keyboard::Eof).await?;
break;
}
Err(_) => break,
_ => {
}
}
}
_ = &mut close_r => {
// If we receive a close signal then break out of the loop and end which drops
// our handle on stdin
break;
}
}
}
Ok(())
}
async fn send_event(
errors: mpsc::Sender<RuntimeError>,
events: priority::Sender<Event, Priority>,
msg: Keyboard,
) -> Result<(), CriticalError> {
let tags = vec![Tag::Source(Source::Keyboard), Tag::Keyboard(msg)];
let event = Event {
tags,
metadata: Default::default(),
};
trace!(?event, "processed keyboard input into event");
if let Err(err) = events.send(event, Priority::Normal).await {
errors
.send(RuntimeError::EventChannelSend {
ctx: "keyboard",
err,
})
.await?;
}
Ok(())
}

View File

@ -106,6 +106,7 @@ pub mod error;
pub mod event;
pub mod filter;
pub mod fs;
pub mod keyboard;
pub mod paths;
pub mod signal;

View File

@ -27,7 +27,7 @@ use crate::{
event::{Event, Priority},
fs,
handler::{rte, Handler},
signal,
keyboard, signal,
};
/// The main watchexec runtime.
@ -43,6 +43,7 @@ pub struct Watchexec {
action_watch: watch::Sender<action::WorkingData>,
fs_watch: watch::Sender<fs::WorkingData>,
keyboard_watch: watch::Sender<keyboard::WorkingData>,
event_input: priority::Sender<Event, Priority>,
}
@ -78,6 +79,7 @@ impl Watchexec {
let (ev_s, ev_r) = priority::bounded(init.event_channel_size);
let (ac_s, ac_r) = watch::channel(take(&mut runtime.action));
let (fs_s, fs_r) = watch::channel(fs::WorkingData::default());
let (keyboard_s, keyboard_r) = watch::channel(keyboard::WorkingData::default());
let event_input = ev_s.clone();
@ -86,6 +88,11 @@ impl Watchexec {
fs_s.send(take(&mut runtime.fs))
.expect("cannot send to just-created fs watch (bug)");
trace!("sending initial config to keyboard worker");
keyboard_s
.send(take(&mut runtime.keyboard))
.expect("cannot send to just-created keyboard watch (bug)");
trace!("creating main task");
let notify = Arc::new(Notify::new());
let start_lock = notify.clone();
@ -105,11 +112,15 @@ impl Watchexec {
let fs = SubTask::spawn("fs", fs::worker(fs_r, er_s.clone(), ev_s.clone()));
let signal =
SubTask::spawn("signal", signal::source::worker(er_s.clone(), ev_s.clone()));
let keyboard = SubTask::spawn(
"keyboard",
keyboard::worker(keyboard_r, er_s.clone(), ev_s.clone()),
);
let error_hook = SubTask::spawn("error_hook", error_hook(er_r, eh));
// Use Tokio TaskSet when that lands
try_join!(action, error_hook, fs, signal)
try_join!(action, error_hook, fs, signal, keyboard)
.map(drop)
.or_else(|e| {
// Close event channel to signal worker task to stop
@ -134,6 +145,7 @@ impl Watchexec {
action_watch: ac_s,
fs_watch: fs_s,
keyboard_watch: keyboard_s,
event_input,
}))
@ -144,6 +156,7 @@ impl Watchexec {
debug!(?config, "reconfiguring");
self.action_watch.send(config.action)?;
self.fs_watch.send(config.fs)?;
self.keyboard_watch.send(config.keyboard)?;
Ok(())
}

View File

@ -104,6 +104,9 @@ Terminates the command if it is still running when subsequent file modifications
* `-s`, `--signal`:
Sends the specified signal (e.g. `SIGKILL`) to the command. Defaults to `SIGTERM`.
* `--stdin-quit`:
Exit when watchexec's stdin is closed. This is useful when watchexec is run as a subprocess and should shut itself down when the parent process stops.
* `-W`, `--watch-when-idle`:
Ignore events while the process is still running. This is distinct from `--restart` in that with this option, events received while the command is running will not trigger a new run immediately after the current command is done.