use std::{
sync::{Arc, Mutex},
time::Duration,
};
use miette::{IntoDiagnostic, Result};
use watchexec::{
command::{Command, Program, Shell},
job::CommandState,
Watchexec,
};
use watchexec_events::{Event, Priority};
use watchexec_signals::Signal;
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
let job = Arc::new(Mutex::new(None));
let wx = Watchexec::new({
let outerjob = job.clone();
move |mut action| {
let (_, job) = action.create_job(Arc::new(Command {
program: Program::Shell {
shell: Shell::new("bash"),
command: "
echo 'Hello world'
trap 'echo Not quitting yet!' TERM
read
"
.into(),
args: Vec::new(),
},
options: Default::default(),
}));
*outerjob.lock().unwrap() = Some(job.clone());
#[cfg(unix)]
job.set_spawn_hook(|cmd, _| {
use nix::sys::signal::{sigprocmask, SigSet, SigmaskHow, Signal};
unsafe {
cmd.command_mut().pre_exec(|| {
let mut newset = SigSet::empty();
newset.add(Signal::SIGINT);
sigprocmask(SigmaskHow::SIG_BLOCK, Some(&newset), None)?;
Ok(())
});
}
});
job.start();
action
}
})?;
let main = wx.main();
wx.send_event(Event::default(), Priority::Urgent)
.await
.unwrap();
while job.lock().unwrap().is_none() {
tokio::task::yield_now().await;
}
let job = job.lock().unwrap().clone().unwrap();
let auto_restart = tokio::spawn(async move {
loop {
job.to_wait().await;
job.run(|context| {
if let CommandState::Finished {
status,
started,
finished,
} = context.current
{
let duration = *finished - *started;
eprintln!("[Program stopped with {status:?}; ran for {duration:?}]");
}
})
.await;
eprintln!("[Restarting...]");
job.start().await;
}
});
let auto_restart_abort = auto_restart.abort_handle();
wx.config.on_action(move |mut action| {
if action.signals().any(|sig| sig == Signal::Interrupt) {
eprintln!("[Quitting...]");
auto_restart_abort.abort();
action.quit_gracefully(Signal::ForceStop, Duration::ZERO);
return action;
}
if action.paths().next().is_some() {
if let Some(job) = action.list_jobs().next().map(|(_, job)| job) {
eprintln!("[Asking program to stop...]");
job.stop_with_signal(Signal::Terminate, Duration::from_secs(5));
}
}
action
});
wx.config.pathset(["."]);
let _ = main.await.into_diagnostic()?;
auto_restart.abort();
Ok(())
}