Merge branch 'add-bm' into rewrite

This commit is contained in:
Matthias Beyer 2015-12-28 18:02:46 +01:00
commit cf7078f6cf
5 changed files with 227 additions and 5 deletions

View file

@ -43,7 +43,7 @@ fn main() {
debug!("Runtime : {:?}", &rt); debug!("Runtime : {:?}", &rt);
if let Some(matches) = rt.config.cli_matches.subcommand_matches("bm") { if let Some(matches) = rt.config.cli_matches.subcommand_matches("bm") {
let res = BM::new(&rt).exec(matches.subcommand_matches("bm").unwrap()); let res = BM::new(&rt).exec(matches);
info!("BM exited with {}", res); info!("BM exited with {}", res);
} else { } else {
info!("No commandline call...") info!("No commandline call...")

36
src/module/bm/header.rs Normal file
View file

@ -0,0 +1,36 @@
use module::helpers::header as headerhelpers;
use storage::file::header::data::FileHeaderData as FHD;
use storage::file::header::spec::FileHeaderSpec as FHS;
pub fn get_spec() -> FHS {
FHS::Map {
keys: vec![
headerhelpers::tags::spec::url_key(),
headerhelpers::tags::spec::tags_key(),
]
}
}
pub fn build_header(url: String, tags: Vec<String>) -> FHD {
FHD::Map {
keys: vec![
FHD::Key {
name: String::from("URL"),
value: Box::new(FHD::Text(url.clone()))
},
FHD::Key {
name: String::from("TAGS"),
value: Box::new(headerhelpers::tags::data::build_tag_array(tags))
}
]
}
}
pub fn get_tags_from_header(header: &FHD) -> Vec<String> {
headerhelpers::tags::data::get_tags_from_header(header)
}
pub fn get_url_from_header(header: &FHD) -> Option<String> {
headerhelpers::data::get_url_from_header(header)
}

View file

@ -6,6 +6,14 @@ use clap::ArgMatches;
use runtime::Runtime; use runtime::Runtime;
use module::Module; use module::Module;
use storage::file::hash::FileHash;
use storage::file::id::FileID;
use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
mod header;
pub struct BM<'a> { pub struct BM<'a> {
rt: &'a Runtime<'a>, rt: &'a Runtime<'a>,
} }
@ -22,16 +30,185 @@ impl<'a> BM<'a> {
&self.rt &self.rt
} }
fn command_add(&self, matches: &ArgMatches) -> bool {
use self::header::build_header;
let parser = Parser::new(JsonHeaderParser::new(None));
let url = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present
let tags = matches.value_of("tags").and_then(|s| {
Some(s.split(",").map(String::from).collect())
}).unwrap_or(vec![]);
debug!("Building header with");
debug!(" url = '{:?}'", url);
debug!(" tags = '{:?}'", tags);
let header = build_header(url, tags);
let fileid = self.rt.store().new_file_with_header(self, header);
self.rt.store().load(&fileid).and_then(|file| {
info!("Created file in memory: {}", fileid);
Some(self.rt.store().persist(&parser, file))
}).unwrap_or(false)
}
fn command_list(&self, matches: &ArgMatches) -> bool {
use ui::file::{FilePrinter, TablePrinter};
use self::header::get_url_from_header;
use self::header::get_tags_from_header;
use std::ops::Deref;
let parser = Parser::new(JsonHeaderParser::new(None));
let files = self.rt.store().load_for_module(self, &parser);
let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());
printer.print_files_custom(files.into_iter(),
&|file| {
let fl = file.deref().borrow();
let hdr = fl.header();
let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
let tags = get_tags_from_header(hdr);
debug!("Custom printer field: url = '{:?}'", url);
debug!("Custom printer field: tags = '{:?}'", tags);
vec![url, tags.join(", ")]
}
);
true
}
fn command_remove(&self, matches: &ArgMatches) -> bool {
use std::process::exit;
let result =
if matches.is_present("id") {
debug!("Removing by ID (Hash)");
let hash = FileHash::from(matches.value_of("id").unwrap());
self.remove_by_hash(hash)
} else if matches.is_present("tags") {
debug!("Removing by tags");
let tags = matches.value_of("tags")
.unwrap()
.split(",")
.map(String::from)
.collect::<Vec<String>>();
self.remove_by_tags(tags)
} else if matches.is_present("match") {
debug!("Removing by match");
self.remove_by_match(String::from(matches.value_of("match").unwrap()))
} else {
error!("Unexpected error. Exiting");
exit(1);
false
};
if result {
info!("Removing succeeded");
} else {
info!("Removing failed");
}
return result;
}
fn remove_by_hash(&self, hash: FileHash) -> bool {
use std::ops::Deref;
debug!("Removing for hash = '{:?}'", hash);
let parser = Parser::new(JsonHeaderParser::new(None));
let file = self.rt.store().load_by_hash(self, &parser, hash);
debug!("file = {:?}", file);
file.map(|file| {
debug!("File loaded, can remove now: {:?}", file);
let f = file.deref().borrow();
self.rt.store().remove(f.id().clone())
}).unwrap_or(false)
}
fn remove_by_tags(&self, tags: Vec<String>) -> bool {
use std::fs::remove_file;
use std::ops::Deref;
use self::header::get_tags_from_header;
let parser = Parser::new(JsonHeaderParser::new(None));
self.rt
.store()
.load_for_module(self, &parser)
.iter()
.filter(|file| {
let f = file.deref().borrow();
get_tags_from_header(f.header()).iter().any(|tag| {
tags.iter().any(|remtag| remtag == tag)
})
}).map(|file| {
let f = file.deref().borrow();
self.rt.store().remove(f.id().clone())
}).all(|x| x)
}
fn remove_by_match(&self, matcher: String) -> bool {
use self::header::get_url_from_header;
use std::fs::remove_file;
use std::ops::Deref;
use std::process::exit;
use regex::Regex;
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);
let parser = Parser::new(JsonHeaderParser::new(None));
self.rt
.store()
.load_for_module(self, &parser)
.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)
}).map(|file| {
let f = file.deref().borrow();
self.rt.store().remove(f.id().clone())
}).all(|x| x)
}
} }
impl<'a> Module<'a> for BM<'a> { impl<'a> Module<'a> for BM<'a> {
fn exec(&self, matches: &ArgMatches) -> bool { fn exec(&self, matches: &ArgMatches) -> bool {
unimplemented!() match matches.subcommand_name() {
Some("add") => {
self.command_add(matches.subcommand_matches("add").unwrap())
},
Some("list") => {
self.command_list(matches.subcommand_matches("list").unwrap())
},
Some("remove") => {
self.command_remove(matches.subcommand_matches("remove").unwrap())
},
Some(_) | None => {
info!("No command given, doing nothing");
false
},
}
} }
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"bm" "bookmark"
} }
} }
@ -43,3 +220,4 @@ impl<'a> Debug for BM<'a> {
} }
} }

View file

@ -19,12 +19,20 @@ pub mod data {
} }
}).and_then(|urlkey| { }).and_then(|urlkey| {
match urlkey.deref().clone() { match urlkey.deref().clone() {
FHD::Key{name: _, value: ref v} => {
match v.deref().clone() {
FHD::Text(s) => Some(s), FHD::Text(s) => Some(s),
_ => { _ => {
warn!("Malformed Header Data: Expected Text, found non-Text"); warn!("Malformed Header Data: Expected Text, found non-Text");
None None
}, },
} }
}
_ => {
warn!("Malformed Header Data: Expected Text, found non-Text");
None
},
}
}) })
}, },
_ => { _ => {

View file

@ -20,7 +20,7 @@ pub mod data {
use std::ops::Deref; use std::ops::Deref;
use storage::file::header::data::FileHeaderData as FHD; use storage::file::header::data::FileHeaderData as FHD;
pub fn build_tag_array(tags: &Vec<String>) -> FHD { pub fn build_tag_array(tags: Vec<String>) -> FHD {
let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect(); let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect();
FHD::Array { values: Box::new(texttags) } FHD::Array { values: Box::new(texttags) }
} }