Get filetype filters actually working

This commit is contained in:
Félix Saparelli 2021-10-14 01:26:15 +13:00
parent ae6af17aea
commit 14b0364135
No known key found for this signature in database
GPG key ID: B948C4BAE44FC474
2 changed files with 138 additions and 76 deletions

View file

@ -1,4 +1,8 @@
use std::{collections::HashSet, env::var, path::PathBuf}; use std::{
collections::HashSet,
env::{self, var},
path::PathBuf,
};
use dunce::canonicalize; use dunce::canonicalize;
use miette::{IntoDiagnostic, Result}; use miette::{IntoDiagnostic, Result};
@ -116,9 +120,14 @@ async fn main() -> Result<()> {
let mut filters = Vec::new(); let mut filters = Vec::new();
// TODO: move into config? // TODO: move into config
let workdir = env::current_dir()
.and_then(|wd| wd.canonicalize())
.into_diagnostic()?;
for filter in args.values_of("filter").unwrap_or_default() { for filter in args.values_of("filter").unwrap_or_default() {
filters.push(filter.parse()?); let mut filter: Filter = filter.parse()?;
filter.in_path = Some(workdir.clone());
filters.push(filter);
} }
for ext in args for ext in args
@ -136,6 +145,8 @@ async fn main() -> Result<()> {
}); });
} }
debug!(?filters, "parsed filters and extensions");
let (init, runtime, filterer) = config::new(&args)?; let (init, runtime, filterer) = config::new(&args)?;
filterer.add_filters(&filters).await?; filterer.add_filters(&filters).await?;

View file

@ -3,6 +3,7 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use dunce::canonicalize; use dunce::canonicalize;
use globset::Glob;
use ignore::gitignore::{Gitignore, GitignoreBuilder}; use ignore::gitignore::{Gitignore, GitignoreBuilder};
use ignore::Match; use ignore::Match;
use tokio::fs::read_to_string; use tokio::fs::read_to_string;
@ -16,7 +17,6 @@ use crate::filter::Filterer;
use crate::ignore_files::IgnoreFile; use crate::ignore_files::IgnoreFile;
// to make filters // to make filters
pub use globset::Glob;
pub use regex::Regex; pub use regex::Regex;
pub mod error; pub mod error;
@ -62,85 +62,116 @@ impl TaggedFilterer {
trace!(tags=%event.tags.len(), "checking all tags on the event"); trace!(tags=%event.tags.len(), "checking all tags on the event");
for tag in &event.tags { for tag in &event.tags {
let filters = self.filters.borrow().get(&tag.into()).cloned(); trace!(?tag, "checking tag");
if let Some(tag_filters) = filters { for matcher in Matcher::from_tag(tag) {
trace!(?tag, "checking tag"); let filters = self.filters.borrow().get(matcher).cloned();
if let Some(tag_filters) = filters {
if tag_filters.is_empty() {
trace!(?tag, ?matcher, "no filters for this tag, skipping (pass)");
continue;
}
if tag_filters.is_empty() { trace!(?tag, ?matcher, filters=%tag_filters.len(), "found some filters for this tag");
trace!(?tag, "no filters for this tag, skipping (pass)");
continue;
}
trace!(?tag, filters=%tag_filters.len(), "found some filters for this tag"); let mut tag_match = true;
let mut tag_match = true; if let (Matcher::Path, Tag::Path { path, file_type }) = (matcher, tag) {
let is_dir = file_type.map_or(false, |ft| ft.is_dir());
if let Tag::Path { path, file_type } = tag { let gc = self.glob_compiled.borrow();
let is_dir = file_type.map_or(false, |ft| ft.is_dir()); if let Some(igs) = gc.as_ref() {
trace!(?tag, ?matcher, "checking against compiled Glob filters");
let gc = self.glob_compiled.borrow(); match igs.matched(path, is_dir) {
if let Some(igs) = gc.as_ref() { Match::None => {
trace!(?tag, "checking against compiled Glob filters"); trace!(?tag, ?matcher, "no match (fail)");
match igs.matched(path, is_dir) { tag_match = false;
Match::None => { }
trace!(?tag, "no match (fail)"); Match::Ignore(glob) => {
tag_match = false; trace!(?tag, ?matcher, ?glob, "positive match (pass)");
tag_match = true;
}
Match::Whitelist(glob) => {
trace!(?tag, ?matcher, ?glob, "negative match (ignore)");
}
} }
Match::Ignore(glob) => { }
trace!(?tag, ?glob, "positive match (pass)");
tag_match = true; let ngc = self.not_glob_compiled.borrow();
} if let Some(ngs) = ngc.as_ref() {
Match::Whitelist(glob) => { trace!(?tag, ?matcher, "checking against compiled NotGlob filters");
trace!(?tag, ?glob, "negative match (ignore)"); match ngs.matched(path, is_dir) {
Match::None => {
trace!(?tag, ?matcher, "no match (pass)");
tag_match = true;
}
Match::Ignore(glob) => {
trace!(?tag, ?matcher, ?glob, "positive match (fail)");
tag_match = false;
}
Match::Whitelist(glob) => {
trace!(?tag, ?matcher, ?glob, "negative match (pass)");
tag_match = true;
}
} }
} }
} }
let ngc = self.not_glob_compiled.borrow(); // those are handled with the compiled ignore filters above
if let Some(ngs) = ngc.as_ref() { let tag_filters = tag_filters
trace!(?tag, "checking against compiled NotGlob filters"); .into_iter()
match ngs.matched(path, is_dir) { .filter(|f| {
Match::None => { !matches!(
trace!(?tag, "no match (pass)"); (tag, matcher, f),
tag_match = true; (
} Tag::Path { .. },
Match::Ignore(glob) => { Matcher::Path,
trace!(?tag, ?glob, "positive match (fail)"); Filter {
tag_match = false; on: Matcher::Path,
} op: Op::Glob | Op::NotGlob,
Match::Whitelist(glob) => { pat: Pattern::Glob(_),
trace!(?tag, ?glob, "negative match (pass)"); ..
tag_match = true; }
} )
} )
})
.collect::<Vec<_>>();
if tag_filters.is_empty() {
trace!(
?tag,
?matcher,
"no more filters for this tag, skipping (pass)"
);
continue;
} }
}
for filter in &tag_filters { trace!(?tag, ?matcher, filters=%tag_filters.len(), "got some filters to check still");
trace!(?filter, ?tag, "checking filter againt tag");
if let Some(app) = self.match_tag(filter, tag)? { for filter in &tag_filters {
if filter.negate { trace!(?filter, ?tag, "checking filter againt tag");
if app { if let Some(app) = self.match_tag(filter, tag)? {
trace!(prev=%tag_match, now=%true, "negate filter passes, resetting tag to pass"); if filter.negate {
tag_match = true; if app {
trace!(prev=%tag_match, now=%true, "negate filter passes, resetting tag to pass");
tag_match = true;
} else {
trace!(prev=%tag_match, now=%tag_match, "negate filter fails, ignoring");
}
} else { } else {
trace!(prev=%tag_match, now=%tag_match, "negate filter fails, ignoring"); trace!(prev=%tag_match, this=%app, now=%(tag_match&app), "filter applies to this tag");
tag_match &= app;
} }
} else {
trace!(prev=%tag_match, this=%app, now=%(tag_match&app), "filter applies to this tag");
tag_match &= app;
} }
} }
}
if !tag_match { if !tag_match {
trace!(?tag, "tag fails check, failing entire event"); trace!(?tag, ?matcher, "tag fails check, failing entire event");
return Ok(false); return Ok(false);
} }
trace!(?tag, "tag passes check, continuing"); trace!(?tag, ?matcher, "tag passes check, continuing");
} else { } else {
trace!(?tag, "no filters for this tag, skipping (pass)"); trace!(?tag, ?matcher, "no filters for this tag, skipping (pass)");
}
} }
} }
@ -379,8 +410,25 @@ impl Filter {
(Op::InSet, Pattern::Exact(pat)) => subject == pat, (Op::InSet, Pattern::Exact(pat)) => subject == pat,
(Op::NotInSet, Pattern::Set(set)) => !set.contains(subject), (Op::NotInSet, Pattern::Set(set)) => !set.contains(subject),
(Op::NotInSet, Pattern::Exact(pat)) => subject != pat, (Op::NotInSet, Pattern::Exact(pat)) => subject != pat,
(Op::Glob | Op::NotGlob, Pattern::Glob(_)) => { (op @ Op::Glob | op @ Op::NotGlob, Pattern::Glob(glob)) => {
todo!("glob matching for non paths???") // FIXME: someway that isn't this horrible
match Glob::new(glob) {
Ok(glob) => {
let matches = glob.compile_matcher().is_match(subject);
match op {
Op::Glob => matches,
Op::NotGlob => !matches,
_ => unreachable!(),
}
}
Err(err) => {
warn!(
"failed to compile glob for non-path match, skipping (pass): {}",
err
);
true
}
}
} }
(op, pat) => { (op, pat) => {
warn!( warn!(
@ -427,15 +475,18 @@ pub enum Matcher {
ProcessCompletion, ProcessCompletion,
} }
impl From<&Tag> for Matcher { impl Matcher {
fn from(tag: &Tag) -> Self { fn from_tag(tag: &Tag) -> &'static [Self] {
match tag { match tag {
Tag::Path { .. } => Matcher::Path, Tag::Path {
Tag::FileEventKind(_) => Matcher::FileEventKind, file_type: None, ..
Tag::Source(_) => Matcher::Source, } => &[Matcher::Path],
Tag::Process(_) => Matcher::Process, Tag::Path { .. } => &[Matcher::Path, Matcher::FileType],
Tag::Signal(_) => Matcher::Signal, Tag::FileEventKind(_) => &[Matcher::FileEventKind],
Tag::ProcessCompletion(_) => Matcher::ProcessCompletion, Tag::Source(_) => &[Matcher::Source],
Tag::Process(_) => &[Matcher::Process],
Tag::Signal(_) => &[Matcher::Signal],
Tag::ProcessCompletion(_) => &[Matcher::ProcessCompletion],
} }
} }
} }