mirror of
https://github.com/watchexec/watchexec.git
synced 2024-10-01 23:51:33 +02:00
Move filterer now that tagged is out
This commit is contained in:
parent
c73f0d086c
commit
576bcf67c7
@ -1,4 +1,144 @@
|
|||||||
mod common;
|
use std::{
|
||||||
mod globset;
|
ffi::OsString,
|
||||||
|
path::{Path, PathBuf, MAIN_SEPARATOR},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
pub use globset::globset;
|
use miette::{IntoDiagnostic, Result};
|
||||||
|
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||||
|
use tracing::{info, trace, trace_span};
|
||||||
|
use watchexec::{
|
||||||
|
error::RuntimeError,
|
||||||
|
event::{
|
||||||
|
filekind::{FileEventKind, ModifyKind},
|
||||||
|
Event, Priority, Tag,
|
||||||
|
},
|
||||||
|
filter::Filterer,
|
||||||
|
};
|
||||||
|
use watchexec_filterer_globset::GlobsetFilterer;
|
||||||
|
|
||||||
|
use crate::args::{Args, FsEvent};
|
||||||
|
|
||||||
|
mod dirs;
|
||||||
|
|
||||||
|
/// A custom filterer that combines the library's Globset filterer and a switch for --no-meta
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WatchexecFilterer {
|
||||||
|
inner: GlobsetFilterer,
|
||||||
|
fs_events: Vec<FsEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Filterer for WatchexecFilterer {
|
||||||
|
fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
|
||||||
|
for tag in &event.tags {
|
||||||
|
if let Tag::FileEventKind(fek) = tag {
|
||||||
|
let normalised = match fek {
|
||||||
|
FileEventKind::Access(_) => FsEvent::Access,
|
||||||
|
FileEventKind::Modify(ModifyKind::Name(_)) => FsEvent::Rename,
|
||||||
|
FileEventKind::Modify(ModifyKind::Metadata(_)) => FsEvent::Metadata,
|
||||||
|
FileEventKind::Modify(_) => FsEvent::Modify,
|
||||||
|
FileEventKind::Create(_) => FsEvent::Create,
|
||||||
|
FileEventKind::Remove(_) => FsEvent::Remove,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.fs_events.contains(&normalised) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("check against original event");
|
||||||
|
if !self.inner.check_event(event, priority)? {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WatchexecFilterer {
|
||||||
|
/// Create a new filterer from the given arguments
|
||||||
|
pub async fn new(args: &Args) -> Result<Arc<Self>> {
|
||||||
|
let (project_origin, workdir) = dirs::dirs(args).await?;
|
||||||
|
let vcs_types = dirs::vcs_types(&project_origin).await;
|
||||||
|
let ignore_files = dirs::ignores(args, &vcs_types, &project_origin).await;
|
||||||
|
|
||||||
|
let mut ignores = Vec::new();
|
||||||
|
|
||||||
|
if !args.no_default_ignore {
|
||||||
|
ignores.extend([
|
||||||
|
(format!("**{MAIN_SEPARATOR}.DS_Store"), None),
|
||||||
|
(String::from("watchexec.*.log"), None),
|
||||||
|
(String::from("*.py[co]"), None),
|
||||||
|
(String::from("#*#"), None),
|
||||||
|
(String::from(".#*"), None),
|
||||||
|
(String::from(".*.kate-swp"), None),
|
||||||
|
(String::from(".*.sw?"), None),
|
||||||
|
(String::from(".*.sw?x"), None),
|
||||||
|
(format!("**{MAIN_SEPARATOR}.bzr{MAIN_SEPARATOR}**"), None),
|
||||||
|
(format!("**{MAIN_SEPARATOR}_darcs{MAIN_SEPARATOR}**"), None),
|
||||||
|
(
|
||||||
|
format!("**{MAIN_SEPARATOR}.fossil-settings{MAIN_SEPARATOR}**"),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(format!("**{MAIN_SEPARATOR}.git{MAIN_SEPARATOR}**"), None),
|
||||||
|
(format!("**{MAIN_SEPARATOR}.hg{MAIN_SEPARATOR}**"), None),
|
||||||
|
(format!("**{MAIN_SEPARATOR}.pijul{MAIN_SEPARATOR}**"), None),
|
||||||
|
(format!("**{MAIN_SEPARATOR}.svn{MAIN_SEPARATOR}**"), None),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut filters = args
|
||||||
|
.filter_patterns
|
||||||
|
.iter()
|
||||||
|
.map(|f| (f.to_owned(), Some(workdir.clone())))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for filter_file in &args.filter_files {
|
||||||
|
filters.extend(read_filter_file(filter_file).await?);
|
||||||
|
}
|
||||||
|
|
||||||
|
ignores.extend(
|
||||||
|
args.ignore_patterns
|
||||||
|
.iter()
|
||||||
|
.map(|f| (f.to_owned(), Some(workdir.clone()))),
|
||||||
|
);
|
||||||
|
|
||||||
|
let exts = args
|
||||||
|
.filter_extensions
|
||||||
|
.iter()
|
||||||
|
.map(|e| OsString::from(e.strip_prefix('.').unwrap_or(e)));
|
||||||
|
|
||||||
|
info!("initialising Globset filterer");
|
||||||
|
Ok(Arc::new(Self {
|
||||||
|
inner: GlobsetFilterer::new(project_origin, filters, ignores, ignore_files, exts)
|
||||||
|
.await
|
||||||
|
.into_diagnostic()?,
|
||||||
|
fs_events: args.filter_fs_events.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_filter_file(path: &Path) -> Result<Vec<(String, Option<PathBuf>)>> {
|
||||||
|
let _span = trace_span!("loading filter file", ?path).entered();
|
||||||
|
|
||||||
|
let file = tokio::fs::File::open(path).await.into_diagnostic()?;
|
||||||
|
|
||||||
|
let mut filters =
|
||||||
|
Vec::with_capacity(file.metadata().await.map(|m| m.len() as usize).unwrap_or(0) / 20);
|
||||||
|
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let mut lines = reader.lines();
|
||||||
|
while let Some(line) = lines.next_line().await.into_diagnostic()? {
|
||||||
|
let line = line.trim();
|
||||||
|
if line.is_empty() || line.starts_with('#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!(?line, "adding filter line");
|
||||||
|
filters.push((line.to_owned(), Some(path.to_owned())));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(filters)
|
||||||
|
}
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
use std::{
|
|
||||||
ffi::OsString,
|
|
||||||
path::{Path, PathBuf, MAIN_SEPARATOR},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use miette::{IntoDiagnostic, Result};
|
|
||||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
|
||||||
use tracing::{info, trace, trace_span};
|
|
||||||
use watchexec::{error::RuntimeError, filter::Filterer};
|
|
||||||
use watchexec_events::{
|
|
||||||
filekind::{FileEventKind, ModifyKind},
|
|
||||||
Event, Priority, Tag,
|
|
||||||
};
|
|
||||||
use watchexec_filterer_globset::GlobsetFilterer;
|
|
||||||
|
|
||||||
use crate::args::{Args, FsEvent};
|
|
||||||
|
|
||||||
pub async fn globset(args: &Args) -> Result<Arc<WatchexecFilterer>> {
|
|
||||||
let (project_origin, workdir) = super::common::dirs(args).await?;
|
|
||||||
|
|
||||||
let ignore_files = if args.no_discover_ignore {
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
let vcs_types = super::common::vcs_types(&project_origin).await;
|
|
||||||
super::common::ignores(args, &vcs_types, &project_origin).await?
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut ignores = Vec::new();
|
|
||||||
|
|
||||||
if !args.no_default_ignore {
|
|
||||||
ignores.extend([
|
|
||||||
(format!("**{MAIN_SEPARATOR}.DS_Store"), None),
|
|
||||||
(String::from("watchexec.*.log"), None),
|
|
||||||
(String::from("*.py[co]"), None),
|
|
||||||
(String::from("#*#"), None),
|
|
||||||
(String::from(".#*"), None),
|
|
||||||
(String::from(".*.kate-swp"), None),
|
|
||||||
(String::from(".*.sw?"), None),
|
|
||||||
(String::from(".*.sw?x"), None),
|
|
||||||
(format!("**{MAIN_SEPARATOR}.bzr{MAIN_SEPARATOR}**"), None),
|
|
||||||
(format!("**{MAIN_SEPARATOR}_darcs{MAIN_SEPARATOR}**"), None),
|
|
||||||
(
|
|
||||||
format!("**{MAIN_SEPARATOR}.fossil-settings{MAIN_SEPARATOR}**"),
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
(format!("**{MAIN_SEPARATOR}.git{MAIN_SEPARATOR}**"), None),
|
|
||||||
(format!("**{MAIN_SEPARATOR}.hg{MAIN_SEPARATOR}**"), None),
|
|
||||||
(format!("**{MAIN_SEPARATOR}.pijul{MAIN_SEPARATOR}**"), None),
|
|
||||||
(format!("**{MAIN_SEPARATOR}.svn{MAIN_SEPARATOR}**"), None),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut filters = args
|
|
||||||
.filter_patterns
|
|
||||||
.iter()
|
|
||||||
.map(|f| (f.to_owned(), Some(workdir.clone())))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
for filter_file in &args.filter_files {
|
|
||||||
filters.extend(read_filter_file(filter_file).await?);
|
|
||||||
}
|
|
||||||
|
|
||||||
ignores.extend(
|
|
||||||
args.ignore_patterns
|
|
||||||
.iter()
|
|
||||||
.map(|f| (f.to_owned(), Some(workdir.clone()))),
|
|
||||||
);
|
|
||||||
|
|
||||||
let exts = args
|
|
||||||
.filter_extensions
|
|
||||||
.iter()
|
|
||||||
.map(|e| OsString::from(e.strip_prefix('.').unwrap_or(e)));
|
|
||||||
|
|
||||||
info!("initialising Globset filterer");
|
|
||||||
Ok(Arc::new(WatchexecFilterer {
|
|
||||||
inner: GlobsetFilterer::new(project_origin, filters, ignores, ignore_files, exts)
|
|
||||||
.await
|
|
||||||
.into_diagnostic()?,
|
|
||||||
fs_events: args.filter_fs_events.clone(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_filter_file(path: &Path) -> Result<Vec<(String, Option<PathBuf>)>> {
|
|
||||||
let _span = trace_span!("loading filter file", ?path).entered();
|
|
||||||
|
|
||||||
let file = tokio::fs::File::open(path).await.into_diagnostic()?;
|
|
||||||
|
|
||||||
let metadata_len = file
|
|
||||||
.metadata()
|
|
||||||
.await
|
|
||||||
.map(|m| usize::try_from(m.len()))
|
|
||||||
.unwrap_or(Ok(0))
|
|
||||||
.into_diagnostic()?;
|
|
||||||
let filter_capacity = if metadata_len == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
metadata_len / 20
|
|
||||||
};
|
|
||||||
let mut filters = Vec::with_capacity(filter_capacity);
|
|
||||||
|
|
||||||
let reader = BufReader::new(file);
|
|
||||||
let mut lines = reader.lines();
|
|
||||||
while let Some(line) = lines.next_line().await.into_diagnostic()? {
|
|
||||||
let line = line.trim();
|
|
||||||
if line.is_empty() || line.starts_with('#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!(?line, "adding filter line");
|
|
||||||
filters.push((line.to_owned(), Some(path.to_owned())));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(filters)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A custom filterer that combines the library's Globset filterer and a switch for --no-meta
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WatchexecFilterer {
|
|
||||||
inner: GlobsetFilterer,
|
|
||||||
fs_events: Vec<FsEvent>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Filterer for WatchexecFilterer {
|
|
||||||
fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
|
|
||||||
for tag in &event.tags {
|
|
||||||
if let Tag::FileEventKind(fek) = tag {
|
|
||||||
let normalised = match fek {
|
|
||||||
FileEventKind::Access(_) => FsEvent::Access,
|
|
||||||
FileEventKind::Modify(ModifyKind::Name(_)) => FsEvent::Rename,
|
|
||||||
FileEventKind::Modify(ModifyKind::Metadata(_)) => FsEvent::Metadata,
|
|
||||||
FileEventKind::Modify(_) => FsEvent::Modify,
|
|
||||||
FileEventKind::Create(_) => FsEvent::Create,
|
|
||||||
FileEventKind::Remove(_) => FsEvent::Remove,
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !self.fs_events.contains(&normalised) {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("check against original event");
|
|
||||||
if !self.inner.check_event(event, priority)? {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,6 +14,8 @@ use tracing::{debug, info, warn};
|
|||||||
use watchexec::Watchexec;
|
use watchexec::Watchexec;
|
||||||
use watchexec_events::{Event, Priority};
|
use watchexec_events::{Event, Priority};
|
||||||
|
|
||||||
|
use crate::filterer::WatchexecFilterer;
|
||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
mod config;
|
mod config;
|
||||||
mod emits;
|
mod emits;
|
||||||
@ -100,8 +102,8 @@ async fn run_watchexec(args: Args) -> Result<()> {
|
|||||||
info!(version=%env!("CARGO_PKG_VERSION"), "constructing Watchexec from CLI");
|
info!(version=%env!("CARGO_PKG_VERSION"), "constructing Watchexec from CLI");
|
||||||
|
|
||||||
let state = state::State::new()?;
|
let state = state::State::new()?;
|
||||||
let config = config::make_config(&args, &state)?;
|
let mut config = config::make_config(&args, &state)?;
|
||||||
config.filterer(filterer::globset(&args).await?);
|
config.filterer(WatchexecFilterer::new(&args).await?);
|
||||||
|
|
||||||
info!("initialising Watchexec runtime");
|
info!("initialising Watchexec runtime");
|
||||||
let wx = Watchexec::with_config(config)?;
|
let wx = Watchexec::with_config(config)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user