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;
|
||||
mod globset;
|
||||
use std::{
|
||||
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_events::{Event, Priority};
|
||||
|
||||
use crate::filterer::WatchexecFilterer;
|
||||
|
||||
pub mod args;
|
||||
mod config;
|
||||
mod emits;
|
||||
@ -100,8 +102,8 @@ async fn run_watchexec(args: Args) -> Result<()> {
|
||||
info!(version=%env!("CARGO_PKG_VERSION"), "constructing Watchexec from CLI");
|
||||
|
||||
let state = state::State::new()?;
|
||||
let config = config::make_config(&args, &state)?;
|
||||
config.filterer(filterer::globset(&args).await?);
|
||||
let mut config = config::make_config(&args, &state)?;
|
||||
config.filterer(WatchexecFilterer::new(&args).await?);
|
||||
|
||||
info!("initialising Watchexec runtime");
|
||||
let wx = Watchexec::with_config(config)?;
|
||||
|
Loading…
Reference in New Issue
Block a user