Add -k option to send SIGKILL instead of SIGTERM; closes #31

This commit is contained in:
Matt Green 2016-12-19 11:37:12 -05:00
parent 787c31040c
commit 9c65e816da
8 changed files with 45 additions and 24 deletions

View File

@ -1,6 +1,6 @@
VER=$(shell grep version Cargo.toml | head -n1 | grep -Eow '".+"' | sed 's/"//g')
.PHONY: doc
.PHONY: doc test
debug: src/* Cargo.toml
@cargo build

View File

@ -54,6 +54,10 @@ Call/restart `python server.py` when any Python file in the current directory (a
$ watchexec -e py -r python server.py
Call/restart `my_server` when any file in the current directory (and all subdirectories) changes, sending `SIGKILL` to stop the child process:
$ watchexec -r -k my_server
Run `make` when any file changes, using the `.gitignore` file in the current directory to filter:
$ watchexec make

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "WATCHEXEC" "1" "November 2016" "" ""
.TH "WATCHEXEC" "1" "December 2016" "" ""
.
.SH "NAME"
\fBwatchexec\fR \- execute commands when watched files change
@ -30,12 +30,16 @@ Comma\-separated list of file extensions to filter by\. Leading dots are allowed
Ignores modifications from paths that do not match \fIpattern\fR\. This option can be specified multiple times, where a match on any given pattern causes the path to trigger \fIcommand\fR\.
.
.TP
\fB\-k\fR, \fB\-\-kill\fR
Send \fBSIGKILL\fR to the child process group instead of \fBSIGTERM\fR\.
.
.TP
\fB\-i\fR, \fB\-\-ignore\fR \fIpattern\fR
Ignores modifications from paths that match \fIpattern\fR\. This option can be specified multiple times, and a match on any pattern causes the path to be ignored\.
.
.TP
\fB\-r\fR, \fB\-\-restart\fR
Sends \fBSIGTERM\fR to the child process if it is still running when subsequent file modifications are detected, then waits for the child to exit\.
Terminates the child process group if it is still running when subsequent file modifications are detected\. By default, sends \fBSIGTERM\fR; use \fB\-\-kill\fR to send \fBSIGKILL\fR\.
.
.TP
\fB\-c\fR, \fB\-\-clear\fR

View File

@ -88,8 +88,9 @@
<dt class="flush"><var>cmd</var></dt><dd><p>Command to run when watched files are modified, and at startup, unless <code>--postpone</code> is specified. All <var>argument</var>s are passed to <var>cmd</var>.</p></dd>
<dt><code>-e</code>, <code>--exts</code> <var>extensions</var></dt><dd><p>Comma-separated list of file extensions to filter by. Leading dots are allowed (.rs) are allowed. (This is a shorthand for <code>-f</code>).</p></dd>
<dt><code>-f</code>, <code>--filter</code> <var>pattern</var></dt><dd><p>Ignores modifications from paths that do not match <var>pattern</var>. This option can be specified multiple times, where a match on any given pattern causes the path to trigger <em>command</em>.</p></dd>
<dt><code>-k</code>, <code>--kill</code></dt><dd><p>Send <code>SIGKILL</code> to the child process group instead of <code>SIGTERM</code>.</p></dd>
<dt><code>-i</code>, <code>--ignore</code> <em>pattern</em></dt><dd><p>Ignores modifications from paths that match <var>pattern</var>. This option can be specified multiple times, and a match on any pattern causes the path to be ignored.</p></dd>
<dt><code>-r</code>, <code>--restart</code></dt><dd><p>Sends <code>SIGTERM</code> to the child process if it is still running when subsequent file modifications are detected, then waits for the child to exit.</p></dd>
<dt><code>-r</code>, <code>--restart</code></dt><dd><p>Terminates the child process group if it is still running when subsequent file modifications are detected. By default, sends <code>SIGTERM</code>; use <code>--kill</code> to send <code>SIGKILL</code>.</p></dd>
<dt><code>-c</code>, <code>--clear</code></dt><dd><p>Clears the screen before executing <var>command</var>.</p></dd>
<dt><code>-p</code>, <code>--postpone</code></dt><dd><p>Postpone execution of <var>command</var> until the first file modification is detected.</p></dd>
<dt><code>-d</code>, <code>--debug</code></dt><dd><p>Prints diagnostic messages to STDERR</p></dd>
@ -127,7 +128,7 @@
<ol class='man-decor man-foot man foot'>
<li class='tl'></li>
<li class='tc'>November 2016</li>
<li class='tc'>December 2016</li>
<li class='tr'>watchexec(1)</li>
</ol>

View File

@ -22,11 +22,14 @@ Comma-separated list of file extensions to filter by. Leading dots are allowed (
* `-f`, `--filter` <pattern>:
Ignores modifications from paths that do not match <pattern>. This option can be specified multiple times, where a match on any given pattern causes the path to trigger *command*.
* `-k`, `--kill`:
Send `SIGKILL` to the child process group instead of `SIGTERM`.
* `-i`, `--ignore` *pattern*:
Ignores modifications from paths that match <pattern>. This option can be specified multiple times, and a match on any pattern causes the path to be ignored.
* `-r`, `--restart`:
Sends `SIGTERM` to the child process if it is still running when subsequent file modifications are detected, then waits for the child to exit.
Terminates the child process group if it is still running when subsequent file modifications are detected. By default, sends `SIGTERM`; use `--kill` to send `SIGKILL`.
* `-c`, `--clear`:
Clears the screen before executing <command>.

View File

@ -9,6 +9,7 @@ pub struct Args {
pub filters: Vec<String>,
pub ignores: Vec<String>,
pub clear_screen: bool,
pub kill: bool,
pub restart: bool,
pub debug: bool,
pub run_initially: bool,
@ -81,6 +82,9 @@ pub fn get_args() -> Args {
.help("Forces polling mode")
.long("force-poll")
.value_name("interval"))
.arg(Arg::with_name("kill")
.help("Send SIGKILL to child processes")
.long("kill"))
.get_matches();
let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
@ -115,6 +119,7 @@ pub fn get_args() -> Args {
filters: filters,
ignores: ignores,
clear_screen: args.is_present("clear"),
kill: args.is_present("kill"),
restart: args.is_present("restart"),
debug: args.is_present("debug"),
run_initially: !args.is_present("postpone"),

View File

@ -79,8 +79,10 @@ fn init_logger(debug: bool) {
}
fn main() {
let args = cli::get_args();
let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
let weak_child = Arc::downgrade(&child_process);
let kill = args.kill;
signal::install_handler(move |sig: Signal| {
if let Some(lock) = weak_child.upgrade() {
@ -88,7 +90,12 @@ fn main() {
if let Some(ref child) = *strong {
match sig {
Signal::Terminate => {
child.kill();
if kill {
child.kill();
} else {
child.terminate();
}
child.wait();
},
Signal::Stop => {
@ -102,8 +109,6 @@ fn main() {
}
});
let args = cli::get_args();
init_logger(args.debug);
let cwd = env::current_dir()

View File

@ -8,8 +8,7 @@ pub use self::imp::Process;
#[cfg(target_family = "unix")]
mod imp {
use libc::c_int;
use libc::pid_t;
use libc::*;
use std::io::Result;
use std::path::PathBuf;
use std::process::Command;
@ -20,7 +19,6 @@ mod imp {
impl Process {
pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
use libc::exit;
use nix::unistd::*;
use std::fs::File;
use std::io;
@ -80,27 +78,19 @@ mod imp {
}
pub fn kill(&self) {
use libc::SIGTERM;
self.signal(SIGTERM);
self.signal(SIGKILL);
}
pub fn pause(&self) {
use libc::SIGTSTP;
self.signal(SIGTSTP);
}
pub fn resume(&self) {
use libc::SIGCONT;
self.signal(SIGCONT);
}
fn signal(&self, sig: c_int) {
use libc::*;
extern "C" {
fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
}
@ -111,6 +101,10 @@ mod imp {
}
pub fn terminate(&self) {
self.signal(SIGTERM);
}
pub fn wait(&self) {
use nix::sys::wait::waitpid;
@ -181,9 +175,7 @@ mod imp {
}
pub fn kill(&self) {
unsafe {
let _ = TerminateJobObject(self.job, 1);
}
self.terminate();
}
pub fn pause(&self) {
@ -192,6 +184,13 @@ mod imp {
pub fn resume(&self) {
}
pub fn terminate(&self) {
unsafe {
let _ = TerminateJobObject(self.job, 1);
}
}
pub fn wait(&self) {
unsafe {
let _ = WaitForSingleObject(self.job, INFINITE);