Skip to content

Commit

Permalink
Update dependencies (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
yozhgoor authored Oct 24, 2022
1 parent 5fba8d0 commit 7db06ed
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 66 deletions.
6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ include = ["src/**/*.rs", "README.md", "LICENSE.Apache-2.0", "LICENSE.MIT"]

[dependencies]
anyhow = "1.0.52"
cargo_metadata = "0.14.1"
cargo_metadata = "0.15.0"
clap = { version = "3.0.10", features = ["derive"] }
lazy_static = "1.4.0"
log = "0.4.14"
notify = "4.0.17"
notify = "5.0.0"

[target.'cfg(unix)'.dependencies]
libc = "0.2.112"

[workspace]
146 changes: 84 additions & 62 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,11 @@
use anyhow::{Context, Result};
use clap::Parser;
use lazy_static::lazy_static;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use notify::{Event, EventHandler, RecursiveMode, Watcher};
use std::{
env,
path::{Path, PathBuf},
process::Command,
sync::mpsc,
process::{Child, Command},
time::{Duration, Instant},
};

Expand Down Expand Up @@ -199,7 +198,7 @@ pub fn xtask_command() -> Command {
/// Watches over your project's source code, relaunching a given command when
/// changes are detected.
#[non_exhaustive]
#[derive(Debug, Default, Parser)]
#[derive(Clone, Debug, Default, Parser)]
#[clap(about = "Watches over your project's source code.")]
pub struct Watch {
/// Watch specific file(s) or folder(s).
Expand Down Expand Up @@ -310,71 +309,41 @@ impl Watch {
})
.collect::<Result<Vec<_>, _>>()?;

let (tx, rx) = mpsc::channel();
let mut watcher: RecommendedWatcher =
notify::Watcher::new_raw(tx).context("could not initialize watcher")?;
let child = command.spawn().context("cannot spawn command")?;

let handler = WatchEventHandler {
watch: self.clone(),
command,
child,
command_start: Instant::now(),
};

let mut watcher =
notify::recommended_watcher(handler).context("could not initialize watcher")?;

for path in &self.watch_paths {
match watcher.watch(&path, RecursiveMode::Recursive) {
match watcher.watch(path, RecursiveMode::Recursive) {
Ok(()) => log::trace!("Watching {}", path.display()),
Err(err) => log::error!("cannot watch {}: {}", path.display(), err),
Err(err) => log::error!("cannot watch {}: {err}", path.display()),
}
}

let mut child = command.spawn().context("cannot spawn command")?;
let mut command_start = Instant::now();

loop {
match rx.recv() {
Ok(notify::RawEvent {
path: Some(path),
op: Ok(op),
..
}) if !self.is_excluded_path(&path)
&& path.exists()
&& !self.is_hidden_path(&path)
&& !self.is_backup_file(&path)
&& op != notify::Op::CREATE
&& op != notify::Op::RENAME
&& command_start.elapsed() >= self.debounce =>
{
log::trace!("Detected changes at {} | {:?}", path.display(), op);
#[cfg(unix)]
{
let now = Instant::now();

unsafe {
log::trace!("Killing watch's command process");
libc::kill(
child.id().try_into().expect("cannot get process id"),
libc::SIGTERM,
);
}

while now.elapsed().as_secs() < 2 {
std::thread::sleep(Duration::from_millis(200));
if let Ok(Some(_)) = child.try_wait() {
break;
}
}
}

match child.try_wait() {
Ok(Some(_)) => {}
_ => {
let _ = child.kill();
let _ = child.wait();
}
}
Ok(())
}

log::info!("Re-running command");
child = command.spawn().context("cannot spawn command")?;
command_start = Instant::now();
}
Ok(event) => log::trace!("Ignoring changes in {:?}", event),
Err(err) => log::error!("watch error: {}", err),
}
}
fn compare_event(&self, event: &notify::Event, command_start: Instant) -> bool {
event.paths.iter().any(|x| {
!self.is_excluded_path(x)
&& x.exists()
&& !self.is_hidden_path(x)
&& !self.is_backup_file(x)
&& event.kind != notify::EventKind::Create(notify::event::CreateKind::Any)
&& event.kind
!= notify::EventKind::Modify(notify::event::ModifyKind::Name(
notify::event::RenameMode::Any,
))
&& command_start.elapsed() >= self.debounce
})
}

fn is_excluded_path(&self, path: &Path) -> bool {
Expand Down Expand Up @@ -412,6 +381,59 @@ impl Watch {
}
}

struct WatchEventHandler {
watch: Watch,
command: Command,
child: Child,
command_start: Instant,
}

impl EventHandler for WatchEventHandler {
fn handle_event(&mut self, event: Result<Event, notify::Error>) {
match event {
Ok(event) => {
if self.watch.compare_event(&event, self.command_start) {
log::trace!("Changes detected in {event:?}");
#[cfg(unix)]
{
let killing_start = Instant::now();

unsafe {
log::trace!("Killing watch's command process");
libc::kill(
self.child.id().try_into().expect("cannot get process id"),
libc::SIGTERM,
);
}

while killing_start.elapsed().as_secs() < 2 {
std::thread::sleep(Duration::from_millis(200));
if let Ok(Some(_)) = self.child.try_wait() {
break;
}
}
}

match self.child.try_wait() {
Ok(Some(_)) => {}
_ => {
let _ = self.child.kill();
let _ = self.child.wait();
}
}

log::info!("Re-running command");
self.child = self.command.spawn().expect("cannot spawn command");
self.command_start = Instant::now();
} else {
log::trace!("Ignoring changes in {event:?}");
}
}
Err(err) => log::error!("watch error: {err}"),
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down

0 comments on commit 7db06ed

Please sign in to comment.