watchexec/crates/filterer/tagged/src/parse.rs

140 lines
3.4 KiB
Rust
Raw Normal View History

2021-09-18 07:07:32 +02:00
use std::str::FromStr;
2021-09-28 11:22:14 +02:00
use nom::{
branch::alt,
bytes::complete::{is_not, tag, tag_no_case, take_while1},
character::complete::char,
combinator::{map_res, opt},
sequence::{delimited, tuple},
Finish, IResult,
};
2021-09-18 07:07:32 +02:00
use regex::Regex;
2021-09-28 11:22:14 +02:00
use tracing::trace;
2021-09-18 07:07:32 +02:00
2022-06-15 05:25:05 +02:00
use crate::{Filter, Matcher, Op, Pattern, TaggedFiltererError};
2021-09-18 07:07:32 +02:00
impl FromStr for Filter {
type Err = TaggedFiltererError;
2021-09-18 07:07:32 +02:00
fn from_str(s: &str) -> Result<Self, Self::Err> {
fn matcher(i: &str) -> IResult<&str, Matcher> {
map_res(
alt((
tag_no_case("tag"),
tag_no_case("path"),
2021-10-12 17:06:55 +02:00
tag_no_case("type"),
2021-09-18 07:07:32 +02:00
tag_no_case("kind"),
2021-12-18 00:44:18 +01:00
tag_no_case("fek"),
2021-09-18 07:07:32 +02:00
tag_no_case("source"),
tag_no_case("src"),
tag_no_case("priority"),
2021-09-18 07:07:32 +02:00
tag_no_case("process"),
2021-12-18 00:44:18 +01:00
tag_no_case("pid"),
2021-09-18 07:07:32 +02:00
tag_no_case("signal"),
2021-12-21 04:19:35 +01:00
tag_no_case("sig"),
2021-12-18 00:44:18 +01:00
tag_no_case("complete"),
2021-09-18 07:07:32 +02:00
tag_no_case("exit"),
)),
|m: &str| match m.to_ascii_lowercase().as_str() {
"tag" => Ok(Matcher::Tag),
"path" => Ok(Matcher::Path),
2021-10-12 17:06:55 +02:00
"type" => Ok(Matcher::FileType),
2021-12-18 00:44:18 +01:00
"kind" | "fek" => Ok(Matcher::FileEventKind),
"source" | "src" => Ok(Matcher::Source),
"priority" => Ok(Matcher::Priority),
2021-12-18 00:44:18 +01:00
"process" | "pid" => Ok(Matcher::Process),
2021-12-21 04:19:35 +01:00
"signal" | "sig" => Ok(Matcher::Signal),
2021-12-18 00:44:18 +01:00
"complete" | "exit" => Ok(Matcher::ProcessCompletion),
2023-01-06 14:53:49 +01:00
m => Err(format!("unknown matcher: {m}")),
2021-09-18 07:07:32 +02:00
},
)(i)
}
fn op(i: &str) -> IResult<&str, Op> {
map_res(
alt((
tag("=="),
tag("!="),
tag("~="),
2021-12-16 15:57:25 +01:00
tag("~!"),
2021-09-18 07:07:32 +02:00
tag("*="),
2021-12-16 15:57:25 +01:00
tag("*!"),
2021-09-18 07:07:32 +02:00
tag(":="),
tag(":!"),
tag("="),
)),
|o: &str| match o {
"==" => Ok(Op::Equal),
"!=" => Ok(Op::NotEqual),
"~=" => Ok(Op::Regex),
"~!" => Ok(Op::NotRegex),
2021-09-18 07:07:32 +02:00
"*=" => Ok(Op::Glob),
"*!" => Ok(Op::NotGlob),
2021-09-18 07:07:32 +02:00
":=" => Ok(Op::InSet),
":!" => Ok(Op::NotInSet),
"=" => Ok(Op::Auto),
2023-01-06 14:53:49 +01:00
o => Err(format!("unknown op: `{o}`")),
2021-09-18 07:07:32 +02:00
},
)(i)
}
fn pattern(i: &str) -> IResult<&str, &str> {
alt((
// TODO: escapes
delimited(char('"'), is_not("\""), char('"')),
delimited(char('\''), is_not("'"), char('\'')),
take_while1(|_| true),
))(i)
}
fn filter(i: &str) -> IResult<&str, Filter> {
map_res(
tuple((opt(tag("!")), matcher, op, pattern)),
|(n, m, o, p)| -> Result<_, ()> {
2021-09-18 07:07:32 +02:00
Ok(Filter {
in_path: None,
on: m,
op: match o {
Op::Auto => match m {
Matcher::Path
| Matcher::FileEventKind
| Matcher::ProcessCompletion => Op::Glob,
2021-09-18 07:07:32 +02:00
_ => Op::InSet,
},
o => o,
},
pat: match (o, m) {
// TODO: carry regex/glob errors through
(
Op::Auto,
Matcher::Path | Matcher::FileEventKind | Matcher::ProcessCompletion,
)
2021-12-18 00:44:40 +01:00
| (Op::Glob | Op::NotGlob, _) => Pattern::Glob(p.to_string()),
2021-09-29 17:03:46 +02:00
(Op::Auto | Op::InSet | Op::NotInSet, _) => {
Pattern::Set(p.split(',').map(|s| s.trim().to_string()).collect())
2021-09-28 11:22:14 +02:00
}
(Op::Regex | Op::NotRegex, _) => {
Pattern::Regex(Regex::new(p).map_err(drop)?)
}
2021-09-29 17:03:46 +02:00
(Op::Equal | Op::NotEqual, _) => Pattern::Exact(p.to_string()),
2021-09-18 07:07:32 +02:00
},
negate: n.is_some(),
2021-09-18 07:07:32 +02:00
})
},
)(i)
}
2021-09-28 11:22:14 +02:00
trace!(src=?s, "parsing tagged filter");
2021-09-18 07:07:32 +02:00
filter(s)
.finish()
2021-09-28 11:22:14 +02:00
.map(|(_, f)| {
trace!(src=?s, filter=?f, "parsed tagged filter");
f
})
.map_err(|e| TaggedFiltererError::Parse {
2021-09-18 07:07:32 +02:00
src: s.to_string(),
err: e.code,
})
}
}