Major changes for c bindings integration as third party crate (see project: github/InfinityMod/watchexec_c).

Changed version to 1.9.3 for third party crate compatibility detection.
This commit is contained in:
David Ziegler 2019-01-23 18:56:09 +01:00
parent 62d24168d6
commit 7b3daeef9c
7 changed files with 106 additions and 81 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
target target
*.tar.gz *.tar.gz
*.zip *.zip
*.vscode

View File

@ -1,6 +1,6 @@
[package] [package]
name = "watchexec" name = "watchexec"
version = "1.9.2" version = "1.9.3"
authors = ["Matt Green <mattgreenrocks@gmail.com>"] authors = ["Matt Green <mattgreenrocks@gmail.com>"]
description = "Executes commands in response to file modifications" description = "Executes commands in response to file modifications"
documentation = "https://github.com/watchexec/watchexec" documentation = "https://github.com/watchexec/watchexec"

View File

@ -1,7 +1,7 @@
use std::path::MAIN_SEPARATOR; use std::path::MAIN_SEPARATOR;
use std::process::Command; use std::process::Command;
use clap::{App, Arg, Error}; use clap::{App, Arg, Error, ArgMatches};
#[derive(Debug)] #[derive(Debug)]
pub struct Args { pub struct Args {
@ -32,10 +32,8 @@ pub fn clear_screen() {
let _ = Command::new("tput").arg("reset").status(); let _ = Command::new("tput").arg("reset").status();
} }
#[allow(unknown_lints)] pub fn init_app<'a, 'b>() -> App<'a, 'b> {
#[allow(or_fun_call)] let app = App::new("watchexec")
pub fn get_args() -> Args {
let args = App::new("watchexec")
.version(crate_version!()) .version(crate_version!())
.about("Execute commands when watched files change") .about("Execute commands when watched files change")
.arg(Arg::with_name("command") .arg(Arg::with_name("command")
@ -117,9 +115,11 @@ pub fn get_args() -> Args {
.help("Do not wrap command in 'sh -c' resp. 'cmd.exe /C'") .help("Do not wrap command in 'sh -c' resp. 'cmd.exe /C'")
.short("n") .short("n")
.long("no-shell")) .long("no-shell"))
.arg(Arg::with_name("once").short("1").hidden(true)) .arg(Arg::with_name("once").short("1").hidden(true));
.get_matches(); app
}
pub fn process_args(args: ArgMatches) -> Args{
let cmd: Vec<String> = values_t!(args.values_of("command"), String).unwrap(); let cmd: Vec<String> = values_t!(args.values_of("command"), String).unwrap();
let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]); let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);
@ -203,3 +203,10 @@ pub fn get_args() -> Args {
poll_interval: poll_interval, poll_interval: poll_interval,
} }
} }
#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
let args = init_app().get_matches();
process_args(args)
}

View File

@ -22,7 +22,7 @@ pub mod cli;
pub mod error; pub mod error;
mod gitignore; mod gitignore;
mod notification_filter; mod notification_filter;
mod pathop; pub mod pathop;
mod process; mod process;
pub mod run; pub mod run;
mod signal; mod signal;

View File

@ -2,5 +2,5 @@ extern crate watchexec;
use watchexec::{cli, error, run}; use watchexec::{cli, error, run};
fn main() -> error::Result<()> { fn main() -> error::Result<()> {
run(cli::get_args()) run(cli::get_args(), None::<fn(_)>)
} }

View File

@ -1,5 +1,6 @@
use notify::op; use notify::op;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::{SystemTime};
/// Info about a path and its corresponding `notify` event /// Info about a path and its corresponding `notify` event
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
@ -7,6 +8,7 @@ pub struct PathOp {
pub path: PathBuf, pub path: PathBuf,
pub op: Option<op::Op>, pub op: Option<op::Op>,
pub cookie: Option<u32>, pub cookie: Option<u32>,
pub time: SystemTime,
} }
impl PathOp { impl PathOp {
@ -15,6 +17,7 @@ impl PathOp {
path: path.to_path_buf(), path: path.to_path_buf(),
op: op, op: op,
cookie: cookie, cookie: cookie,
time: SystemTime::now(),
} }
} }

View File

@ -32,7 +32,7 @@ fn init_logger(debug: bool) {
.init(); .init();
} }
pub fn run(args: cli::Args) -> Result<()> { pub fn run<F>(args: cli::Args, cb: Option<F>) -> Result<()> where F: Fn(Vec<PathOp>) {
let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None)); let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
let weak_child = Arc::downgrade(&child_process); let weak_child = Arc::downgrade(&child_process);
@ -103,87 +103,101 @@ pub fn run(args: cli::Args) -> Result<()> {
*guard = Some(process::spawn(&args.cmd, vec![], args.no_shell)); *guard = Some(process::spawn(&args.cmd, vec![], args.no_shell));
} }
loop { //Decide if callback cb function or direct execution should be used
debug!("Waiting for filesystem activity"); let has_cb: bool = cb.is_some();
let paths = wait_fs(&rx, &filter, args.debounce); if has_cb {
if let Some(path) = paths.get(0) { let fcb = cb.unwrap();
debug!("Path updated: {:?}", path); loop {
debug!("Waiting for filesystem activity");
let paths = wait_fs(&rx, &filter, args.debounce);
if let Some(path) = paths.get(0) {
debug!("Path updated: {:?}", path);
}
//Execute callback
fcb(paths);
} }
}else{
loop {
debug!("Waiting for filesystem activity");
let paths = wait_fs(&rx, &filter, args.debounce);
if let Some(path) = paths.get(0) {
debug!("Path updated: {:?}", path);
}
// We have three scenarios here: // We have three scenarios here:
// //
// 1. Make sure the previous run was ended, then run the command again // 1. Make sure the previous run was ended, then run the command again
// 2. Just send a specified signal to the child, do nothing more // 2. Just send a specified signal to the child, do nothing more
// 3. Send SIGTERM to the child, wait for it to exit, then run the command again // 3. Send SIGTERM to the child, wait for it to exit, then run the command again
// 4. Send a specified signal to the child, wait for it to exit, then run the command again // 4. Send a specified signal to the child, wait for it to exit, then run the command again
// //
let scenario = (args.restart, signal.is_some()); let scenario = (args.restart, signal.is_some());
match scenario { match scenario {
// Custom restart behaviour (--restart was given, and --signal specified): // Custom restart behaviour (--restart was given, and --signal specified):
// Send specified signal to the child, wait for it to exit, then run the command again // Send specified signal to the child, wait for it to exit, then run the command again
(true, true) => { (true, true) => {
signal_process(&child_process, signal, true); signal_process(&child_process, signal, true);
// Launch child process // Launch child process
if args.clear_screen { if args.clear_screen {
cli::clear_screen(); cli::clear_screen();
}
debug!("Launching child process");
{
let mut guard = child_process.write().unwrap();
*guard = Some(process::spawn(&args.cmd, paths, args.no_shell));
}
} }
debug!("Launching child process"); // Default restart behaviour (--restart was given, but --signal wasn't specified):
{ // Send SIGTERM to the child, wait for it to exit, then run the command again
let mut guard = child_process.write().unwrap(); (true, false) => {
*guard = Some(process::spawn(&args.cmd, paths, args.no_shell)); let sigterm = signal::new(Some("SIGTERM".to_owned()));
signal_process(&child_process, sigterm, true);
// Launch child process
if args.clear_screen {
cli::clear_screen();
}
debug!("Launching child process");
{
let mut guard = child_process.write().unwrap();
*guard = Some(process::spawn(&args.cmd, paths, args.no_shell));
}
}
// SIGHUP scenario: --signal was given, but --restart was not
// Just send a signal (e.g. SIGHUP) to the child, do nothing more
(false, true) => signal_process(&child_process, signal, false),
// Default behaviour (neither --signal nor --restart specified):
// Make sure the previous run was ended, then run the command again
(false, false) => {
signal_process(&child_process, None, true);
// Launch child process
if args.clear_screen {
cli::clear_screen();
}
debug!("Launching child process");
{
let mut guard = child_process.write().unwrap();
*guard = Some(process::spawn(&args.cmd, paths, args.no_shell));
}
} }
} }
// Default restart behaviour (--restart was given, but --signal wasn't specified): // Handle once option for integration testing
// Send SIGTERM to the child, wait for it to exit, then run the command again if args.once {
(true, false) => { signal_process(&child_process, signal, false);
let sigterm = signal::new(Some("SIGTERM".to_owned())); break;
signal_process(&child_process, sigterm, true);
// Launch child process
if args.clear_screen {
cli::clear_screen();
}
debug!("Launching child process");
{
let mut guard = child_process.write().unwrap();
*guard = Some(process::spawn(&args.cmd, paths, args.no_shell));
}
} }
}
// SIGHUP scenario: --signal was given, but --restart was not
// Just send a signal (e.g. SIGHUP) to the child, do nothing more
(false, true) => signal_process(&child_process, signal, false),
// Default behaviour (neither --signal nor --restart specified):
// Make sure the previous run was ended, then run the command again
(false, false) => {
signal_process(&child_process, None, true);
// Launch child process
if args.clear_screen {
cli::clear_screen();
}
debug!("Launching child process");
{
let mut guard = child_process.write().unwrap();
*guard = Some(process::spawn(&args.cmd, paths, args.no_shell));
}
}
}
// Handle once option for integration testing
if args.once {
signal_process(&child_process, signal, false);
break;
}
} }
Ok(()) Ok(())
} }