Merge pull request #170 from matthiasbeyer/libimagentryfilter/init

Libimagentryfilter/init
This commit is contained in:
Matthias Beyer 2016-02-07 01:52:15 +01:00
commit 20ee0c958b
23 changed files with 627 additions and 0 deletions

View 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"

View 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()
}
}

View 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
}
}

View 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
}
}

View file

@ -0,0 +1,2 @@
pub mod is_over;
pub mod is_under;

View file

@ -0,0 +1,2 @@
pub mod grep;
pub mod length;

View 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)
}
}

View 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()
}
}

View 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)
}
}

View 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)
}
}

View 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)
}
}

View 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(())
}
}

View 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
}
}

View 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))
})
}
}

View 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;

View file

@ -0,0 +1,2 @@
pub mod content;
pub mod header;

View file

View 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)))
}
}

View 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;

View 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)
}
}

View file

@ -0,0 +1,3 @@
pub mod and;
pub mod not;
pub mod or;

View 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)
}
}

View 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)
}
}