Refactor: Provide generic cli-to-filter-function generator
The refactors functions from the BM module into more generic functions for all modules. The previous state was, that there were functions in the BM module which were used to load from the store and applying some filters. The new state is that there are functions to generate the filter functions which are then used to filter the loaded files from the store, so we can apply some more functionality on the filtered list.
This commit is contained in:
parent
09aa7d9ec3
commit
7bbe1bb6d0
3 changed files with 208 additions and 105 deletions
|
@ -18,6 +18,8 @@ use storage::file::File;
|
||||||
use storage::parser::FileHeaderParser;
|
use storage::parser::FileHeaderParser;
|
||||||
use storage::parser::Parser;
|
use storage::parser::Parser;
|
||||||
use storage::json::parser::JsonHeaderParser;
|
use storage::json::parser::JsonHeaderParser;
|
||||||
|
use module::helpers::cli::get_file_filter_by_cli;
|
||||||
|
use module::helpers::cli::CliFileFilter;
|
||||||
|
|
||||||
mod header;
|
mod header;
|
||||||
|
|
||||||
|
@ -136,15 +138,13 @@ impl<'a> BM<'a> {
|
||||||
fn command_remove(&self, matches: &ArgMatches) -> bool {
|
fn command_remove(&self, matches: &ArgMatches) -> bool {
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
let (filtered, files) = self.get_files(matches, "id", "match", "tags");
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
|
let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", None);
|
||||||
if !filtered {
|
let result = self.rt
|
||||||
error!("Unexpected error. Exiting");
|
.store()
|
||||||
exit(1);
|
.load_for_module(self, &parser)
|
||||||
}
|
|
||||||
|
|
||||||
let result = files
|
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|file| filter.filter_file(file))
|
||||||
.map(|file| {
|
.map(|file| {
|
||||||
debug!("File loaded, can remove now: {:?}", file);
|
debug!("File loaded, can remove now: {:?}", file);
|
||||||
let f = file.deref().borrow();
|
let f = file.deref().borrow();
|
||||||
|
@ -209,15 +209,18 @@ impl<'a> BM<'a> {
|
||||||
})
|
})
|
||||||
.unwrap_or(vec![]);
|
.unwrap_or(vec![]);
|
||||||
|
|
||||||
let (filter, files) = self.get_files(matches, "with_id", "with_match", "with_tags");
|
|
||||||
|
|
||||||
if !filter {
|
|
||||||
warn!("There were no filter applied when loading the files");
|
|
||||||
}
|
|
||||||
|
|
||||||
let parser = Parser::new(JsonHeaderParser::new(None));
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
files
|
let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser,
|
||||||
|
matches,
|
||||||
|
"with_id",
|
||||||
|
"with_match",
|
||||||
|
"with_tags",
|
||||||
|
None);
|
||||||
|
self.rt
|
||||||
|
.store()
|
||||||
|
.load_for_module(self, &parser)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.filter(|file| filter.filter_file(file))
|
||||||
.map(|file| {
|
.map(|file| {
|
||||||
debug!("Remove tags from file: {:?}", file);
|
debug!("Remove tags from file: {:?}", file);
|
||||||
|
|
||||||
|
@ -250,96 +253,6 @@ impl<'a> BM<'a> {
|
||||||
.all(|x| x)
|
.all(|x| x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to get files from the store filtered by the constraints passed via the
|
|
||||||
* CLI
|
|
||||||
*/
|
|
||||||
fn get_files(&self,
|
|
||||||
matches: &ArgMatches,
|
|
||||||
id_key: &'static str,
|
|
||||||
match_key: &'static str,
|
|
||||||
tag_key: &'static str)
|
|
||||||
-> (bool, Vec<Rc<RefCell<File>>>)
|
|
||||||
{
|
|
||||||
if matches.is_present(id_key) {
|
|
||||||
let hash = FileHash::from(matches.value_of(id_key).unwrap());
|
|
||||||
(true, self.get_files_by_id(hash))
|
|
||||||
} else if matches.is_present(match_key) {
|
|
||||||
let matcher = String::from(matches.value_of(match_key).unwrap());
|
|
||||||
(true, self.get_files_by_match(matcher))
|
|
||||||
} else if matches.is_present(tag_key) {
|
|
||||||
let tags = matches.value_of(tag_key)
|
|
||||||
.unwrap()
|
|
||||||
.split(",")
|
|
||||||
.map(String::from)
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
(true, self.get_files_by_tags(tags))
|
|
||||||
} else {
|
|
||||||
// get all files
|
|
||||||
let parser = Parser::new(JsonHeaderParser::new(None));
|
|
||||||
(false, self.rt.store().load_for_module(self, &parser))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get files from the store, filtere by ID
|
|
||||||
*/
|
|
||||||
fn get_files_by_id(&self, hash: FileHash) -> Vec<Rc<RefCell<File>>> {
|
|
||||||
let parser = Parser::new(JsonHeaderParser::new(None));
|
|
||||||
self.rt
|
|
||||||
.store()
|
|
||||||
.load_by_hash(self, &parser, hash)
|
|
||||||
.map(|f| vec![f])
|
|
||||||
.unwrap_or(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get files from the store, filtere by Regex
|
|
||||||
*/
|
|
||||||
fn get_files_by_match(&self, matcher: String) -> Vec<Rc<RefCell<File>>> {
|
|
||||||
let parser = Parser::new(JsonHeaderParser::new(None));
|
|
||||||
let re = Regex::new(&matcher[..]).unwrap_or_else(|e| {
|
|
||||||
error!("Cannot build regex out of '{}'", matcher);
|
|
||||||
error!("{}", e);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
debug!("Compiled '{}' to regex: '{:?}'", matcher, re);
|
|
||||||
|
|
||||||
self.rt
|
|
||||||
.store()
|
|
||||||
.load_for_module(self, &parser)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|file| {
|
|
||||||
let f = file.deref().borrow();
|
|
||||||
let url = get_url_from_header(f.header());
|
|
||||||
debug!("url = {:?}", url);
|
|
||||||
url.map(|u| {
|
|
||||||
debug!("Matching '{}' ~= '{}'", re.as_str(), u);
|
|
||||||
re.is_match(&u[..])
|
|
||||||
}).unwrap_or(false)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get files from the store, filtere by tags
|
|
||||||
*/
|
|
||||||
fn get_files_by_tags(&self, tags: Vec<String>) -> Vec<Rc<RefCell<File>>> {
|
|
||||||
let parser = Parser::new(JsonHeaderParser::new(None));
|
|
||||||
self.rt
|
|
||||||
.store()
|
|
||||||
.load_for_module(self, &parser)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|file| {
|
|
||||||
let f = file.deref().borrow();
|
|
||||||
get_tags_from_header(f.header()).iter().any(|tag| {
|
|
||||||
tags.iter().any(|remtag| remtag == tag)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
189
src/module/helpers/cli.rs
Normal file
189
src/module/helpers/cli.rs
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
|
use clap::ArgMatches;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use storage::file::File;
|
||||||
|
use storage::file::hash::FileHash;
|
||||||
|
use storage::file::header::data::FileHeaderData;
|
||||||
|
use storage::file::id::FileID;
|
||||||
|
use storage::json::parser::JsonHeaderParser;
|
||||||
|
use storage::parser::FileHeaderParser;
|
||||||
|
use storage::parser::Parser;
|
||||||
|
|
||||||
|
pub trait CliFileFilter {
|
||||||
|
|
||||||
|
fn filter_file(&self, &Rc<RefCell<File>>) -> bool;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CliFileFilterDefault {
|
||||||
|
default: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CliFileFilter for CliFileFilterDefault {
|
||||||
|
|
||||||
|
fn filter_file(&self, _: &Rc<RefCell<File>>) -> bool {
|
||||||
|
debug!("Filtering file with default value = {}", self.default);
|
||||||
|
return self.default
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CliFileFilterByHash {
|
||||||
|
hash: FileHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CliFileFilter for CliFileFilterByHash {
|
||||||
|
|
||||||
|
fn filter_file(&self, file: &Rc<RefCell<File>>) -> bool {
|
||||||
|
debug!("Filtering file with hash = {}", self.hash);
|
||||||
|
let f = file.deref().borrow();
|
||||||
|
f.id().get_id() == self.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CliFileFilterByDataRegex {
|
||||||
|
regex: Regex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CliFileFilter for CliFileFilterByDataRegex {
|
||||||
|
|
||||||
|
fn filter_file(&self, file: &Rc<RefCell<File>>) -> bool {
|
||||||
|
debug!("Filtering file with regex = {:?}", self.regex);
|
||||||
|
let f = file.deref().borrow();
|
||||||
|
self.regex.is_match(&f.data()[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CliFileFilterByHeaderRegex {
|
||||||
|
header_field_name: &'static str,
|
||||||
|
regex: Regex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CliFileFilter for CliFileFilterByHeaderRegex {
|
||||||
|
|
||||||
|
fn filter_file(&self, file: &Rc<RefCell<File>>) -> bool {
|
||||||
|
use module::helpers::header::data::get_named_text_from_header;
|
||||||
|
|
||||||
|
debug!("Filtering file (header field = {}) with regex = {:?}",
|
||||||
|
self.header_field_name,
|
||||||
|
self.regex);
|
||||||
|
|
||||||
|
let f = file.deref().borrow();
|
||||||
|
get_named_text_from_header(self.header_field_name, f.header())
|
||||||
|
.map(|headerfield| self.regex.is_match(&headerfield[..]))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CliFileFilterByTags {
|
||||||
|
tags: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CliFileFilter for CliFileFilterByTags {
|
||||||
|
|
||||||
|
fn filter_file(&self, file: &Rc<RefCell<File>>) -> bool {
|
||||||
|
use module::helpers::header::tags::data::get_tags_from_header;
|
||||||
|
|
||||||
|
debug!("Filtering file with tags = {:?}", self.tags);
|
||||||
|
|
||||||
|
let f = file.deref().borrow();
|
||||||
|
get_tags_from_header(f.header())
|
||||||
|
.iter()
|
||||||
|
.any(|tag| self.tags.iter().any(|remtag| remtag == tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to get files from the store filtered by the constraints passed via the
|
||||||
|
* CLI
|
||||||
|
*/
|
||||||
|
pub fn get_file_filter_by_cli<HP>(parser: &Parser<HP>,
|
||||||
|
matches: &ArgMatches,
|
||||||
|
id_key: &'static str,
|
||||||
|
match_key: &'static str,
|
||||||
|
tag_key: &'static str,
|
||||||
|
header_field_name: Option<&'static str>)
|
||||||
|
-> Box<CliFileFilter>
|
||||||
|
where HP: FileHeaderParser,
|
||||||
|
{
|
||||||
|
if matches.is_present(id_key) {
|
||||||
|
Box::new(CliFileFilterByHash { hash: FileHash::from(matches.value_of(id_key).unwrap()) })
|
||||||
|
} else if matches.is_present(match_key) {
|
||||||
|
let matcher = String::from(matches.value_of(match_key).unwrap());
|
||||||
|
header_field_name
|
||||||
|
.and_then(|header_field_name| {
|
||||||
|
Some(get_files_by_header_field_match_filter(parser,
|
||||||
|
&matcher,
|
||||||
|
header_field_name))
|
||||||
|
})
|
||||||
|
.unwrap_or(get_file_by_match_filter(parser, &matcher))
|
||||||
|
} else if matches.is_present(tag_key) {
|
||||||
|
let tags = matches.value_of(tag_key)
|
||||||
|
.unwrap()
|
||||||
|
.split(",")
|
||||||
|
.map(String::from)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
get_file_by_tags_filter(tags)
|
||||||
|
} else {
|
||||||
|
Box::new(CliFileFilterDefault { default: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get files from the store, filtere by Regex
|
||||||
|
*/
|
||||||
|
fn get_file_by_match_filter<HP>(parser: &Parser<HP>, matcher: &String)
|
||||||
|
-> Box<CliFileFilter>
|
||||||
|
where HP: FileHeaderParser
|
||||||
|
{
|
||||||
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
|
let re = Regex::new(&matcher[..]).unwrap_or_else(|e| {
|
||||||
|
error!("Cannot build regex out of '{}'", matcher);
|
||||||
|
error!("{}", e);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
debug!("Compiled '{}' to regex: '{:?}'", matcher, re);
|
||||||
|
|
||||||
|
Box::new(CliFileFilterByDataRegex { regex: re })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_files_by_header_field_match_filter<HP>(parser: &Parser<HP>,
|
||||||
|
matcher: &String,
|
||||||
|
header_field_name: &'static str)
|
||||||
|
-> Box<CliFileFilter>
|
||||||
|
where HP: FileHeaderParser,
|
||||||
|
{
|
||||||
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
|
let re = Regex::new(&matcher[..]).unwrap_or_else(|e| {
|
||||||
|
error!("Cannot build regex out of '{}'", matcher);
|
||||||
|
error!("{}", e);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
debug!("Compiled '{}' to regex: '{:?}'", matcher, re);
|
||||||
|
|
||||||
|
Box::new(CliFileFilterByHeaderRegex {
|
||||||
|
header_field_name: header_field_name,
|
||||||
|
regex: re
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get files from the store, filtere by tags
|
||||||
|
*/
|
||||||
|
fn get_file_by_tags_filter(tags: Vec<String>)
|
||||||
|
-> Box<CliFileFilter>
|
||||||
|
{
|
||||||
|
Box::new(CliFileFilterByTags { tags: tags })
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Utility helpers for modules
|
* Utility helpers for modules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
pub mod cli;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue