Merge branch 'bm' into master
This commit is contained in:
commit
80643c0c89
9 changed files with 462 additions and 37 deletions
71
etc/cli.yml
71
etc/cli.yml
|
@ -113,6 +113,77 @@ subcommands:
|
||||||
help: Sets the level of debugging information
|
help: Sets the level of debugging information
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
subcommands:
|
||||||
|
- add:
|
||||||
|
about: Add bookmark
|
||||||
|
version: 0.1
|
||||||
|
author: Matthias Beyer <mail@beyermatthias.de>
|
||||||
|
args:
|
||||||
|
- url:
|
||||||
|
short: u
|
||||||
|
long: url
|
||||||
|
help: Add a new URL as bookmark
|
||||||
|
required: true
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- tags:
|
||||||
|
short: t
|
||||||
|
long: tags
|
||||||
|
help: Add these tags to the URL
|
||||||
|
required: false
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- list:
|
||||||
|
about: List bookmarks
|
||||||
|
version: 0.1
|
||||||
|
author: Matthias Beyer <mail@beyermatthias.de>
|
||||||
|
args:
|
||||||
|
- match:
|
||||||
|
short: m
|
||||||
|
long: match
|
||||||
|
help: Match for regex
|
||||||
|
required: false
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- tags:
|
||||||
|
short: t
|
||||||
|
long: tags
|
||||||
|
help: Filter for these tags
|
||||||
|
required: false
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- remove:
|
||||||
|
about: Remove bookmark(s)
|
||||||
|
version: 0.1
|
||||||
|
author: Matthias Beyer <mail@beyermatthias.de>
|
||||||
|
args:
|
||||||
|
- id:
|
||||||
|
long: id
|
||||||
|
help: Delete Bookmark with ID
|
||||||
|
required: false
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- match:
|
||||||
|
short: m
|
||||||
|
long: match
|
||||||
|
help: Match for regex
|
||||||
|
required: false
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- tags:
|
||||||
|
short: t
|
||||||
|
long: tags
|
||||||
|
help: Filter for these tags
|
||||||
|
required: false
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
|
- check:
|
||||||
|
short: c
|
||||||
|
long: check
|
||||||
|
help: Ensure there are no references to this link
|
||||||
|
required: false
|
||||||
|
takes_value: false
|
||||||
|
|
||||||
- todo:
|
- todo:
|
||||||
about: Todo module
|
about: Todo module
|
||||||
version: 0.1
|
version: 0.1
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -4,14 +4,19 @@
|
||||||
#[macro_use] extern crate serde_json;
|
#[macro_use] extern crate serde_json;
|
||||||
#[macro_use] extern crate glob;
|
#[macro_use] extern crate glob;
|
||||||
#[macro_use] extern crate uuid;
|
#[macro_use] extern crate uuid;
|
||||||
|
#[macro_use] extern crate regex;
|
||||||
#[macro_use] extern crate prettytable;
|
#[macro_use] extern crate prettytable;
|
||||||
extern crate config;
|
extern crate config;
|
||||||
extern crate regex;
|
|
||||||
|
|
||||||
use cli::CliConfig;
|
use cli::CliConfig;
|
||||||
use configuration::Configuration;
|
use configuration::Configuration;
|
||||||
use runtime::{ImagLogger, Runtime};
|
use runtime::{ImagLogger, Runtime};
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
use module::Module;
|
||||||
|
use module::ModuleError;
|
||||||
|
use module::CommandEnv;
|
||||||
|
use module::bm::BMModule;
|
||||||
|
use storage::backend::StorageBackend;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod configuration;
|
mod configuration;
|
||||||
|
@ -20,6 +25,8 @@ mod module;
|
||||||
mod storage;
|
mod storage;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let yaml = load_yaml!("../etc/cli.yml");
|
let yaml = load_yaml!("../etc/cli.yml");
|
||||||
let app = App::from_yaml(yaml);
|
let app = App::from_yaml(yaml);
|
||||||
|
@ -36,5 +43,39 @@ fn main() {
|
||||||
|
|
||||||
debug!("Runtime : {:?}", &rt);
|
debug!("Runtime : {:?}", &rt);
|
||||||
|
|
||||||
|
let backend = StorageBackend::new(&rt).unwrap_or_else(|e| {
|
||||||
|
error!("Error: {}", e);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(matches) = rt.config.cli_matches.subcommand_matches("bm") {
|
||||||
|
let module = BMModule::new(&rt);
|
||||||
|
let commands = module.get_commands(&rt);
|
||||||
|
if let Some(command) = matches.subcommand_name() {
|
||||||
|
debug!("Subcommand: {}", command);
|
||||||
|
|
||||||
|
let cmdenv = CommandEnv {
|
||||||
|
rt: &rt,
|
||||||
|
bk: &backend,
|
||||||
|
matches: matches.subcommand_matches(command).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = match commands.get(command) {
|
||||||
|
Some(f) => f(&module, cmdenv),
|
||||||
|
None => Err(ModuleError::new("No subcommand found")),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Result of command: {:?}", result);
|
||||||
|
} else {
|
||||||
|
debug!("No subcommand");
|
||||||
|
}
|
||||||
|
|
||||||
|
module.shutdown(&rt);
|
||||||
|
} else {
|
||||||
|
// Err(ModuleError::mk("No commandline call"))
|
||||||
|
info!("No commandline call...")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
info!("Hello, world!");
|
info!("Hello, world!");
|
||||||
}
|
}
|
||||||
|
|
173
src/module/bm/commands.rs
Normal file
173
src/module/bm/commands.rs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
use runtime::Runtime;
|
||||||
|
use storage::backend::{StorageBackendError, StorageBackend};
|
||||||
|
|
||||||
|
use module::Module;
|
||||||
|
use module::ModuleError;
|
||||||
|
use module::CommandResult;
|
||||||
|
use module::CommandEnv;
|
||||||
|
|
||||||
|
use module::bm::header::build_header;
|
||||||
|
use module::bm::header::get_tags_from_header;
|
||||||
|
use storage::json::parser::JsonHeaderParser;
|
||||||
|
use storage::parser::{Parser, FileHeaderParser};
|
||||||
|
use storage::file::File;
|
||||||
|
use ui::file::{FilePrinter, TablePrinter};
|
||||||
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
|
use clap::ArgMatches;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
pub fn add_command(module: &Module, env: CommandEnv) -> CommandResult {
|
||||||
|
let url = env.matches.value_of("url").unwrap();
|
||||||
|
let tags = get_tags(env.rt, env.matches);
|
||||||
|
info!("Adding url '{}' with tags '{:?}'", url, tags);
|
||||||
|
|
||||||
|
let header = build_header(&String::from(url), &tags);
|
||||||
|
let file = File::new_with_header(module, header);
|
||||||
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
|
let putres = env.bk.put_file(file, &parser);
|
||||||
|
|
||||||
|
putres.map_err(|sberr| {
|
||||||
|
let mut err = ModuleError::new("Storage Backend Error");
|
||||||
|
err.caused_by = Some(Box::new(sberr));
|
||||||
|
err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_command(module: &Module, env: CommandEnv) -> CommandResult {
|
||||||
|
let printer = TablePrinter::new(env.rt.is_verbose(), env.rt.is_debugging());
|
||||||
|
let files = get_filtered_files_from_backend(module, &env);
|
||||||
|
|
||||||
|
debug!("Printing files now");
|
||||||
|
printer.print_files(files);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_command(module: &Module, env: CommandEnv) -> CommandResult {
|
||||||
|
let checked : bool = run_removal_checking(&env);
|
||||||
|
debug!("Checked mode: {}", checked);
|
||||||
|
if let Some(id) = get_id(env.rt, env.matches) {
|
||||||
|
debug!("Remove by id: {}", id);
|
||||||
|
|
||||||
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
|
let file = env.bk.get_file_by_id(module, &id, &parser).unwrap();
|
||||||
|
debug!("Remove file : {:?}", file);
|
||||||
|
|
||||||
|
if let Err(e) = env.bk.remove_file(module, file, checked) {
|
||||||
|
debug!("Remove failed");
|
||||||
|
let mut err = ModuleError::new("Removing file failed");
|
||||||
|
err.caused_by = Some(Box::new(e));
|
||||||
|
Err(err)
|
||||||
|
} else {
|
||||||
|
debug!("Remove worked");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug!("Remove more than one file");
|
||||||
|
|
||||||
|
let files = get_filtered_files_from_backend(module, &env);
|
||||||
|
let nfiles = files.len();
|
||||||
|
info!("Removing {} Files", nfiles);
|
||||||
|
|
||||||
|
let errs = files.map(|file| {
|
||||||
|
debug!("Remove file: {:?}", file);
|
||||||
|
env.bk.remove_file(module, file, checked)
|
||||||
|
})
|
||||||
|
.filter(|e| e.is_err())
|
||||||
|
.map(|e| {
|
||||||
|
let err = e.err().unwrap();
|
||||||
|
warn!("Error occured in Filesystem operation: {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.collect::<Vec<StorageBackendError>>();
|
||||||
|
|
||||||
|
let nerrs = errs.len();
|
||||||
|
|
||||||
|
if nerrs != 0 {
|
||||||
|
warn!("{} Errors occured while removing {} files", nerrs, nfiles);
|
||||||
|
let moderr = ModuleError::new("File removal failed");
|
||||||
|
|
||||||
|
// TODO : Collect StorageBackendErrors
|
||||||
|
|
||||||
|
Err(moderr)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Private helpers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn get_filtered_files_from_backend<'a>(module: &'a Module,
|
||||||
|
env: &CommandEnv) -> IntoIter<File<'a>>
|
||||||
|
{
|
||||||
|
let parser = Parser::new(JsonHeaderParser::new(None));
|
||||||
|
let tags = get_tags(env.rt, env.matches);
|
||||||
|
debug!("Tags: {:?}", tags);
|
||||||
|
env.bk.iter_files(module, &parser).and_then(|files| {
|
||||||
|
let f = files.filter(|file| {
|
||||||
|
if tags.len() != 0 {
|
||||||
|
debug!("Checking tags of: {:?}", file.id());
|
||||||
|
get_tags_from_header(&file.header()).iter()
|
||||||
|
.any(|t| tags.contains(t))
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}).filter(|file| {
|
||||||
|
debug!("Checking matches of: {:?}", file.id());
|
||||||
|
get_matcher(env.rt, env.matches)
|
||||||
|
.and_then(|r| Some(file.matches_with(&r)))
|
||||||
|
.unwrap_or(true)
|
||||||
|
}).collect::<Vec<File>>();
|
||||||
|
Some(f)
|
||||||
|
}).unwrap_or(Vec::<File>::new()).into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {
|
||||||
|
debug!("Fetching tags from commandline");
|
||||||
|
sub.value_of("tags").and_then(|tags|
|
||||||
|
Some(tags.split(",")
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.filter(|e|
|
||||||
|
if e.contains(" ") {
|
||||||
|
warn!("Tag contains spaces: '{}'", e);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}).collect()
|
||||||
|
)
|
||||||
|
).or(Some(vec![])).unwrap()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
|
||||||
|
debug!("Fetching matcher from commandline");
|
||||||
|
if let Some(s) = sub.value_of("match") {
|
||||||
|
if let Ok(r) = Regex::new(s) {
|
||||||
|
return Some(r)
|
||||||
|
} else {
|
||||||
|
error!("Regex error, continuing without regex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
|
||||||
|
debug!("Fetching id from commandline");
|
||||||
|
sub.value_of("id").and_then(|s| Some(String::from(s)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks whether the commandline call was set to run the removal "checked",
|
||||||
|
* so if another entry from the store refers to this ID, do not remove the file.
|
||||||
|
*/
|
||||||
|
fn run_removal_checking(env: &CommandEnv) -> bool {
|
||||||
|
env.matches.is_present("check")
|
||||||
|
}
|
79
src/module/bm/header.rs
Normal file
79
src/module/bm/header.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use storage::file::FileHeaderSpec as FHS;
|
||||||
|
use storage::file::FileHeaderData as FHD;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub fn get_spec() -> FHS {
|
||||||
|
FHS::Map { keys: vec![ url_key(), tags_key() ] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url_key() -> FHS {
|
||||||
|
FHS::Key { name: String::from("URL"), value_type: Box::new(FHS::Text) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tags_key() -> FHS {
|
||||||
|
FHS::Key { name: String::from("TAGS"), value_type: Box::new(text_array()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_array() -> FHS {
|
||||||
|
FHS::Array { allowed_types: vec![FHS::Text] }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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(build_tag_array(tags))
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_tag_array(tags: &Vec<String>) -> FHD {
|
||||||
|
let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect();
|
||||||
|
FHD::Array { values: Box::new(texttags) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tags_from_header(header: &FHD) -> Vec<String> {
|
||||||
|
let mut tags : Vec<String> = vec![];
|
||||||
|
|
||||||
|
fn match_array(a: &Box<FHD>) -> Vec<String> {
|
||||||
|
let mut tags : Vec<String> = vec![];
|
||||||
|
|
||||||
|
match a.deref() {
|
||||||
|
&FHD::Array{values: ref vs} => {
|
||||||
|
let values : Vec<FHD> = vs.deref().clone();
|
||||||
|
for value in values {
|
||||||
|
match value {
|
||||||
|
FHD::Text(t) => tags.push(t),
|
||||||
|
_ => warn!("Malformed Header Data: Expected Text, found non-Text"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => warn!("Malformed Header Data: Expected Array, found non-Array"),
|
||||||
|
}
|
||||||
|
|
||||||
|
tags
|
||||||
|
}
|
||||||
|
|
||||||
|
match header {
|
||||||
|
&FHD::Map{keys: ref ks} => {
|
||||||
|
let keys : Vec<FHD> = ks.clone();
|
||||||
|
for key in keys {
|
||||||
|
match key {
|
||||||
|
FHD::Key{name: _, value: ref v} => return match_array(v),
|
||||||
|
_ => warn!("Malformed Header Data: Expected Key, found non-Key"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => warn!("Malformed Header Data: Expected Map, found non-Map"),
|
||||||
|
}
|
||||||
|
|
||||||
|
tags
|
||||||
|
}
|
||||||
|
|
69
src/module/bm/mod.rs
Normal file
69
src/module/bm/mod.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use runtime::Runtime;
|
||||||
|
use module::Module;
|
||||||
|
use module::CommandMap;
|
||||||
|
use module::ModuleResult;
|
||||||
|
use module::ModuleError;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::result::Result;
|
||||||
|
use std::fmt::Result as FMTResult;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use clap::ArgMatches;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
mod header;
|
||||||
|
mod commands;
|
||||||
|
|
||||||
|
use self::header::build_header;
|
||||||
|
use storage::json::parser::JsonHeaderParser;
|
||||||
|
use storage::parser::FileHeaderParser;
|
||||||
|
|
||||||
|
use self::commands::*;
|
||||||
|
|
||||||
|
pub struct BMModule {
|
||||||
|
path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CALLNAMES : &'static [&'static str] = &[ "bm", "bookmark" ];
|
||||||
|
|
||||||
|
impl BMModule {
|
||||||
|
|
||||||
|
pub fn new(rt : &Runtime) -> BMModule {
|
||||||
|
BMModule {
|
||||||
|
path: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module for BMModule {
|
||||||
|
|
||||||
|
fn callnames(&self) -> &'static [&'static str] {
|
||||||
|
CALLNAMES
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &'static str{
|
||||||
|
"bookmark"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shutdown(&self, rt : &Runtime) -> ModuleResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_commands(&self, rt: &Runtime) -> CommandMap {
|
||||||
|
let mut hm = CommandMap::new();
|
||||||
|
hm.insert("add", add_command);
|
||||||
|
hm.insert("list", list_command);
|
||||||
|
hm.insert("remove", remove_command);
|
||||||
|
hm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for BMModule {
|
||||||
|
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> FMTResult {
|
||||||
|
write!(fmt, "[Module][BM]");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
use std::result::Result;
|
|
||||||
|
|
||||||
use super::ModuleError;
|
|
||||||
use storage::backend::{StorageBackend, StorageBackendError};
|
|
||||||
|
|
||||||
type CommandError = Result<ModuleError, StorageBackendError>;
|
|
||||||
type CommandResult = Result<(), Result<ModuleError, CommandError>>;
|
|
||||||
|
|
||||||
pub trait ExecutableCommand {
|
|
||||||
fn exec(StorageBackend) -> CommandResult;
|
|
||||||
}
|
|
|
@ -3,21 +3,28 @@ use std::error::Error;
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::fmt::Result as FMTResult;
|
use std::fmt::Result as FMTResult;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::path::Path;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use storage::backend::StorageBackend;
|
use clap::{App, ArgMatches};
|
||||||
use self::command::ExecutableCommand;
|
|
||||||
mod command;
|
use storage::backend::{StorageBackend, StorageBackendError};
|
||||||
|
|
||||||
|
pub mod bm;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ModuleError {
|
pub struct ModuleError {
|
||||||
desc: String,
|
desc: String,
|
||||||
|
caused_by: Option<Box<Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleError {
|
impl ModuleError {
|
||||||
fn mk(desc: &'static str) -> ModuleError {
|
pub fn new(desc: &'static str) -> ModuleError {
|
||||||
ModuleError {
|
ModuleError {
|
||||||
desc: desc.to_owned().to_string(),
|
desc: desc.to_owned().to_string(),
|
||||||
|
caused_by: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +36,7 @@ impl Error for ModuleError {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self) -> Option<&Error> {
|
fn cause(&self) -> Option<&Error> {
|
||||||
None
|
self.caused_by.as_ref().map(|e| &**e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,20 +47,23 @@ impl Display for ModuleError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CommandEnv<'a> {
|
||||||
|
pub rt: &'a Runtime<'a>,
|
||||||
|
pub bk: &'a StorageBackend,
|
||||||
|
pub matches: &'a ArgMatches<'a, 'a>,
|
||||||
|
}
|
||||||
|
|
||||||
pub type ModuleResult = Result<(), ModuleError>;
|
pub type ModuleResult = Result<(), ModuleError>;
|
||||||
|
pub type CommandResult = ModuleResult;
|
||||||
|
pub type CommandMap<'a> = HashMap<&'a str, fn(&Module, CommandEnv) -> CommandResult>;
|
||||||
|
|
||||||
pub trait Module {
|
pub trait Module : Debug {
|
||||||
|
|
||||||
fn new(rt : &Runtime) -> Self;
|
fn callnames(&self) -> &'static [&'static str];
|
||||||
fn callnames() -> &'static [&'static str];
|
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
fn execute(&self, rt : &Runtime) -> ModuleResult;
|
|
||||||
fn shutdown(&self, rt : &Runtime) -> ModuleResult;
|
fn shutdown(&self, rt : &Runtime) -> ModuleResult;
|
||||||
|
|
||||||
fn getCommandBuilder<T, F>() -> F
|
fn get_commands(&self, rt: &Runtime) -> CommandMap;
|
||||||
where F: FnOnce(StorageBackend) -> T,
|
|
||||||
T: ExecutableCommand;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,6 @@ impl StorageBackend {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
|
|
||||||
let path = rt.get_rtp() + m.name() + "/store";
|
|
||||||
// TODO: Don't use "/store" but value from configuration
|
|
||||||
debug!("Building StorageBackend for {}", path);
|
|
||||||
StorageBackend::new(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
|
fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
|
||||||
let list = glob(&self.prefix_of_files_for_module(m)[..]);
|
let list = glob(&self.prefix_of_files_for_module(m)[..]);
|
||||||
|
|
||||||
|
@ -272,7 +265,7 @@ impl StorageBackendError {
|
||||||
StorageBackendError {
|
StorageBackendError {
|
||||||
action: String::from(action),
|
action: String::from(action),
|
||||||
desc: String::from(desc),
|
desc: String::from(desc),
|
||||||
dataDump: data,
|
data_dump: data,
|
||||||
caused_by: None,
|
caused_by: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +284,7 @@ impl Error for StorageBackendError {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for StorageBackendError {
|
impl<'a> Display for StorageBackendError {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FMTResult {
|
fn fmt(&self, f: &mut Formatter) -> FMTResult {
|
||||||
write!(f, "StorageBackendError[{}]: {}",
|
write!(f, "StorageBackendError[{}]: {}",
|
||||||
self.action, self.desc)
|
self.action, self.desc)
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub enum FileHeaderSpec {
|
||||||
UInteger,
|
UInteger,
|
||||||
Float,
|
Float,
|
||||||
Text,
|
Text,
|
||||||
Key { name: &'static str, value_type: Box<FileHeaderSpec> },
|
Key { name: String, value_type: Box<FileHeaderSpec> },
|
||||||
Map { keys: Vec<FileHeaderSpec> },
|
Map { keys: Vec<FileHeaderSpec> },
|
||||||
Array { allowed_types: Vec<FileHeaderSpec> },
|
Array { allowed_types: Vec<FileHeaderSpec> },
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ pub enum FileHeaderData {
|
||||||
UInteger(u64),
|
UInteger(u64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Text(String),
|
Text(String),
|
||||||
Key { name: &'static str, value: Box<FileHeaderData> },
|
Key { name: String, value: Box<FileHeaderData> },
|
||||||
Map { keys: Vec<FileHeaderData> },
|
Map { keys: Vec<FileHeaderData> },
|
||||||
Array { values: Box<Vec<FileHeaderData>> },
|
Array { values: Box<Vec<FileHeaderData>> },
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue