diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2019-07-28 12:54:34 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2019-07-28 12:54:34 +0200 |
commit | 598b6ec9a6f8eb0b878f924df3ebe10ca27d68b0 (patch) | |
tree | d07e9938d33bc6735033e8b0eeac22fa282f76db | |
parent | fc5bfb43bfe407656960cdda48c44e7bc8e29120 (diff) | |
parent | 981c6f852e1cc3e69db07931dc1156266dca8837 (diff) |
Merge branch 'imag-ids-split-into-more-tools' into master
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | bin/core/imag-id-in-collection/Cargo.toml | 40 | ||||
-rw-r--r-- | bin/core/imag-id-in-collection/src/main.rs | 120 | ||||
-rw-r--r-- | bin/core/imag-id-in-collection/src/ui.rs | 58 | ||||
-rw-r--r-- | bin/core/imag-ids/Cargo.toml | 3 | ||||
-rw-r--r-- | bin/core/imag-ids/src/id_filters.rs | 743 | ||||
-rw-r--r-- | bin/core/imag-ids/src/main.rs | 38 | ||||
-rw-r--r-- | bin/core/imag-ids/src/ui.rs | 22 | ||||
-rw-r--r-- | bin/core/imag-ids/static/language-doc.md | 51 | ||||
-rw-r--r-- | scripts/release.sh | 1 |
10 files changed, 221 insertions, 856 deletions
@@ -9,6 +9,7 @@ members = [ "bin/core/imag-gps", "bin/core/imag-grep", "bin/core/imag-header", + "bin/core/imag-id-in-collection", "bin/core/imag-ids", "bin/core/imag-init", "bin/core/imag-link", diff --git a/bin/core/imag-id-in-collection/Cargo.toml b/bin/core/imag-id-in-collection/Cargo.toml new file mode 100644 index 00000000..fc9f6136 --- /dev/null +++ b/bin/core/imag-id-in-collection/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "imag-id-in-collection" +version = "0.10.0" +authors = ["Matthias Beyer <mail@beyermatthias.de>"] + +description = "Part of the imag core distribution: imag-ids command" + +keywords = ["imag", "PIM", "personal", "information", "management"] +readme = "../../../README.md" +license = "LGPL-2.1" + +documentation = "https://imag-pim.org/doc/" +repository = "https://github.com/matthiasbeyer/imag" +homepage = "http://imag-pim.org" + +[badges] +travis-ci = { repository = "matthiasbeyer/imag" } +is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" } +is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" } +maintenance = { status = "actively-developed" } + +[dependencies] +filters = "0.3.0" +log = "0.4.6" +toml = "0.5.1" +toml-query = "0.9.2" +failure = "0.1.5" + +libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } +libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" } +libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } + +[dependencies.clap] +version = "2.33.0" +default-features = false +features = ["color", "suggestions", "wrap_help"] + +[dev-dependencies] +env_logger = "0.6.1" + diff --git a/bin/core/imag-id-in-collection/src/main.rs b/bin/core/imag-id-in-collection/src/main.rs new file mode 100644 index 00000000..8357828a --- /dev/null +++ b/bin/core/imag-id-in-collection/src/main.rs @@ -0,0 +1,120 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +#![forbid(unsafe_code)] + +#![deny( + non_camel_case_types, + non_snake_case, + path_statements, + trivial_numeric_casts, + unstable_features, + unused_allocation, + unused_import_braces, + unused_imports, + unused_must_use, + unused_mut, + unused_qualifications, + while_true, +)] + +extern crate clap; +extern crate filters; +#[macro_use] extern crate log; +extern crate toml; +extern crate toml_query; +extern crate failure; + +#[cfg(test)] +extern crate env_logger; + +extern crate libimagerror; +extern crate libimagstore; +#[macro_use] extern crate libimagrt; + +use std::io::Write; + +use filters::filter::Filter; + +use libimagstore::storeid::StoreId; +use libimagrt::setup::generate_runtime_setup; +use libimagerror::trace::MapErrTrace; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; + +mod ui; + +pub struct IsInCollectionsFilter<'a, A>(Option<A>, ::std::marker::PhantomData<&'a str>) + where A: AsRef<[&'a str]>; + +impl<'a, A> IsInCollectionsFilter<'a, A> + where A: AsRef<[&'a str]> +{ + pub fn new(collections: Option<A>) -> Self { + IsInCollectionsFilter(collections, ::std::marker::PhantomData) + } +} + +impl<'a, A> Filter<StoreId> for IsInCollectionsFilter<'a, A> + where A: AsRef<[&'a str]> + 'a +{ + fn filter(&self, sid: &StoreId) -> bool { + match self.0 { + Some(ref colls) => sid.is_in_collection(colls), + None => true, + } + } +} + + +fn main() { + let version = make_imag_version!(); + let rt = generate_runtime_setup("imag-id-in-collection", + &version, + "filter ids by collection", + crate::ui::build_ui); + let values = rt + .cli() + .values_of("in-collection-filter") + .map(|v| v.collect::<Vec<&str>>()); + + let collection_filter = IsInCollectionsFilter::new(values); + + let mut stdout = rt.stdout(); + trace!("Got output: {:?}", stdout); + + + rt.ids::<crate::ui::PathProvider>() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .iter() + .filter(|id| collection_filter.filter(id)) + .for_each(|id| { + rt.report_touched(&id).unwrap_or_exit(); + if !rt.output_is_pipe() { + let id = id.to_str().map_err_trace_exit_unwrap(); + trace!("Writing to {:?}", stdout); + writeln!(stdout, "{}", id).to_exit_code().unwrap_or_exit(); + } + }) +} + diff --git a/bin/core/imag-id-in-collection/src/ui.rs b/bin/core/imag-id-in-collection/src/ui.rs new file mode 100644 index 00000000..6480550b --- /dev/null +++ b/bin/core/imag-id-in-collection/src/ui.rs @@ -0,0 +1,58 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::path::PathBuf; + +use clap::{Arg, ArgMatches, App}; +use failure::Fallible as Result; + +use libimagstore::storeid::StoreId; +use libimagrt::runtime::IdPathProvider; + +pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { + app + .arg(Arg::with_name("in-collection-filter") + .index(1) + .required(true) + .takes_value(true) + .multiple(false) + .value_name("COLLECTION") + .help("Filter for ids which are in this collection")) + + .arg(Arg::with_name("ids") + .index(2) + .required(false) + .takes_value(true) + .multiple(true) + .value_names(&["IDs"]) + .help("Ids to filter")) +} + +pub struct PathProvider; +impl IdPathProvider for PathProvider { + fn get_ids(matches: &ArgMatches) -> Result<Option<Vec<StoreId>>> { + if let Some(ids) = matches.values_of("ids") { + ids.map(|i| StoreId::new(PathBuf::from(i))) + .collect::<Result<Vec<StoreId>>>() + .map(Some) + } else { + Ok(None) + } + } +} diff --git a/bin/core/imag-ids/Cargo.toml b/bin/core/imag-ids/Cargo.toml index 05167dd1..eca1fa39 100644 --- a/bin/core/imag-ids/Cargo.toml +++ b/bin/core/imag-ids/Cargo.toml @@ -20,12 +20,9 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" } maintenance = { status = "actively-developed" } [dependencies] -filters = "0.3.0" -nom = "3.2.0" log = "0.4.6" toml = "0.5.1" toml-query = "0.9.2" -is-match = "0.1.0" failure = "0.1.5" libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } diff --git a/bin/core/imag-ids/src/id_filters.rs b/bin/core/imag-ids/src/id_filters.rs deleted file mode 100644 index da9de964..00000000 --- a/bin/core/imag-ids/src/id_filters.rs +++ /dev/null @@ -1,743 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; version -// 2.1 of the License. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// - -use filters::filter::Filter; - -use libimagstore::storeid::StoreId; - -pub struct IsInCollectionsFilter<'a, A>(Option<A>, ::std::marker::PhantomData<&'a str>) - where A: AsRef<[&'a str]>; - -impl<'a, A> IsInCollectionsFilter<'a, A> - where A: AsRef<[&'a str]> -{ - pub fn new(collections: Option<A>) -> Self { - IsInCollectionsFilter(collections, ::std::marker::PhantomData) - } -} - -impl<'a, A> Filter<StoreId> for IsInCollectionsFilter<'a, A> - where A: AsRef<[&'a str]> + 'a -{ - fn filter(&self, sid: &StoreId) -> bool { - match self.0 { - Some(ref colls) => sid.is_in_collection(colls), - None => true, - } - } -} - -/// Language definition for the header-filter language -pub mod header_filter_lang { - use std::str; - use std::str::FromStr; - use std::process::exit; - - use nom::digit; - use nom::multispace; - use failure::Error; - - use libimagstore::store::Entry; - use libimagerror::trace::MapErrTrace; - - #[derive(Debug, PartialEq, Eq)] - enum Unary { - Not - } - - named!(unary_operator<Unary>, alt_complete!( - tag!("not") => { |_| { trace!("Unary::Not"); Unary::Not }} - )); - - #[derive(Debug, PartialEq, Eq)] - enum CompareOp { - OpIs, - OpIn, - OpEq, - OpNeq, - OpGte, // >= - OpLte, // <= - OpLt, // < - OpGt, // > - } - - named!(compare_op<CompareOp>, alt_complete!( - tag!("is" ) => { |_| { trace!("CompareOp::OpIs"); CompareOp::OpIs }} | - tag!("in" ) => { |_| { trace!("CompareOp::OpIn"); CompareOp::OpIn }} | - tag!("==" ) => { |_| { trace!("CompareOp::OpEq"); CompareOp::OpEq }} | - tag!("eq" ) => { |_| { trace!("CompareOp::OpEq"); CompareOp::OpEq }} | - tag!("!=" ) => { |_| { trace!("CompareOp::OpNeq"); CompareOp::OpNeq }} | - tag!("neq") => { |_| { trace!("CompareOp::OpNeq"); CompareOp::OpNeq }} | - tag!(">=" ) => { |_| { trace!("CompareOp::OpGte"); CompareOp::OpGte }} | - tag!("<=" ) => { |_| { trace!("CompareOp::OpLte"); CompareOp::OpLte }} | - tag!("<" ) => { |_| { trace!("CompareOp::OpLt"); CompareOp::OpLt }} | - tag!(">" ) => { |_| { trace!("CompareOp::OpGt"); CompareOp::OpGt }} - )); - - #[derive(Debug, PartialEq, Eq)] - enum Operator { - Or, - And, - Xor, - } - - named!(operator<Operator>, alt_complete!( - tag!("or") => { |_| { trace!("Operator::Or"); Operator::Or }} | - tag!("and") => { |_| { trace!("Operator::And"); Operator::And }} | - tag!("xor") => { |_| { trace!("Operator::Xor"); Operator::Xor }} - )); - - #[derive(Debug, PartialEq, Eq)] - enum Function { - Length, - Keys, - Values, - } - - named!(function<Function>, alt_complete!( - tag!("length") => { |_| { trace!("Function::Length"); Function::Length }} | - tag!("keys") => { |_| { trace!("Function::Keys"); Function::Keys }} | - tag!("values") => { |_| { trace!("Function::Values"); Function::Values }} - )); - - #[derive(Debug, PartialEq, Eq)] - enum Value { - Boolean(bool), - Integer(i64), - String(String), - } - - named!(int64<i64>, map!(digit, |r: &[u8]| { - let val = str::from_utf8(r).unwrap_or_else(|e| { - error!("Error = '{:?}'", e); - ::std::process::exit(1) - }); - - i64::from_str(val).unwrap_or_else(|e| { - error!("Error while parsing number: '{:?}'", e); - ::std::process::exit(1) - }) - })); - - named!(signed_digits<(Option<&[u8]>, i64)>, - pair!(opt!(alt!(tag_s!("+") | tag_s!("-"))), int64) - ); - named!(integer<i64>, do_parse!(tpl: signed_digits >> ({ - let v = match tpl.0 { - Some(b"-") => -tpl.1, - _ => tpl.1, - }; - trace!("integer = {:?}", v); - v - }))); - - named!(boolean<bool>, alt_complete!( - tag!("false") => { |_| { trace!("'false'"); false }} | - tag!("true") => { |_| { trace!("'true'"); true }} - )); - - named!(string<String>, do_parse!( - text: delimited!(char!('"'), take_until!("\""), char!('"')) - >> ({ - let s = String::from_utf8(text.to_vec()).unwrap(); - trace!("Parsed string: {:?}", s); - s - }) - )); - - named!(val<Value>, alt_complete!( - do_parse!(b: boolean >> ({ - let v = Value::Boolean(b); - trace!("Value = {:?}", v); - v - })) | - do_parse!(number: integer >> ({ - let v = Value::Integer(number); - trace!("Value = {:?}", v); - v - })) | - do_parse!(text: string >> ({ - let v = Value::String(text); - trace!("Value = {:?}", v); - v - })) - )); - - named!(list_of_val<Vec<Value>>, do_parse!( - char!('[') >> - list: many0!( - do_parse!( - list: terminated!(val, opt!(char!(','))) >> - opt!(multispace) >> - (list) - )) >> - char!(']') >> (list) - )); - - #[derive(Debug, PartialEq, Eq)] - enum CompareValue { - Value(Value), - Values(Vec<Value>) - } - - named!(compare_value<CompareValue>, alt_complete!( - do_parse!(list: list_of_val >> (CompareValue::Values(list))) | - do_parse!(val: val >> (CompareValue::Value(val))) - )); - - #[derive(Debug, PartialEq, Eq)] - enum Selector { - Direct(String), - Function(Function, String) - } - - impl Selector { - fn selector_str(&self) -> &String { - match *self { - Selector::Direct(ref s) => s, - Selector::Function(_, ref s) => s, - } - } - fn function(&self) -> Option<&Function> { - match *self { - Selector::Direct(_) => None, - Selector::Function(ref f, _) => Some(f), - } - } - } - - named!(selector_str<String>, do_parse!( - selector: take_till!(|s: u8| s == b' ') >> (String::from_utf8(selector.to_vec()).unwrap()) - )); - - named!(bracketed, - delimited!( - tag!("("), - take_until!(")"), - tag!(")") - ) - ); - - named!(selector<Selector>, alt_complete!( - do_parse!(fun: function >> sel: bracketed >> ({ - let sel = Selector::Function(fun, String::from_utf8(sel.to_vec()).unwrap()); - trace!("Building Selector object: {:?}", sel); - sel - })) | - do_parse!(sel: selector_str >> ({ - let sel = Selector::Direct(sel); - trace!("Building Selector object: {:?}", sel); - sel - })) - )); - - #[derive(Debug, PartialEq, Eq)] - struct Filter { - unary : Option<Unary>, - selector : Selector, - compare_operator : CompareOp, - compare_value : CompareValue, - } - - named!(filter<Filter>, do_parse!( - unary: opt!(unary_operator) >> - selec: selector >> opt!(multispace) >> - comop: compare_op >> opt!(multispace) >> - cmval: compare_value >> - ({ - let f = Filter { - unary: unary, - selector: selec, - compare_operator: comop, - compare_value: cmval, - }; - - trace!("Building Filter object: {:?}", f); - f - }) - )); - - #[derive(Debug, PartialEq, Eq)] - pub struct Query { - filter: Filter, - next_filters: Vec<(Operator, Filter)>, - } - - named!(parse_query<Query>, do_parse!( - filt: filter >> - next: many0!(do_parse!(opt!(multispace) >> op: operator >> opt!(multispace) >> fil: filter >> ((op, fil)))) >> - ({ - let q = Query { - filter: filt, - next_filters: next, - }; - - trace!("Building Query object: {:?}", q); - - q - }) - )); - - /// Helper type which can filters::filter::Filter be implemented on so that the implementation - /// of ::filters::filter::Filter on self::Filter is less complex. - struct Comparator<'a>(&'a CompareOp, &'a CompareValue); - - impl<'a> ::filters::filter::Filter<::toml::Value> for Comparator<'a> { - fn filter(&self, val: &::toml::Value) -> bool { - use self::CompareValue as CV; - use self::CompareOp as CO; - use toml::Value as TVal; - - match *self.0 { - CO::OpIs => match self.1 { - &CV::Values(_) => error_exit("Cannot check whether a header field is the same type as mulitple values!"), - &CV::Value(ref v) => { - trace!("Checking whether {:?} and {:?} have same type", v, val); - match v { - &Value::Boolean(_) => is_match!(*val, TVal::Boolean(_)), - &Value::Integer(_) => is_match!(*val, TVal::Integer(_)), - &Value::String(_) => is_match!(val, &TVal::String(_)), - } - }, - }, - CO::OpIn => { - trace!("Checking whether {:?} is in {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Boolean(i)), &TVal::Boolean(j)) => i == j, - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i == j, - (&CV::Value(Value::String(ref s)), &TVal::String(ref b)) => s.contains(b), - (&CV::Value(_), _) => false, - - (&CV::Values(ref v), &TVal::Integer(j)) => v.iter().any(|e| match e { - &Value::Integer(i) => i == j, - _ => false - }), - (&CV::Values(ref v), &TVal::String(ref b)) => v.iter().any(|e| match e { - &Value::String(ref s) => s == b, - _ => false - }), - (&CV::Values(_), _) => false, - } - }, - CO::OpEq => { - trace!("Checking whether {:?} == {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Boolean(i)), &TVal::Boolean(j)) => i == j, - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i == j, - (&CV::Value(Value::String(ref s)), &TVal::String(ref b)) => s == b, - (&CV::Value(_), _) => false, - (&CV::Values(_), _) => error_exit("Cannot check a header field for equality to multiple header fields!"), - } - }, - CO::OpNeq => { - trace!("Checking whether {:?} != {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Boolean(i)), &TVal::Boolean(j)) => i != j, - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i != j, - (&CV::Value(Value::String(ref s)), &TVal::String(ref b)) => s != b, - (&CV::Value(_), _) => false, - (&CV::Values(_), _) => error_exit("Cannot check a header field for inequality to multiple header fields!"), - } - }, - CO::OpGte => { - trace!("Checking whether {:?} >= {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i >= j, - (&CV::Value(_), _) => false, - (&CV::Values(_), _) => error_exit("Cannot check a header field for greater_than_equal to multiple header fields!"), - } - }, - CO::OpLte => { - trace!("Checking whether {:?} <= {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i <= j, - (&CV::Value(_), _) => false, - (&CV::Values(_), _) => error_exit("Cannot check a header field for lesser_than_equal to multiple header fields!"), - } - }, - CO::OpLt => { - trace!("Checking whether {:?} < {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i < j, - (&CV::Value(_), _) => false, - (&CV::Values(_), _) => error_exit("Cannot check a header field for lesser_than to multiple header fields!"), - } - }, - CO::OpGt => { - trace!("Checking whether {:?} > {:?}", self.1, val); - match (self.1, val) { - (&CV::Value(Value::Integer(i)), &TVal::Integer(j)) => i > j, - (&CV::Value(_), _) => false, - (&CV::Values(_), _) => { - error!("Cannot check a header field for greater_than to multiple header fields!"); - exit(1) - }, - } - }, - } - } - } - - impl ::filters::filter::Filter<Entry> for Filter { - fn filter(&self, entry: &Entry) -> bool { - use toml_query::read::TomlValueReadExt; - - let selector_str = self.selector.selector_str(); - trace!("Filtering {} at {}", entry.get_location(), selector_str); - - entry - .get_header() - .read(selector_str) - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .map(|value| { - let comp = Comparator(&self.compare_operator, &self.compare_value); - let val = match self.selector.function() { - None => { - ::filters::filter::Filter::filter(&comp, value) - } - Some(func) => { - match *func { - Function::Length => { - let val = match value { - &::toml::Value::Array(ref a) => a.len() as i64, - &::toml::Value::String(ref s) => s.len() as i64, - _ => 1 - }; - let val = ::toml::Value::Integer(val); - ::filters::filter::Filter::filter(&comp, &val) - }, - Function::Keys => { - let keys = match value { - &::toml::Value::Table(ref tab) => tab - .keys() - .cloned() - .map(::toml::Value::String) - .collect(), - _ => return false, - }; - let keys = ::toml::Value::Array(keys); - ::filters::filter::Filter::filter(&comp, &keys) - }, - Function::Values => { - let vals = match value { - &::toml::Value::Table(ref tab) => tab - .values() - .cloned() - .collect(), - _ => return false, - }; - let vals = ::toml::Value::Array(vals); - ::filters::filter::Filter::filter(&comp, &vals) - }, - } - } - }; - - match self.unary { - Some(Unary::Not) => !val, - _ => val - } - }) - .unwrap_or(false) - } - } - - impl ::filters::filter::Filter<Entry> for Query { - - fn filter(&self, entry: &Entry) -> bool { - trace!("Filtering = {}", entry.get_location()); - let mut res = self.filter.filter(entry); - trace!("First filter = {}", res); - - for &(ref operator, ref next) in self.next_filters.iter() { - match *operator { - Operator::Or => { - trace!("Operator = {} OR {:?}", res, next); - res = res || ::filters::filter::Filter::filter(next, entry); - }, - Operator::And => { - trace!("Operator = {} AND {:?}", res, next); - res = res && ::filters::filter::Filter::filter(next, entry); - }, - Operator::Xor => { - trace!("Operator = {} XOR {:?}", res, next); - let other = ::filters::filter::Filter::filter(next, entry); - res = (res && !other) || (!res && other); - }, - } - trace!("After applying next filter = {}", res); - } - - res - } - - } - - fn error_exit(s: &'static str) -> ! { - error!("{}", s); - exit(1) - } - - pub fn parse(s: &str) -> Query { - match parse_query(s.as_bytes()) { - ::nom::IResult::Done(_i, o) => o, - ::nom::IResult::Error(e) => { - error!("Error during parsing the query"); - error!("Error = {:?}", e); - ::std::process::exit(1) - }, - ::nom::IResult::Incomplete(needed) => { - error!("Error during parsing the query. Incomplete input."); - error!("Needed = {:?}", needed); - ::std::process::exit(1) - }, - } - } - - #[cfg(test)] - mod tests { - use super::*; - - fn setup_logging() { - let _ = ::env_logger::try_init(); - } - - #[test] - fn test_unary() { - assert_eq!(unary_operator(b"not").unwrap().1, Unary::Not); - } - - #[test] - fn test_compare_op() { - assert_eq!(compare_op(b"is" ).unwrap().1, CompareOp::OpIs ); - assert_eq!(compare_op(b"in" ).unwrap().1, CompareOp::OpIn ); - assert_eq!(compare_op(b"==" ).unwrap().1, CompareOp::OpEq ); - assert_eq!(compare_op(b"eq" ).unwrap().1, CompareOp::OpEq ); - assert_eq!(compare_op(b"!=" ).unwrap().1, CompareOp::OpNeq); - assert_eq!(compare_op(b"neq" ).unwrap().1, CompareOp::OpNeq); - assert_eq!(compare_op(b">=" ).unwrap().1, CompareOp::OpGte); - assert_eq!(compare_op(b"<=" ).unwrap().1, CompareOp::OpLte); - assert_eq!(compare_op(b"<" ).unwrap().1, CompareOp::OpLt ); - assert_eq!(compare_op(b">" ).unwrap().1, CompareOp::OpGt ); - } - - #[test] - fn test_operator() { - assert_eq!(operator(b"or").unwrap().1, Operator::Or ); - assert_eq!(operator(b"and").unwrap().1, Operator::And ); - assert_eq!(operator(b"xor").unwrap().1, Operator::Xor ); - } - - #[test] - fn test_function() { - assert_eq!(function(b"length").unwrap().1, Function::Length ); - assert_eq!(function(b"keys").unwrap().1, Function::Keys ); - assert_eq!(function(b"values").unwrap().1, Function::Values ); - } - - #[test] - fn test_integer() { - assert_eq!(integer(b"12").unwrap().1, 12); - assert_eq!(integer(b"11292").unwrap().1, 11292); - assert_eq!(integer(b"-12").unwrap().1, -12); - assert_eq!(integer(b"10101012").unwrap().1, 10101012); - } - - #[test] - fn test_string() { - assert_eq!(string(b"\"foo\"").unwrap().1, "foo"); - } - - #[test] - fn test_boolean() { - assert_eq!(boolean(b"false").unwrap().1, false); - assert_eq!(boolean(b"true").unwrap().1, true); - } - - #[test] - fn test_val() { - assert_eq!(val(b"false").unwrap().1, Value::Boolean(false)); - assert_eq!(val(b"true").unwrap().1, Value::Boolean(true)); - assert_eq!(val(b"12").unwrap().1, Value::Integer(12)); - assert_eq!(val(b"\"foobar\"").unwrap().1, Value::String(String::from("foobar"))); - } - - #[test] - fn test_list_of_val() { - setup_logging(); - { - let list = list_of_val(b"[]"); - debug!("list: {:?}", list); - let vals = list.unwrap().1; - assert_eq!(vals, vec![]); - } - - { - let list = list_of_val(b"[1]"); - debug!("list: {:?}", list); - let vals = list.unwrap().1; - assert_eq!(vals, vec![Value::Integer(1)]); - } - - { - let list = list_of_val(b"[12,13]"); - debug!("list: {:?}", list); - let vals = list.unwrap().1; - assert_eq!(vals, vec![Value::Integer(12), Value::Integer(13)]); - } - - { - let vals = list_of_val(b"[\"foobar\",\"bazbaz\"]").unwrap().1; - let expt = vec![Value::String(String::from("foobar")), - Value::String(String::from("bazbaz"))]; - assert_eq!(vals, expt) - } - - { - let vals = list_of_val(b"[\"1\", \"2\"]").unwrap().1; - let expt = vec![Value::String(String::from("1")), - Value::String(String::from("2"))]; - assert_eq!(vals, expt) - } - } - - #[test] - fn test_selector_str() { - assert_eq!(selector_str(b"foo.bar baz").unwrap().1, String::from("foo.bar")); - } - - #[test] - fn test_selector() { - assert_eq!(selector(b"foo.bar baz").unwrap().1, Selector::Direct(String::from("foo.bar"))); - - assert_eq!(function(b"length").unwrap().1, Function::Length); - - let exp = Selector::Function(Function::Length, String::from("foo.bar")); - assert_eq!(selector(b"length(foo.bar)").unwrap().1, exp); - } - - #[test] - fn test_filter_1() { - setup_logging(); - trace!("Setup worked"); - let text |