diff --git a/etc/cli.yml b/etc/cli.yml index 70c05007..4a6590d2 100644 --- a/etc/cli.yml +++ b/etc/cli.yml @@ -34,87 +34,26 @@ subcommands: about: Calendar module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false - cont: about: Contact module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false - mail: about: Mail module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false - wiki: about: Wiki module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false - bm: about: Bookmark module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false - subcommands: - add: about: Add bookmark @@ -190,33 +129,9 @@ subcommands: about: Todo module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false - news: about: News module version: 0.1 author: Matthias Beyer - args: - - verbose: - short: v - long: verbose - help: Enable verbosity - required: false - - - debug: - short: d - long: debug - help: Sets the level of debugging information - required: false diff --git a/src/module/bm/commands.rs b/src/module/bm/commands.rs index 87ba320f..2d6f8bad 100644 --- a/src/module/bm/commands.rs +++ b/src/module/bm/commands.rs @@ -14,6 +14,7 @@ use ui::file::{FilePrinter, TablePrinter}; pub fn add_command(module: &Module, env: CommandEnv) -> CommandResult { use url::Url; + use module::helpers::utils::cli::get_tags; let url = env.matches.value_of("url").unwrap(); @@ -123,6 +124,8 @@ fn get_filtered_files_from_backend<'a>(module: &'a Module, env: &CommandEnv) -> Result>, ModuleError> { + use module::helpers::utils::cli::get_tags; + fn check_tags(tags: &Vec, file: &File) -> bool { if tags.len() != 0 { debug!("Checking tags of: {:?}", file.id()); @@ -159,28 +162,6 @@ fn get_filtered_files_from_backend<'a>(module: &'a Module, }) } -fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec { - - fn reject_if_with_spaces(e: &String) -> bool { - if e.contains(" ") { - warn!("Tag contains spaces: '{}'", e); - false - } else { - true - } - } - - debug!("Fetching tags from commandline"); - sub.value_of("tags").and_then(|tags| { - Some(tags.split(",") - .into_iter() - .map(|s| s.to_string()) - .filter(|e| reject_if_with_spaces(e)) - .collect() - ) - }).or(Some(vec![])).unwrap() -} - fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option { debug!("Fetching matcher from commandline"); if let Some(s) = sub.value_of("match") { diff --git a/src/module/bm/header.rs b/src/module/bm/header.rs index c25199aa..3cb4f75a 100644 --- a/src/module/bm/header.rs +++ b/src/module/bm/header.rs @@ -1,6 +1,6 @@ use module::helpers::header as headerhelpers; -use storage::file::FileHeaderData as FHD; -use storage::file::FileHeaderSpec as FHS; +use storage::file::header::data::FileHeaderData as FHD; +use storage::file::header::spec::FileHeaderSpec as FHS; pub fn get_spec() -> FHS { FHS::Map { diff --git a/src/module/helpers/header/tags.rs b/src/module/helpers/header/tags.rs index f9c22c33..2ad2e61b 100644 --- a/src/module/helpers/header/tags.rs +++ b/src/module/helpers/header/tags.rs @@ -3,25 +3,22 @@ */ pub mod spec { - use storage::file::FileHeaderSpec as FHS; + use storage::file::header::spec::FileHeaderSpec as FHS; + use module::helpers::spec::{named_text, named_text_array}; pub fn url_key() -> FHS { - FHS::Key { name: String::from("URL"), value_type: Box::new(FHS::Text) } + named_text("URL") } pub fn tags_key() -> FHS { - FHS::Key { name: String::from("TAGS"), value_type: Box::new(text_array()) } - } - - pub fn text_array() -> FHS { - FHS::Array { allowed_types: vec![FHS::Text] } + named_text_array("TAGS") } } pub mod data { use std::ops::Deref; - use storage::file::FileHeaderData as FHD; + use storage::file::header::data::FileHeaderData as FHD; pub fn build_tag_array(tags: &Vec) -> FHD { let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect(); diff --git a/src/module/helpers/mod.rs b/src/module/helpers/mod.rs index f505d688..8b501b4a 100644 --- a/src/module/helpers/mod.rs +++ b/src/module/helpers/mod.rs @@ -1 +1,19 @@ pub mod header; +pub mod utils; + +pub mod spec { + use storage::file::header::spec::FileHeaderSpec as FHS; + + pub fn named_text(name: &str) -> FHS { + FHS::Key { name: String::from(name), value_type: Box::new(FHS::Text) } + } + + pub fn named_text_array(name: &str) -> FHS { + FHS::Key { name: String::from(name), value_type: Box::new(text_array()) } + } + + pub fn text_array() -> FHS { + FHS::Array { allowed_types: vec![FHS::Text] } + } + +} diff --git a/src/module/helpers/utils.rs b/src/module/helpers/utils.rs new file mode 100644 index 00000000..9589aa2a --- /dev/null +++ b/src/module/helpers/utils.rs @@ -0,0 +1,29 @@ +pub mod cli { + use clap::ArgMatches; + use regex::Regex; + + use runtime::Runtime; + + pub fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec { + + fn reject_if_with_spaces(e: &String) -> bool { + if e.contains(" ") { + warn!("Tag contains spaces: '{}'", e); + false + } else { + true + } + } + + debug!("Fetching tags from commandline"); + sub.value_of("tags").and_then(|tags| { + Some(tags.split(",") + .into_iter() + .map(|s| s.to_string()) + .filter(|e| reject_if_with_spaces(e)) + .collect() + ) + }).or(Some(vec![])).unwrap() + } + +} diff --git a/src/storage/file.rs b/src/storage/file.rs deleted file mode 100644 index 7a14bb5d..00000000 --- a/src/storage/file.rs +++ /dev/null @@ -1,367 +0,0 @@ -use std::error::Error; -use std::fmt::{Debug, Display, Formatter}; -use std::fmt; - -use regex::Regex; - -use module::Module; -use storage::file_id::*; -use super::parser::{FileHeaderParser, Parser, ParserError}; - -#[derive(Debug)] -#[derive(Clone)] -pub enum FileHeaderSpec { - Null, - Bool, - Integer, - UInteger, - Float, - Text, - Key { name: String, value_type: Box }, - Map { keys: Vec }, - Array { allowed_types: Vec }, -} - -#[derive(Debug)] -#[derive(Clone)] -pub enum FileHeaderData { - Null, - Bool(bool), - Integer(i64), - UInteger(u64), - Float(f64), - Text(String), - Key { name: String, value: Box }, - Map { keys: Vec }, - Array { values: Box> }, -} - -impl Display for FileHeaderSpec { - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - match self { - &FileHeaderSpec::Null => write!(fmt, "NULL"), - &FileHeaderSpec::Bool => write!(fmt, "Bool"), - &FileHeaderSpec::Integer => write!(fmt, "Integer"), - &FileHeaderSpec::UInteger => write!(fmt, "UInteger"), - &FileHeaderSpec::Float => write!(fmt, "Float"), - &FileHeaderSpec::Text => write!(fmt, "Text"), - &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => { - write!(fmt, "Key({:?}) -> {:?}", n, vt) - } - &FileHeaderSpec::Map{keys: ref ks} => { - write!(fmt, "Map -> {:?}", ks) - } - &FileHeaderSpec::Array{allowed_types: ref at} => { - write!(fmt, "Array({:?})", at) - } - } - } - -} - -impl FileHeaderData { - - pub fn matches_with(&self, r: &Regex) -> bool { - match self { - &FileHeaderData::Text(ref t) => r.is_match(&t[..]), - &FileHeaderData::Key{name: ref n, value: ref val} => { - r.is_match(n) || val.matches_with(r) - }, - - &FileHeaderData::Map{keys: ref dks} => { - dks.iter().any(|x| x.matches_with(r)) - }, - - &FileHeaderData::Array{values: ref vs} => { - vs.iter().any(|x| x.matches_with(r)) - } - - _ => false, - } - } -} - -pub struct MatchError<'a> { - summary: String, - expected: &'a FileHeaderSpec, - found: &'a FileHeaderData -} - -impl<'a> MatchError<'a> { - - pub fn new(s: String, - ex: &'a FileHeaderSpec, - found: &'a FileHeaderData) -> MatchError<'a> { - MatchError { - summary: s, - expected: ex, - found: found, - } - } - - pub fn format(&self) -> String { - format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n", - self.summary, self.expected, self.found) - } -} - -impl<'a> Error for MatchError<'a> { - - fn description(&self) -> &str { - &self.summary[..] - } - - fn cause(&self) -> Option<&Error> { - None - } - -} - -impl<'a> Debug for MatchError<'a> { - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "{}", self.format()); - Ok(()) - } - -} - -impl<'a> Display for MatchError<'a> { - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "{}", self.format()); - Ok(()) - } - -} - -pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData) - -> Option> -{ - debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data); - match (spec, data) { - (&FileHeaderSpec::Null, &FileHeaderData::Null) => { } - (&FileHeaderSpec::Bool, &FileHeaderData::Bool(_)) => { } - (&FileHeaderSpec::Integer, &FileHeaderData::Integer(_)) => { } - (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_)) => { } - (&FileHeaderSpec::Float, &FileHeaderData::Float(_)) => { } - (&FileHeaderSpec::Text, &FileHeaderData::Text(_)) => { } - - ( - &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype}, - &FileHeaderData::Key{name: ref n, value: ref val} - ) => { - debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'", - kname, n, - vtype, val); - if kname != n { - debug!("Keys not matching"); - unimplemented!(); - } - return match_header_spec(&*vtype, &*val); - } - - ( - &FileHeaderSpec::Map{keys: ref sks}, - &FileHeaderData::Map{keys: ref dks} - ) => { - debug!("Matching Map: '{:?}' == '{:?}'", sks, dks); - - for (s, d) in sks.iter().zip(dks.iter()) { - let res = match_header_spec(s, d); - if res.is_some() { - return res; - } - } - } - - ( - &FileHeaderSpec::Array{allowed_types: ref vtypes}, - &FileHeaderData::Array{values: ref vs} - ) => { - debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs); - for (t, v) in vtypes.iter().zip(vs.iter()) { - let res = match_header_spec(t, v); - if res.is_some() { - return res; - } - } - } - - (k, v) => { - return Some(MatchError::new(String::from("Expected type does not match found type"), - k, v - )) - } - } - None -} - -/* - * Internal abstract view on a file. Does not exist on the FS and is just kept - * internally until it is written to disk. - */ -pub struct File<'a> { - owning_module : &'a Module, - header : FileHeaderData, - data : String, - id : FileID, -} - -impl<'a> File<'a> { - - pub fn new(module: &'a Module) -> File<'a> { - let f = File { - owning_module: module, - header: FileHeaderData::Null, - data: String::from(""), - id: File::get_new_file_id(), - }; - debug!("Create new File object: {:?}", f); - f - } - - pub fn from_parser_result(module: &Module, id: FileID, header: FileHeaderData, data: String) -> File { - let f = File { - owning_module: module, - header: header, - data: data, - id: id, - }; - debug!("Create new File object from parser result: {:?}", f); - f - } - - pub fn new_with_header(module: &Module, h: FileHeaderData) -> File { - let f = File { - owning_module: module, - header: h, - data: String::from(""), - id: File::get_new_file_id(), - }; - debug!("Create new File object with header: {:?}", f); - f - } - - pub fn new_with_data(module: &Module, d: String) -> File { - let f = File { - owning_module: module, - header: FileHeaderData::Null, - data: d, - id: File::get_new_file_id(), - }; - debug!("Create new File object with data: {:?}", f); - f - } - - pub fn new_with_content(module: &Module, h: FileHeaderData, d: String) -> File { - let f = File { - owning_module: module, - header: h, - data: d, - id: File::get_new_file_id(), - }; - debug!("Create new File object with content: {:?}", f); - f - } - - pub fn header(&self) -> FileHeaderData { - self.header.clone() - } - - pub fn data(&self) -> String { - self.data.clone() - } - - pub fn contents(&self) -> (FileHeaderData, String) { - (self.header(), self.data()) - } - - pub fn id(&self) -> FileID { - self.id.clone() - } - - pub fn owner(&self) -> &Module { - self.owning_module - } - - pub fn matches_with(&self, r: &Regex) -> bool { - r.is_match(&self.data[..]) || self.header.matches_with(r) - } - - fn get_new_file_id() -> FileID { - use uuid::Uuid; - FileID::new(FileIDType::UUID, Uuid::new_v4().to_hyphenated_string()) - } -} - -impl<'a> Display for File<'a> { - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, -"[File] Owner : '{:?}' - FileID: '{:?}' - Header: '{:?}' - Data : '{:?}'", - self.owning_module, - self.header, - self.data, - self.id); - Ok(()) - } - -} - -impl<'a> Debug for File<'a> { - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, -"[File] Owner : '{:?}' - FileID: '{:?}' - Header: '{:?}' - Data : '{:?}'", - self.owning_module, - self.header, - self.data, - self.id); - Ok(()) - } - -} - -#[cfg(test)] -mod test { - // we use the JSON parser here, so we can generate FileHeaderData - use storage::json::parser::JsonHeaderParser; - use super::match_header_spec; - use storage::parser::{FileHeaderParser, ParserError}; - use storage::file::FileHeaderData as FHD; - use storage::file::FileHeaderSpec as FHS; - - #[test] - fn test_spec_matching() { - let text = String::from("{\"a\": 1, \"b\": -2}"); - let spec = FHS::Map { - keys: vec![ - FHS::Key { - name: String::from("a"), - value_type: Box::new(FHS::UInteger) - }, - FHS::Key { - name: String::from("b"), - value_type: Box::new(FHS::Integer) - } - ] - }; - - let parser = JsonHeaderParser::new(Some(spec.clone())); - let datares = parser.read(Some(text.clone())); - assert!(datares.is_ok(), "Text could not be parsed: '{}'", text); - let data = datares.unwrap(); - - let matchres = match_header_spec(&spec, &data); - assert!(matchres.is_none(), "Matching returns error: {:?}", matchres); - } -} - diff --git a/src/storage/file/header/data.rs b/src/storage/file/header/data.rs new file mode 100644 index 00000000..f94a4b26 --- /dev/null +++ b/src/storage/file/header/data.rs @@ -0,0 +1,37 @@ +use regex::Regex; + +#[derive(Debug)] +#[derive(Clone)] +pub enum FileHeaderData { + Null, + Bool(bool), + Integer(i64), + UInteger(u64), + Float(f64), + Text(String), + Key { name: String, value: Box }, + Map { keys: Vec }, + Array { values: Box> }, +} + +impl FileHeaderData { + + pub fn matches_with(&self, r: &Regex) -> bool { + match self { + &FileHeaderData::Text(ref t) => r.is_match(&t[..]), + &FileHeaderData::Key{name: ref n, value: ref val} => { + r.is_match(n) || val.matches_with(r) + }, + + &FileHeaderData::Map{keys: ref dks} => { + dks.iter().any(|x| x.matches_with(r)) + }, + + &FileHeaderData::Array{values: ref vs} => { + vs.iter().any(|x| x.matches_with(r)) + } + + _ => false, + } + } +} diff --git a/src/storage/file/header/mod.rs b/src/storage/file/header/mod.rs new file mode 100644 index 00000000..8725d40d --- /dev/null +++ b/src/storage/file/header/mod.rs @@ -0,0 +1,126 @@ +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; + +pub mod spec; +pub mod data; + +use self::data::*; +use self::spec::*; + +pub struct MatchError<'a> { + summary: String, + expected: &'a FileHeaderSpec, + found: &'a FileHeaderData +} + +impl<'a> MatchError<'a> { + + pub fn new(s: String, + ex: &'a FileHeaderSpec, + found: &'a FileHeaderData) -> MatchError<'a> { + MatchError { + summary: s, + expected: ex, + found: found, + } + } + + pub fn format(&self) -> String { + format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n", + self.summary, self.expected, self.found) + } +} + +impl<'a> Error for MatchError<'a> { + + fn description(&self) -> &str { + &self.summary[..] + } + + fn cause(&self) -> Option<&Error> { + None + } + +} + +impl<'a> Debug for MatchError<'a> { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}", self.format()); + Ok(()) + } + +} + +impl<'a> Display for MatchError<'a> { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}", self.format()); + Ok(()) + } + +} + +pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData) + -> Option> +{ + debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data); + match (spec, data) { + (&FileHeaderSpec::Null, &FileHeaderData::Null) => { } + (&FileHeaderSpec::Bool, &FileHeaderData::Bool(_)) => { } + (&FileHeaderSpec::Integer, &FileHeaderData::Integer(_)) => { } + (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_)) => { } + (&FileHeaderSpec::Float, &FileHeaderData::Float(_)) => { } + (&FileHeaderSpec::Text, &FileHeaderData::Text(_)) => { } + + ( + &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype}, + &FileHeaderData::Key{name: ref n, value: ref val} + ) => { + debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'", + kname, n, + vtype, val); + if kname != n { + debug!("Keys not matching"); + unimplemented!(); + } + return match_header_spec(&*vtype, &*val); + } + + ( + &FileHeaderSpec::Map{keys: ref sks}, + &FileHeaderData::Map{keys: ref dks} + ) => { + debug!("Matching Map: '{:?}' == '{:?}'", sks, dks); + + for (s, d) in sks.iter().zip(dks.iter()) { + let res = match_header_spec(s, d); + if res.is_some() { + return res; + } + } + } + + ( + &FileHeaderSpec::Array{allowed_types: ref vtypes}, + &FileHeaderData::Array{values: ref vs} + ) => { + debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs); + for (t, v) in vtypes.iter().zip(vs.iter()) { + let res = match_header_spec(t, v); + if res.is_some() { + return res; + } + } + } + + (k, v) => { + return Some(MatchError::new(String::from("Expected type does not match found type"), + k, v + )) + } + } + None +} + diff --git a/src/storage/file/header/spec.rs b/src/storage/file/header/spec.rs new file mode 100644 index 00000000..bcec162e --- /dev/null +++ b/src/storage/file/header/spec.rs @@ -0,0 +1,41 @@ +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; + +#[derive(Debug)] +#[derive(Clone)] +pub enum FileHeaderSpec { + Null, + Bool, + Integer, + UInteger, + Float, + Text, + Key { name: String, value_type: Box }, + Map { keys: Vec }, + Array { allowed_types: Vec }, +} + +impl Display for FileHeaderSpec { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + match self { + &FileHeaderSpec::Null => write!(fmt, "NULL"), + &FileHeaderSpec::Bool => write!(fmt, "Bool"), + &FileHeaderSpec::Integer => write!(fmt, "Integer"), + &FileHeaderSpec::UInteger => write!(fmt, "UInteger"), + &FileHeaderSpec::Float => write!(fmt, "Float"), + &FileHeaderSpec::Text => write!(fmt, "Text"), + &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => { + write!(fmt, "Key({:?}) -> {:?}", n, vt) + } + &FileHeaderSpec::Map{keys: ref ks} => { + write!(fmt, "Map -> {:?}", ks) + } + &FileHeaderSpec::Array{allowed_types: ref at} => { + write!(fmt, "Array({:?})", at) + } + } + } + +} + diff --git a/src/storage/file_id.rs b/src/storage/file/id.rs similarity index 100% rename from src/storage/file_id.rs rename to src/storage/file/id.rs diff --git a/src/storage/file/mod.rs b/src/storage/file/mod.rs new file mode 100644 index 00000000..baa40002 --- /dev/null +++ b/src/storage/file/mod.rs @@ -0,0 +1,183 @@ +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; + +use regex::Regex; + +pub mod id; +pub mod header; + +use module::Module; +use storage::file::id::*; +use super::parser::{FileHeaderParser, Parser, ParserError}; + +use self::header::spec::*; +use self::header::data::*; + +/* + * Internal abstract view on a file. Does not exist on the FS and is just kept + * internally until it is written to disk. + */ +pub struct File<'a> { + owning_module : &'a Module, + header : FileHeaderData, + data : String, + id : FileID, +} + +impl<'a> File<'a> { + + pub fn new(module: &'a Module) -> File<'a> { + let f = File { + owning_module: module, + header: FileHeaderData::Null, + data: String::from(""), + id: File::get_new_file_id(), + }; + debug!("Create new File object: {:?}", f); + f + } + + pub fn from_parser_result(module: &Module, id: FileID, header: FileHeaderData, data: String) -> File { + let f = File { + owning_module: module, + header: header, + data: data, + id: id, + }; + debug!("Create new File object from parser result: {:?}", f); + f + } + + pub fn new_with_header(module: &Module, h: FileHeaderData) -> File { + let f = File { + owning_module: module, + header: h, + data: String::from(""), + id: File::get_new_file_id(), + }; + debug!("Create new File object with header: {:?}", f); + f + } + + pub fn new_with_data(module: &Module, d: String) -> File { + let f = File { + owning_module: module, + header: FileHeaderData::Null, + data: d, + id: File::get_new_file_id(), + }; + debug!("Create new File object with data: {:?}", f); + f + } + + pub fn new_with_content(module: &Module, h: FileHeaderData, d: String) -> File { + let f = File { + owning_module: module, + header: h, + data: d, + id: File::get_new_file_id(), + }; + debug!("Create new File object with content: {:?}", f); + f + } + + pub fn header(&self) -> FileHeaderData { + self.header.clone() + } + + pub fn data(&self) -> String { + self.data.clone() + } + + pub fn contents(&self) -> (FileHeaderData, String) { + (self.header(), self.data()) + } + + pub fn id(&self) -> FileID { + self.id.clone() + } + + pub fn owner(&self) -> &Module { + self.owning_module + } + + pub fn matches_with(&self, r: &Regex) -> bool { + r.is_match(&self.data[..]) || self.header.matches_with(r) + } + + fn get_new_file_id() -> FileID { + use uuid::Uuid; + FileID::new(FileIDType::UUID, Uuid::new_v4().to_hyphenated_string()) + } +} + +impl<'a> Display for File<'a> { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, +"[File] Owner : '{:?}' + FileID: '{:?}' + Header: '{:?}' + Data : '{:?}'", + self.owning_module, + self.header, + self.data, + self.id); + Ok(()) + } + +} + +impl<'a> Debug for File<'a> { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, +"[File] Owner : '{:?}' + FileID: '{:?}' + Header: '{:?}' + Data : '{:?}'", + self.owning_module, + self.header, + self.data, + self.id); + Ok(()) + } + +} + +#[cfg(test)] +mod test { + // we use the JSON parser here, so we can generate FileHeaderData + use storage::json::parser::JsonHeaderParser; + use super::match_header_spec; + use storage::parser::{FileHeaderParser, ParserError}; + use storage::file::FileHeaderData as FHD; + use storage::file::FileHeaderSpec as FHS; + + #[test] + fn test_spec_matching() { + let text = String::from("{\"a\": 1, \"b\": -2}"); + let spec = FHS::Map { + keys: vec![ + FHS::Key { + name: String::from("a"), + value_type: Box::new(FHS::UInteger) + }, + FHS::Key { + name: String::from("b"), + value_type: Box::new(FHS::Integer) + } + ] + }; + + let parser = JsonHeaderParser::new(Some(spec.clone())); + let datares = parser.read(Some(text.clone())); + assert!(datares.is_ok(), "Text could not be parsed: '{}'", text); + let data = datares.unwrap(); + + let matchres = match_header_spec(&spec, &data); + assert!(matchres.is_none(), "Matching returns error: {:?}", matchres); + } +} + diff --git a/src/storage/json/parser.rs b/src/storage/json/parser.rs index 39b6ad58..c752e20a 100644 --- a/src/storage/json/parser.rs +++ b/src/storage/json/parser.rs @@ -8,7 +8,8 @@ use serde::ser::Serialize; use serde::ser::Serializer as Ser; use storage::parser::{FileHeaderParser, ParserError}; -use storage::file::{FileHeaderSpec, FileHeaderData}; +use storage::file::header::spec::FileHeaderSpec; +use storage::file::header::data::FileHeaderData; pub struct JsonHeaderParser { spec: Option, diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 29bdda3a..96fe6968 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -8,9 +8,7 @@ use std::path::Path; use std::vec::{Vec, IntoIter}; pub mod file; -pub mod file_id; pub mod parser; -pub mod backend; pub mod json; use glob::glob; @@ -19,7 +17,7 @@ use glob::Paths; use module::Module; use runtime::Runtime; use storage::file::File; -use storage::file_id::*; +use storage::file::id::*; use storage::parser::{FileHeaderParser, Parser}; pub type BackendOperationResult = Result; diff --git a/src/storage/parser.rs b/src/storage/parser.rs index 0f30f04b..c627e56a 100644 --- a/src/storage/parser.rs +++ b/src/storage/parser.rs @@ -4,7 +4,7 @@ use std::fmt; use regex::Regex; -use super::file::FileHeaderData; +use super::file::header::data::FileHeaderData; pub struct ParserError { summary: String,