Merge branch 'add-bm' into rewrite
This commit is contained in:
commit
cf7078f6cf
5 changed files with 227 additions and 5 deletions
|
@ -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
36
src/module/bm/header.rs
Normal 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)
|
||||||
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
},
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -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) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue