mirror of
https://github.com/zaphar/runwhen.git
synced 2025-07-22 20:39:49 -04:00
Exclude files using glob patterns
This commit is contained in:
parent
38b0b6aa59
commit
a7caf8a1c8
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -109,6 +109,12 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@ -298,6 +304,7 @@ name = "runwhen"
|
||||
version = "0.0.7"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"glob",
|
||||
"humantime",
|
||||
"notify",
|
||||
]
|
||||
|
@ -11,6 +11,7 @@ license = "Apache-2.0"
|
||||
[dependencies]
|
||||
humantime = "2.1.0"
|
||||
notify = "4.0.17"
|
||||
glob = "0.3.1"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "3.2.17"
|
||||
|
@ -21,6 +21,19 @@ pub enum WatchEventType {
|
||||
Ignore,
|
||||
}
|
||||
|
||||
pub fn get_file(evt: &DebouncedEvent) -> Option<&std::path::PathBuf> {
|
||||
match evt {
|
||||
DebouncedEvent::NoticeWrite(b)
|
||||
| DebouncedEvent::NoticeRemove(b)
|
||||
| DebouncedEvent::Create(b)
|
||||
| DebouncedEvent::Write(b)
|
||||
| DebouncedEvent::Chmod(b)
|
||||
| DebouncedEvent::Remove(b)
|
||||
| DebouncedEvent::Rename(b, _) => Some(b),
|
||||
DebouncedEvent::Error(_, _) | DebouncedEvent::Rescan => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DebouncedEvent> for WatchEventType {
|
||||
fn from(e: DebouncedEvent) -> WatchEventType {
|
||||
match e {
|
||||
|
29
src/file.rs
29
src/file.rs
@ -16,6 +16,7 @@ use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use glob;
|
||||
use notify::{watcher, RecursiveMode, Watcher};
|
||||
|
||||
use error::CommandError;
|
||||
@ -27,6 +28,7 @@ pub struct FileProcess<'a> {
|
||||
cmd: &'a str,
|
||||
env: Option<Vec<String>>,
|
||||
files: Vec<&'a str>,
|
||||
exclude: Option<Vec<&'a str>>,
|
||||
method: WatchEventType,
|
||||
poll: Option<Duration>,
|
||||
}
|
||||
@ -36,6 +38,7 @@ impl<'a> FileProcess<'a> {
|
||||
cmd: &'a str,
|
||||
env: Option<Vec<String>>,
|
||||
file: Vec<&'a str>,
|
||||
exclude: Option<Vec<&'a str>>,
|
||||
method: WatchEventType,
|
||||
poll: Option<Duration>,
|
||||
) -> FileProcess<'a> {
|
||||
@ -44,6 +47,7 @@ impl<'a> FileProcess<'a> {
|
||||
env,
|
||||
method,
|
||||
poll,
|
||||
exclude,
|
||||
files: file,
|
||||
}
|
||||
}
|
||||
@ -122,6 +126,7 @@ fn wait_for_fs_events(
|
||||
ch: Sender<()>,
|
||||
method: WatchEventType,
|
||||
files: &Vec<&str>,
|
||||
excluded: &Option<Vec<&str>>,
|
||||
) -> Result<(), CommandError> {
|
||||
// Notify requires a channel for communication.
|
||||
let (tx, rx) = channel();
|
||||
@ -137,9 +142,29 @@ fn wait_for_fs_events(
|
||||
watcher.watch(*file, RecursiveMode::Recursive)?;
|
||||
println!("Watching {:?}", *file);
|
||||
}
|
||||
let mut patterns = Vec::new();
|
||||
if let Some(exclude) = excluded {
|
||||
for ef in exclude.iter() {
|
||||
patterns.push(glob::Pattern::new(*ef).expect("Invalid path pattern"));
|
||||
//patterns.push(ef.clone());
|
||||
println!("Added pattern {:?}", patterns.iter().last());
|
||||
}
|
||||
}
|
||||
loop {
|
||||
let evt: WatchEventType = match rx.recv() {
|
||||
Ok(event) => WatchEventType::from(event),
|
||||
Ok(event) => {
|
||||
// TODO(jwall): Filter this based on the exclude pattern
|
||||
if let Some(f) = crate::events::get_file(&event) {
|
||||
for pat in patterns.iter() {
|
||||
println!("Testing pattern {:?} against {:?}", pat, f);
|
||||
if pat.matches_path(&f) {
|
||||
println!("Excluding: {:?}", f);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
WatchEventType::from(event)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Watch Error: {}", e);
|
||||
WatchEventType::Error
|
||||
@ -175,7 +200,7 @@ impl<'a> Process for FileProcess<'a> {
|
||||
watch_for_change_events(rx, cmd, env, poll);
|
||||
}
|
||||
});
|
||||
wait_for_fs_events(tx, self.method.clone(), &self.files)?;
|
||||
wait_for_fs_events(tx, self.method.clone(), &self.files, &self.exclude)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
11
src/main.rs
11
src/main.rs
@ -16,6 +16,7 @@
|
||||
extern crate clap;
|
||||
extern crate humantime;
|
||||
extern crate notify;
|
||||
extern crate glob;
|
||||
|
||||
use std::{process, str::FromStr};
|
||||
|
||||
@ -47,6 +48,10 @@ fn do_flags() -> clap::ArgMatches {
|
||||
arg!(-f --file).name("file")
|
||||
.takes_value(true).help("File or directory to watch for changes"),
|
||||
)
|
||||
.arg(
|
||||
arg!(-e --exclude).name("exclude")
|
||||
.takes_value(true).help("path names to skip when watching. Specified in unix glob format."),
|
||||
)
|
||||
.arg(arg!(--touch).name("filetouch").help("Use file or directory timestamps to monitor for changes."))
|
||||
.arg(arg!(--poll).name("poll").takes_value(true).value_parser(value_parser!(humantime::Duration)).help("Duration of time between polls")))
|
||||
.subcommand(
|
||||
@ -90,8 +95,12 @@ fn main() {
|
||||
Some(d) => Some((*d).into()),
|
||||
None => None,
|
||||
};
|
||||
let exclude = match matches.values_of("exclude") {
|
||||
Some(vr) => Some(vr.collect()),
|
||||
None => None,
|
||||
};
|
||||
println!("Enforcing a poll time of {:?}", duration);
|
||||
Box::new(FileProcess::new(cmd, maybe_env, file, method, duration))
|
||||
Box::new(FileProcess::new(cmd, maybe_env, file, exclude, method, duration))
|
||||
} else if let Some(matches) = app.subcommand_matches("timer") {
|
||||
// TODO(jwall): This should use cancelable commands.
|
||||
// Unwrap because this flag is required.
|
||||
|
Loading…
x
Reference in New Issue
Block a user