Merge pull request #170 from matthiasbeyer/libimagentryfilter/init
Libimagentryfilter/init
This commit is contained in:
commit
20ee0c958b
23 changed files with 627 additions and 0 deletions
15
libimagentryfilter/Cargo.toml
Normal file
15
libimagentryfilter/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "libimagentryfilter"
|
||||
version = "0.1.0"
|
||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
||||
|
||||
[dependencies]
|
||||
clap = "1.5.5"
|
||||
itertools = "0.4.7"
|
||||
log = "0.3.4"
|
||||
regex = "0.1.48"
|
||||
toml = "0.1.27"
|
||||
|
||||
[dependencies.libimagstore]
|
||||
path = "../libimagstore"
|
||||
|
57
libimagentryfilter/src/builtin/content/grep.rs
Normal file
57
libimagentryfilter/src/builtin/content/grep.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use std::convert::Into;
|
||||
|
||||
use regex::Regex;
|
||||
use regex::Error as RError;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
pub trait IntoRegex {
|
||||
|
||||
fn into_regex(self) -> Result<Regex, RError>;
|
||||
|
||||
}
|
||||
|
||||
impl<'a> IntoRegex for &'a str {
|
||||
|
||||
fn into_regex(self) -> Result<Regex, RError> {
|
||||
Regex::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoRegex for Regex {
|
||||
|
||||
fn into_regex(self) -> Result<Regex, RError> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ContentGrep {
|
||||
regex: Regex,
|
||||
}
|
||||
|
||||
impl ContentGrep {
|
||||
|
||||
pub fn new<IR>(regex: IR) -> Result<ContentGrep, RError>
|
||||
where IR: IntoRegex
|
||||
{
|
||||
regex.into_regex()
|
||||
.map(|reg| {
|
||||
ContentGrep {
|
||||
regex: reg,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for ContentGrep {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
self.regex.captures(&e.get_content()[..]).is_some()
|
||||
}
|
||||
|
||||
}
|
||||
|
28
libimagentryfilter/src/builtin/content/length/is_over.rs
Normal file
28
libimagentryfilter/src/builtin/content/length/is_over.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
pub struct ContentLengthIsOver {
|
||||
val: usize
|
||||
}
|
||||
|
||||
impl ContentLengthIsOver {
|
||||
|
||||
pub fn new(value: usize) -> ContentLengthIsOver {
|
||||
ContentLengthIsOver {
|
||||
val: value,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for ContentLengthIsOver {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
e.get_content().len() > self.val
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
28
libimagentryfilter/src/builtin/content/length/is_under.rs
Normal file
28
libimagentryfilter/src/builtin/content/length/is_under.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
pub struct ContentLengthIsUnder {
|
||||
val: usize
|
||||
}
|
||||
|
||||
impl ContentLengthIsUnder {
|
||||
|
||||
pub fn new(value: usize) -> ContentLengthIsUnder {
|
||||
ContentLengthIsUnder {
|
||||
val: value,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for ContentLengthIsUnder {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
e.get_content().len() < self.val
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
2
libimagentryfilter/src/builtin/content/length/mod.rs
Normal file
2
libimagentryfilter/src/builtin/content/length/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod is_over;
|
||||
pub mod is_under;
|
2
libimagentryfilter/src/builtin/content/mod.rs
Normal file
2
libimagentryfilter/src/builtin/content/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod grep;
|
||||
pub mod length;
|
36
libimagentryfilter/src/builtin/header/field_eq.rs
Normal file
36
libimagentryfilter/src/builtin/header/field_eq.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
/// Check whether certain header field in a entry is equal to a value
|
||||
pub struct FieldEq {
|
||||
header_field_path: FieldPath,
|
||||
expected_value: Value
|
||||
}
|
||||
|
||||
impl FieldEq {
|
||||
|
||||
pub fn new(path: FieldPath, expected_value: Value) -> FieldEq {
|
||||
FieldEq {
|
||||
header_field_path: path,
|
||||
expected_value: expected_value,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for FieldEq {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
let header = e.get_header();
|
||||
self.header_field_path
|
||||
.walk(header)
|
||||
.map(|v| self.expected_value == v.clone())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
31
libimagentryfilter/src/builtin/header/field_exists.rs
Normal file
31
libimagentryfilter/src/builtin/header/field_exists.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
pub struct FieldExists {
|
||||
header_field_path: FieldPath,
|
||||
}
|
||||
|
||||
impl FieldExists {
|
||||
|
||||
pub fn new(path: FieldPath) -> FieldExists {
|
||||
FieldExists {
|
||||
header_field_path: path,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for FieldExists {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
let header = e.get_header();
|
||||
self.header_field_path.walk(header).is_some()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
43
libimagentryfilter/src/builtin/header/field_grep.rs
Normal file
43
libimagentryfilter/src/builtin/header/field_grep.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use regex::Regex;
|
||||
use toml::Value;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
/// Check whether certain header field in a entry is equal to a value
|
||||
pub struct FieldGrep {
|
||||
header_field_path: FieldPath,
|
||||
grep: Regex,
|
||||
}
|
||||
|
||||
impl FieldGrep {
|
||||
|
||||
pub fn new(path: FieldPath, grep: Regex) -> FieldGrep {
|
||||
FieldGrep {
|
||||
header_field_path: path,
|
||||
grep: grep,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for FieldGrep {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
let header = e.get_header();
|
||||
self.header_field_path
|
||||
.walk(header)
|
||||
.map(|v| {
|
||||
match v {
|
||||
Value::String(s) => self.grep.captures(&s[..]).is_some(),
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
45
libimagentryfilter/src/builtin/header/field_isempty.rs
Normal file
45
libimagentryfilter/src/builtin/header/field_isempty.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
pub struct FieldIsEmpty {
|
||||
header_field_path: FieldPath,
|
||||
}
|
||||
|
||||
impl FieldIsEmpty {
|
||||
|
||||
pub fn new(path: FieldPath) -> FieldIsEmpty {
|
||||
FieldIsEmpty {
|
||||
header_field_path: path,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for FieldIsEmpty {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
let header = e.get_header();
|
||||
self.header_field_path
|
||||
.walk(header)
|
||||
.map(|v| {
|
||||
match v {
|
||||
Value::Array(a) => a.is_empty(),
|
||||
Value::Boolean(_) => false,
|
||||
Value::Float(_) => false,
|
||||
Value::Integer(_) => false,
|
||||
Value::String(_) => false,
|
||||
Value::Table(t) => t.is_empty(),
|
||||
_ => true,
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
62
libimagentryfilter/src/builtin/header/field_istype.rs
Normal file
62
libimagentryfilter/src/builtin/header/field_istype.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use builtin::header::field_path::FieldPath;
|
||||
use filter::Filter;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
pub enum Type {
|
||||
Array,
|
||||
Boolean,
|
||||
Float,
|
||||
Integer,
|
||||
None,
|
||||
String,
|
||||
Table,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
|
||||
fn matches(&self, v: &Value) -> bool {
|
||||
match (self, v) {
|
||||
(&Type::String, &Value::String(_)) => true,
|
||||
(&Type::Integer, &Value::Integer(_)) => true,
|
||||
(&Type::Float, &Value::Float(_)) => true,
|
||||
(&Type::Boolean, &Value::Boolean(_)) => true,
|
||||
(&Type::Array, &Value::Array(_)) => true,
|
||||
(&Type::Table, &Value::Table(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct FieldIsType {
|
||||
header_field_path: FieldPath,
|
||||
expected_type: Type,
|
||||
}
|
||||
|
||||
impl FieldIsType {
|
||||
|
||||
pub fn new(path: FieldPath, expected_type: Type) -> FieldIsType {
|
||||
FieldIsType {
|
||||
header_field_path: path,
|
||||
expected_type: expected_type,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for FieldIsType {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
let header = e.get_header();
|
||||
self.header_field_path
|
||||
.walk(header)
|
||||
.map(|v| self.expected_type.matches(&v))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
47
libimagentryfilter/src/builtin/header/field_path/element.rs
Normal file
47
libimagentryfilter/src/builtin/header/field_path/element.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::fmt::Error as FmtError;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FieldPathElement {
|
||||
name: String
|
||||
}
|
||||
|
||||
impl FieldPathElement {
|
||||
|
||||
pub fn new(name: String) -> FieldPathElement {
|
||||
FieldPathElement { name: name }
|
||||
}
|
||||
|
||||
pub fn apply(&self, value: Value) -> Option<Value> {
|
||||
use std::str::FromStr;
|
||||
use std::ops::Index;
|
||||
|
||||
match value {
|
||||
Value::Table(t) => {
|
||||
t.get(&self.name).map(|a| a.clone())
|
||||
},
|
||||
|
||||
Value::Array(a) => {
|
||||
usize::from_str(&self.name[..])
|
||||
.ok()
|
||||
.and_then(|i| Some(a[i].clone()))
|
||||
},
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Display for FieldPathElement {
|
||||
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
||||
try!(write!(fmt, "{}", self.name));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
39
libimagentryfilter/src/builtin/header/field_path/error.rs
Normal file
39
libimagentryfilter/src/builtin/header/field_path/error.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::fmt::Error as FmtError;
|
||||
use std::error::Error;
|
||||
|
||||
use builtin::header::field_path::element::FieldPathElement;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FieldPathParsingError {
|
||||
source: String,
|
||||
token: FieldPathElement
|
||||
}
|
||||
|
||||
impl FieldPathParsingError {
|
||||
|
||||
pub fn new(source: String, token: FieldPathElement) -> FieldPathParsingError {
|
||||
FieldPathParsingError { source: source, token: token }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FieldPathParsingError {
|
||||
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
||||
try!(write!(fmt, "Failed to compile '{}', failed at: '{}'", self.source, self.token));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Error for FieldPathParsingError {
|
||||
|
||||
fn description(&self) -> &str {
|
||||
&self.source[..]
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
None
|
||||
}
|
||||
|
||||
}
|
44
libimagentryfilter/src/builtin/header/field_path/mod.rs
Normal file
44
libimagentryfilter/src/builtin/header/field_path/mod.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::fmt::Error as FmtError;
|
||||
use std::error::Error;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
pub mod element;
|
||||
pub mod error;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
use libimagstore::store::EntryHeader;
|
||||
|
||||
use builtin::header::field_path::element::FieldPathElement;
|
||||
use builtin::header::field_path::error::FieldPathParsingError;
|
||||
|
||||
pub struct FieldPath {
|
||||
elements: Vec<FieldPathElement>,
|
||||
}
|
||||
|
||||
impl FieldPath {
|
||||
|
||||
pub fn new(elements: Vec<FieldPathElement>) -> FieldPath {
|
||||
FieldPath {
|
||||
elements: elements,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(source: String) -> Result<FieldPath, FieldPathParsingError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn walk(&self, e: &EntryHeader) -> Option<Value> {
|
||||
let init_val : Value = Value::Table(e.toml().clone());
|
||||
|
||||
self.elements
|
||||
.clone()
|
||||
.into_iter()
|
||||
.fold(Some(init_val), |acc: Option<Value>, token: FieldPathElement| {
|
||||
acc.and_then(|element| token.apply(element))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
6
libimagentryfilter/src/builtin/header/mod.rs
Normal file
6
libimagentryfilter/src/builtin/header/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
pub mod field_eq;
|
||||
pub mod field_exists;
|
||||
pub mod field_grep;
|
||||
pub mod field_isempty;
|
||||
pub mod field_istype;
|
||||
pub mod field_path;
|
2
libimagentryfilter/src/builtin/mod.rs
Normal file
2
libimagentryfilter/src/builtin/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod content;
|
||||
pub mod header;
|
0
libimagentryfilter/src/cli.rs
Normal file
0
libimagentryfilter/src/cli.rs
Normal file
54
libimagentryfilter/src/filter.rs
Normal file
54
libimagentryfilter/src/filter.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
pub use ops::and::And;
|
||||
pub use ops::not::Not;
|
||||
pub use ops::or::Or;
|
||||
|
||||
pub trait Filter {
|
||||
|
||||
fn filter(&self, &Entry) -> bool;
|
||||
|
||||
fn not(self) -> Not
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
Not::new(Box::new(self))
|
||||
}
|
||||
|
||||
fn or(self, other: Box<Filter>) -> Or
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
Or::new(Box::new(self), other)
|
||||
}
|
||||
|
||||
fn or_not(self, other: Box<Filter>) -> Or
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
self.or(Box::new(Not::new(other)))
|
||||
}
|
||||
|
||||
fn or3(self, other: Box<Filter>, other2: Box<Filter>) -> Or
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
Or::new(Box::new(self), Box::new(Or::new(other, other2)))
|
||||
}
|
||||
|
||||
fn and(self, other: Box<Filter>) -> And
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
And::new(Box::new(self), other)
|
||||
}
|
||||
|
||||
fn and3(self, other: Box<Filter>, other2: Box<Filter>) -> And
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
And::new(Box::new(self), Box::new(And::new(other, other2)))
|
||||
}
|
||||
|
||||
fn and_not(self, other: Box<Filter>) -> And
|
||||
where Self: Sized + 'static
|
||||
{
|
||||
self.and(Box::new(Not::new(other)))
|
||||
}
|
||||
|
||||
}
|
||||
|
12
libimagentryfilter/src/lib.rs
Normal file
12
libimagentryfilter/src/lib.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
#[macro_use] extern crate log;
|
||||
|
||||
extern crate itertools;
|
||||
extern crate regex;
|
||||
extern crate toml;
|
||||
|
||||
extern crate libimagstore;
|
||||
|
||||
pub mod cli;
|
||||
pub mod builtin;
|
||||
pub mod filter;
|
||||
pub mod ops;
|
24
libimagentryfilter/src/ops/and.rs
Normal file
24
libimagentryfilter/src/ops/and.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use filter::Filter;
|
||||
|
||||
pub struct And {
|
||||
a: Box<Filter>,
|
||||
b: Box<Filter>
|
||||
}
|
||||
|
||||
impl And {
|
||||
|
||||
pub fn new(a: Box<Filter>, b: Box<Filter>) -> And {
|
||||
And { a: a, b: b }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for And {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
self.a.filter(e) && self.b.filter(e)
|
||||
}
|
||||
|
||||
}
|
3
libimagentryfilter/src/ops/mod.rs
Normal file
3
libimagentryfilter/src/ops/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod and;
|
||||
pub mod not;
|
||||
pub mod or;
|
23
libimagentryfilter/src/ops/not.rs
Normal file
23
libimagentryfilter/src/ops/not.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use filter::Filter;
|
||||
|
||||
pub struct Not {
|
||||
a: Box<Filter>
|
||||
}
|
||||
|
||||
impl Not {
|
||||
|
||||
pub fn new(a: Box<Filter>) -> Not {
|
||||
Not { a: a }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for Not {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
!self.a.filter(e)
|
||||
}
|
||||
|
||||
}
|
24
libimagentryfilter/src/ops/or.rs
Normal file
24
libimagentryfilter/src/ops/or.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use libimagstore::store::Entry;
|
||||
|
||||
use filter::Filter;
|
||||
|
||||
pub struct Or {
|
||||
a: Box<Filter>,
|
||||
b: Box<Filter>
|
||||
}
|
||||
|
||||
impl Or {
|
||||
|
||||
pub fn new(a: Box<Filter>, b: Box<Filter>) -> Or {
|
||||
Or { a: a, b: b }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Filter for Or {
|
||||
|
||||
fn filter(&self, e: &Entry) -> bool {
|
||||
self.a.filter(e) || self.b.filter(e)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue