From bdcfa344498ef72d75e9feaad645eb0d80f9c190 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 16:41:20 +0100 Subject: [PATCH 01/18] Rewrite README, squash some content to save lines --- README.md | 166 +++++++++++++++++++----------------------------------- 1 file changed, 59 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index a519c242..a0bc3296 100644 --- a/README.md +++ b/README.md @@ -21,23 +21,11 @@ see [Linking](#Linking)) Some modules might not want to store content there, for example you don't want to put your icalendar files in there. So the calendar module just crawls through -your ical files and puts the scanned meta-information into the store. Of course, -if the content of the ical file changes, the store entry does not. It still -points (via its JSON content for example) to the same file. So changes are not -tracked (We can argue here whether we want to copy the contents to the store for -ical and vcard files, but we cannot argue on for example music files). - +your ical files and puts only a link and some hashsums (for refinding on content +move) to the store. Changes are not tracked via this model. If a (for example ical-)file gets removed, the store entry gets invalid and has to be garbage-collected. -> The current model is not fixed yet. I'm thinking about copying .ical and -> .vcard, basically all text files, to the store. -> This is not possible for media files like music or movies, though. Also this -> is not feasible for documents like .pdf or similar. - -Each of the following modules has a short description including a table what -core features are required to get it working. - ### Linking The UUID/SHA hashes in the file names can be used to connect two store entries. @@ -89,40 +77,75 @@ should't touch the content at all. Here is a short overview what are the modules like: -| Module | Indexer | Header | Hdr-Format | Content | -| :---------------- | ------- | ------- | ---------- | ------- | -| Bookmarks | | X | JSON | | -| Contacts | X | X | JSON | | -| Calendar | X | X | JSON | | -| Notes | | X | YAML | X | -| Mail | X | X | JSON | | -| Wiki | | X | YAML | X | -| Todo | | X | YAML | | -| Shoppinglist | | X | YAML | | -| Bibliography | X | X | JSON | | -| News | X | X | JSON | | -| Image | X | X | JSON | | -| Movie | X | X | JSON | | -| Music | X | X | JSON | | +| Module | Indexer | Header-Format | Content | Expl | Dep | +| :----------- | ------- | ------------- | ------- | ------- | ----------- | +| Bibliography | X | JSON | X | .bib | Notes | +| Bookmarks | | JSON | | | | +| Calendar | X | JSON | | | | +| Contacts | X | JSON | | | | +| Image | X | JSON | | | Notes | +| Mail | X | JSON | | | | +| Movie | X | JSON | | | Notes | +| Music | X | JSON | | | Notes | +| News | X | JSON | | | | +| Notes | | YAML | X | Content | | +| Shoppinglist | | YAML | | | Notes, Todo | +| Todo | | YAML | | | Notes | +| Wiki | | YAML | X | Content | | Explanation: -- An "Indexer" Module does only index some data and store the indexed meta - information in the store -- "Header" means that the header part of a store entry is used -- "Hdr-Format" Which format is chosen for the header. Basically: YAML if the +- An "Indexer" Module does only index some data and stores only some information + on how to content +- "Header-Format": Which format is chosen for the header. Basically: YAML if the user might want to edit the header, otherwise JSON (pretty). - "Content" means that the content part of a store entry is used +- "Expl": What the content part of a file is used for. "Content" means simply + user content. +- "Dep" means that the module uses this other module as a dependency for + extending its own functionality + +### External Dependencies + +| Library | Optional | Module | +| :------------ | :------: | :------- | +| vcard | | Contacts | +| icalendar | | Calendar | +| XDG | X | Contacts | +| | X | Calendar | +| | X | Notes | +| | X | Mail | +| | X | Wiki | +| | X | Todo | +| | X | Shopping List | +| | X | BibMan | +| | X | Music | +| | X | Movie | +| | X | Image | +| Markdown | | Notes | +| | | Wiki | +| Maildir | | Mail | +| BibTex parsing | X | BibMan | +| git-annex | X | BibMan | +| | X | Music | +| | X | Movie | +| | X | Image | +| Exif | X | Image | +| id3 | X | Music | +| RSS/Atom | | News | + +(Optional means that these things are optional for the main functionality, but +should be implemented at some point to offer powerful functionality) ### Bookmarks Bookmarks should be stored in a simple format: ```json -{ "URL": "https://github.com", "tags": ["ducks", "r", "great"]} +{ "URL": "https://github.com", "TAGS": ["ducks", "r", "great"]} ``` -| Required core feature | Purpose | +| Required util feature | Purpose | | :------------------------------------ | :------------ | | XDG-open (Browser) | External program | @@ -131,29 +154,15 @@ Bookmarks should be stored in a simple format: Contacts are just read and indexed by `imag`, to create an internal index of them and to be able to refer to. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| vcard file format parsing | Data access | -| XDG-open (Mail program) | External Program | - ### Calendar Calendar are just read and indexed by `imag`, to create an internal index of them and to be able to refer to. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| ical file format parsing | Data access | - ### Notes Just plain text notes. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Linking to other store entries | Data Link | -| XDG-open (Editor) | External Program | - ### Mail `imag` should be able to index all your mail and make them accessible through @@ -163,26 +172,12 @@ notes, etc etc. to your mail. Some of these things (like linking contacts, calendar entries) should be linked automatically. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Parser: Maildir | Data access | -| Parser: mbox | Data access | -| XDG-open (Mail program) | External Program | -| XDG-open (Editor) | External Program | - ### Personal Wiki `imag` should contain a complete personal wiki software. It should contain of simple markdown files which have a YAML header, nothing too special for the first step. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Parser: Markdown | Data parsing | -| XDG-open (Editor) | External Program | -| XDG-open (Mail program) | External Program | -| XDG-open (Browser) | External Program | - Some more ideas: - Extract URLs and put them into store as Bookmarks @@ -192,21 +187,9 @@ Some more ideas: `imag` should also contain a full todo-tool. I'm thinking about integrating taskwarrior through a wrapper here. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Library: taskwarrior | Implementation | -| XDG-open (Editor) | External Program | - ### Shoppinglist -Simply dot-and-tick lists. - -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Module: Todo-List | Implementation | -| XDG-open (Editor) | External Program | - -- Sub-form of the Todo-List module +Simply dot-and-tick lists, uses Todo and Notes in combination. ### Bibliography management @@ -214,53 +197,22 @@ BibTex would be the first step, maybe we should be able to add the actual PDFs here as well... didn't waste too much thoughts on this by now. If we have the PDF data, we need git-annex. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| BibTex parsing | Data parsing | -| Backend: git-annex | Data parsing | -| XDG-open (Editor) | External Program | -| XDG-open (PDF viewer) | External Program | -| XDG-open (Office suite) | External Program | - ### News (RSS) Just indexing, reading news is not task of `imag` and so isn't syncing. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Parser: RSS | Data parsing | -| Parser: Atom | Data parsing | - ### Image Just indexing photos. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Backend: git-annex | Data parsing | -| Image metadata reading | Data parsing | -| XDG-open (Image viewer) | External Program | - ### Video Just indexing movies. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Backend: git-annex | Data parsing | -| Movie metadata reading | Data parsing | -| XDG-open (Movie viewer) | External Program | - ### Music Just indexing music. -| Required core feature | Purpose | -| :------------------------------------ | :------------ | -| Backend: git-annex | Data parsing | -| Music metadata reading | Data parsing | -| XDG-open (Music player) | External Program | - # License This code is released under terms of GNU GPLv2. From 0d6f2b9500039685ff9b006e5cac7dfb3bb30e4f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 16:45:14 +0100 Subject: [PATCH 02/18] cli.rs: Add documentation to functions --- src/cli.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/cli.rs b/src/cli.rs index 3b1d8b4b..ee62a7b1 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -28,18 +28,32 @@ impl<'a> CliConfig<'a> { } } + /** + * Check whether the CLI says we should run verbose + */ pub fn is_verbose(&self) -> bool { self.cli_matches.is_present("verbose") || self.is_debugging() } + /** + * Check whether the CLI says we should run in debugging + */ pub fn is_debugging(&self) -> bool { self.cli_matches.is_present("debug") } + /** + * Get the runtime path the CLI configured + */ pub fn get_rtp(&self) -> Option { self.cli_matches.value_of("rtp").and_then(|s| Some(String::from(s))) } + /** + * Get the store path the CLI configured + * + * TODO: Implement properly. Not working by now. + */ pub fn store_path(&self) -> Option { self.get_rtp().and_then(|rtp| { self.cli_matches From bbc62183912d8684084a9f0db2d911fc89a2b366 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 16:51:33 +0100 Subject: [PATCH 03/18] configuration.rs: Add documentation --- src/configuration.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/configuration.rs b/src/configuration.rs index a26cccff..35a15758 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -5,6 +5,15 @@ use config::reader::from_file; use config::types::Config as Cfg; use cli::CliConfig; +/** + * Configuration object which represents the configuration file. + * + * It gets passed a CliConfig object on ::new(), retreives some data from this one which is then + * provided as default value to the callee if there is no value for it in the configuration. + * + * TODO: Setup is kinda ugly, as we re-use data from the CLI, which is the job of the Runtime + * object later. + */ pub struct Configuration { pub rtp : String, pub store_sub : String, @@ -49,24 +58,39 @@ impl Configuration { } } + /** + * Check whether the configuration says we should run verbose + */ pub fn is_verbose(&self) -> bool { self.verbose } + /** + * Check whether the configuration says we should run in debugging + */ pub fn is_debugging(&self) -> bool { self.debugging } + /** + * Get the store path the configuration configured + */ pub fn store_path(&self) -> String { format!("{}{}", self.rtp, self.store_sub) } + /** + * Get the runtime path the configuration configured + */ pub fn get_rtp(&self) -> String { self.rtp.clone() } } +/** + * Helper to get the runtimepath from the CLI + */ fn rtp_path(config: &CliConfig) -> Option { config.cli_matches.value_of("rtp") .and_then(|s| Some(String::from(s))) @@ -76,6 +100,9 @@ fn fetch_config(rtp: Option) -> Option { rtp.and_then(|r| from_file(Path::new(&(r.clone() + "/config"))).ok()) } +/** + * Default runtime path, if available. + */ fn default_path() -> Option { use std::env::home_dir; From 89cc625133583b84251e741c9d632a487e3f8f59 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 16:54:18 +0100 Subject: [PATCH 04/18] runtime.rs: Add docs to functions --- src/runtime.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/runtime.rs b/src/runtime.rs index a2b1eed1..ffcd6389 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -51,6 +51,11 @@ impl log::Log for ImagLogger { } } +/** + * Runtime object, represents a single interface to both the CLI configuration and the + * configuration file. Also carries the store object around and is basically an object which + * contains everything which is required to run a command/module. + */ pub struct Runtime<'a> { pub config : CliConfig<'a>, pub configuration : Cfg, @@ -68,22 +73,37 @@ impl<'a> Runtime<'a> { } } + /** + * Check whether we run verbose + */ pub fn is_verbose(&self) -> bool { self.config.is_verbose() || self.configuration.is_verbose() } + /** + * Check whether we run in debugging + */ pub fn is_debugging(&self) -> bool { self.config.is_debugging() || self.configuration.is_verbose() } + /** + * Get the store path we are currently using + */ pub fn store_path(&self) -> String { self.config.store_path().unwrap_or(self.configuration.store_path()) } + /** + * Get the store object + */ pub fn store(&self) -> &Store { &self.store } + /** + * Get the runtime path we are currently using + */ pub fn get_rtp(&self) -> String { if let Some(rtp) = self.config.get_rtp() { rtp From dc181ba8eb903f3850e15e3bc8e7bc1e725e2a56 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 16:55:28 +0100 Subject: [PATCH 05/18] Add doc to Module trait --- src/module/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/module/mod.rs b/src/module/mod.rs index 3c907d78..95f0b7be 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -11,6 +11,9 @@ use runtime::Runtime; pub mod bm; pub mod helpers; +/** + * Module interface, each module has to implement this. + */ pub trait Module<'a> : Debug { fn exec(&self, matches: &ArgMatches) -> bool; fn name(&self) -> &'static str; From 271c91e9039e4a35c239b09a359814f7f093b23b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 16:57:14 +0100 Subject: [PATCH 06/18] Add documentation on module helper utils --- src/module/helpers/utils.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/module/helpers/utils.rs b/src/module/helpers/utils.rs index 9589aa2a..a890c5fd 100644 --- a/src/module/helpers/utils.rs +++ b/src/module/helpers/utils.rs @@ -1,9 +1,16 @@ +/** + * Utility helpers for CLI + */ pub mod cli { use clap::ArgMatches; use regex::Regex; use runtime::Runtime; + /** + * Get a commandline option "tags" and split the argument by "," to be able to provide a + * Vec with the argument as array. + */ pub fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec { fn reject_if_with_spaces(e: &String) -> bool { From e9cee25ac81571b5501e0d4ed2d5424fa82f29e6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:04:24 +0100 Subject: [PATCH 07/18] Add doc to module helpers --- src/module/helpers/mod.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/module/helpers/mod.rs b/src/module/helpers/mod.rs index 8b501b4a..f260114b 100644 --- a/src/module/helpers/mod.rs +++ b/src/module/helpers/mod.rs @@ -1,17 +1,39 @@ +/*! + * Utility helpers for modules + */ + pub mod header; pub mod utils; +/** + * Helpers for header specs + */ pub mod spec { use storage::file::header::spec::FileHeaderSpec as FHS; + /** + * Helper to get a spec for a Key-Value for a named text: + * + * { '': "" } + */ pub fn named_text(name: &str) -> FHS { FHS::Key { name: String::from(name), value_type: Box::new(FHS::Text) } } + /** + * Helper to get a spec for a Key-Value for a named array: + * + * { '': [ "", ...] } + */ pub fn named_text_array(name: &str) -> FHS { FHS::Key { name: String::from(name), value_type: Box::new(text_array()) } } + /** + * Helper to get a spec for Array: + * + * [ "", ...] + */ pub fn text_array() -> FHS { FHS::Array { allowed_types: vec![FHS::Text] } } From ffcb95146832378a2a7c292fc7958b876ff18db9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:04:35 +0100 Subject: [PATCH 08/18] Add doc to module header helpers --- src/module/helpers/header/mod.rs | 12 ++++++++++- src/module/helpers/header/tags.rs | 33 ++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/module/helpers/header/mod.rs b/src/module/helpers/header/mod.rs index 250decc2..04fdc834 100644 --- a/src/module/helpers/header/mod.rs +++ b/src/module/helpers/header/mod.rs @@ -1,13 +1,23 @@ -/* +/*! * Helpers for headers */ pub mod tags; +/** + * Utility helpers for header data + */ pub mod data { use std::ops::Deref; use storage::file::header::data::FileHeaderData as FHD; + /** + * Get an URL from a header, whereas the header has to have the following format: + * + * { ..., "URL": "", ... } + * + * Does no spec verification. + */ pub fn get_url_from_header(header: &FHD) -> Option { match header { &FHD::Map{keys: ref ks} => { diff --git a/src/module/helpers/header/tags.rs b/src/module/helpers/header/tags.rs index a78a2fb4..e2e390e0 100644 --- a/src/module/helpers/header/tags.rs +++ b/src/module/helpers/header/tags.rs @@ -1,30 +1,61 @@ -/* +/*! * Helpers for headers - Tags */ +/** + * Spec helpers for header-tags + */ pub mod spec { use storage::file::header::spec::FileHeaderSpec as FHS; use module::helpers::spec::{named_text, named_text_array}; + /** + * helper for a Header spec for + * + * { "URL": "" } + */ pub fn url_key() -> FHS { named_text("URL") } + /** + * helper for a Header spec for + * + * { "TAGS": [ "", ... ] } + */ pub fn tags_key() -> FHS { named_text_array("TAGS") } } +/** + * Data helpers for header-tags + */ pub mod data { use std::ops::Deref; use storage::file::header::data::FileHeaderData as FHD; + /** + * Use a Vec to build a Tag-Array: + * + * [ "", ... ] + */ pub fn build_tag_array(tags: Vec) -> FHD { let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect(); FHD::Array { values: Box::new(texttags) } } + /** + * Fetch tags from a header, whereas the header looks like this: + * + * { ..., + * "TAGS": [ "", ... ], + * ... + * } + * + * Does no spec verification. + */ pub fn get_tags_from_header(header: &FHD) -> Vec { let mut tags : Vec = vec![]; From be233b8abaae656c18be172fc1bd2c1e127e5832 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:07:14 +0100 Subject: [PATCH 09/18] Add docs to BM module --- src/module/bm/mod.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/module/bm/mod.rs b/src/module/bm/mod.rs index 6644c59e..9b500ec3 100644 --- a/src/module/bm/mod.rs +++ b/src/module/bm/mod.rs @@ -40,6 +40,9 @@ impl<'a> BM<'a> { &self.rt } + /** + * Subcommand: add + */ fn command_add(&self, matches: &ArgMatches) -> bool { use std::process::exit; use self::header::build_header; @@ -100,6 +103,9 @@ impl<'a> BM<'a> { return true; } + /** + * Subcommand: list + */ fn command_list(&self, matches: &ArgMatches) -> bool { use ui::file::{FilePrinter, TablePrinter}; use std::ops::Deref; @@ -124,6 +130,9 @@ impl<'a> BM<'a> { true } + /** + * Subcommand: remove + */ fn command_remove(&self, matches: &ArgMatches) -> bool { use std::process::exit; @@ -152,6 +161,9 @@ impl<'a> BM<'a> { return result; } + /** + * Subcommand: add_tags + */ fn command_add_tags(&self, matches: &ArgMatches) -> bool { self.alter_tags_in_files(matches, |old_tags, cli_tags| { let mut new_tags = old_tags.clone(); @@ -160,6 +172,9 @@ impl<'a> BM<'a> { }) } + /** + * Subcommand: rm_tags + */ fn command_rm_tags(&self, matches: &ArgMatches) -> bool { self.alter_tags_in_files(matches, |old_tags, cli_tags| { old_tags.clone() @@ -169,12 +184,18 @@ impl<'a> BM<'a> { }) } + /** + * Subcommand: set_tags + */ fn command_set_tags(&self, matches: &ArgMatches) -> bool { self.alter_tags_in_files(matches, |old_tags, cli_tags| { cli_tags.clone() }) } + /** + * Helper function to alter the tags in a file + */ fn alter_tags_in_files(&self, matches: &ArgMatches, generate_new_tags: F) -> bool where F: Fn(Vec, &Vec) -> Vec { @@ -229,7 +250,10 @@ impl<'a> BM<'a> { .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, @@ -257,6 +281,9 @@ impl<'a> BM<'a> { } } + /** + * Get files from the store, filtere by ID + */ fn get_files_by_id(&self, hash: FileHash) -> Vec>> { let parser = Parser::new(JsonHeaderParser::new(None)); self.rt @@ -266,6 +293,9 @@ impl<'a> BM<'a> { .unwrap_or(vec![]) } + /** + * Get files from the store, filtere by Regex + */ fn get_files_by_match(&self, matcher: String) -> Vec>> { let parser = Parser::new(JsonHeaderParser::new(None)); let re = Regex::new(&matcher[..]).unwrap_or_else(|e| { @@ -292,6 +322,9 @@ impl<'a> BM<'a> { .collect() } + /** + * Get files from the store, filtere by tags + */ fn get_files_by_tags(&self, tags: Vec) -> Vec>> { let parser = Parser::new(JsonHeaderParser::new(None)); self.rt @@ -309,6 +342,9 @@ impl<'a> BM<'a> { } +/** + * Trait implementation for BM module + */ impl<'a> Module<'a> for BM<'a> { fn exec(&self, matches: &ArgMatches) -> bool { From 5791ba7b8d72b76e55dd83a67d161e7b2d9bfba9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:26:17 +0100 Subject: [PATCH 10/18] Add doc to Store object implementation --- src/storage/mod.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/storage/mod.rs b/src/storage/mod.rs index f97e4b50..8f2a3707 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -27,6 +27,12 @@ pub struct Store { cache : RefCell, } +/** + * Store object + * + * This object is an abstraction layer over FS and an interface to the object store of this + * software. + */ impl Store { pub fn new(storepath: String) -> Store { @@ -36,12 +42,20 @@ impl Store { } } + /** + * Put a file into the cache + */ fn put_in_cache(&self, f: File) -> FileID { let res = f.id().clone(); self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f))); res } + /** + * Load a file by ID into the cache and return it afterwards + * + * Returns None if the file could be loaded from the Filesystem + */ pub fn load_in_cache(&self, m: &Module, parser: &Parser, id: FileID) -> Option>> where HP: FileHeaderParser @@ -63,6 +77,11 @@ impl Store { self.load(&id) } + /** + * Generate a new file for a module. + * + * Returns the new FileID object then + */ pub fn new_file(&self, module: &Module) -> FileID { @@ -77,6 +96,11 @@ impl Store { self.put_in_cache(f) } + /** + * Generate a new file from a parser result. + * + * @deprecated This function shouldn't be needed anymore + */ pub fn new_file_from_parser_result(&self, module: &Module, id: FileID, @@ -94,6 +118,11 @@ impl Store { self.put_in_cache(f) } + /** + * Generate a new file for a module, providing some header data + * + * Returns the new FileID object then + */ pub fn new_file_with_header(&self, module: &Module, h: FileHeaderData) @@ -109,6 +138,11 @@ impl Store { self.put_in_cache(f) } + /** + * Generate a new file for a module, providing some initial data + * + * Returns the new FileID object then + */ pub fn new_file_with_data(&self, module: &Module, d: String) -> FileID { @@ -122,6 +156,12 @@ impl Store { self.put_in_cache(f) } + + /** + * Generate a new file for a module, providing some initial data and some header + * + * Returns the new FileID object then + */ pub fn new_file_with_content(&self, module: &Module, h: FileHeaderData, @@ -138,6 +178,11 @@ impl Store { self.put_in_cache(f) } + /** + * Persist a File on the filesystem + * + * Returns true if this worked + */ pub fn persist(&self, p: &Parser, f: Rc>) -> bool @@ -162,8 +207,15 @@ impl Store { }).map_err(|writeerr| { debug!("Could not create file at '{}'", path); }).and(Ok(true)).unwrap() + + // TODO: Is this unwrap() save? } + /** + * Helper to generate the store path + * + * Kills the program if it fails + */ fn ensure_store_path_exists(&self) { use std::fs::create_dir_all; use std::process::exit; @@ -176,11 +228,20 @@ impl Store { }) } + /** + * Load a file from the cache by FileID + * + * TODO: Semantics: This function should load from FS if the file is not in the cache yet or + * fail if the file is not available. + */ pub fn load(&self, id: &FileID) -> Option>> { debug!("Loading '{:?}'", id); self.cache.borrow().get(id).cloned() } + /** + * Load a file from the filesystem/cache by a FileHash + */ pub fn load_by_hash(&self, m: &Module, parser: &Parser, @@ -232,6 +293,11 @@ impl Store { }).unwrap_or(None) } + /** + * Remove a file from the filesystem by FileID + * + * Returns true if this works. + */ pub fn remove(&self, id: FileID) -> bool { use std::fs::remove_file; @@ -250,6 +316,9 @@ impl Store { .unwrap_or(false) } + /** + * Load all files for a module + */ pub fn load_for_module(&self, m: &Module, parser: &Parser) -> Vec>> where HP: FileHeaderParser @@ -276,6 +345,9 @@ impl Store { res } + /** + * Helper to generate a new FileID object + */ fn get_new_file_id(&self) -> FileID { use uuid::Uuid; let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string()); From 3a7bf9f4dee3f33a09620ab49a9a13ce99c6b437 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:30:42 +0100 Subject: [PATCH 11/18] Add doc to parser code --- src/storage/parser.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/storage/parser.rs b/src/storage/parser.rs index 3c343623..bcbf9a53 100644 --- a/src/storage/parser.rs +++ b/src/storage/parser.rs @@ -83,11 +83,26 @@ impl Display for ParserError { } +/** + * Trait for a header parser. + * + * This parser type has to provide two functions: + * - read(), which reads an String into a FileHeaderData structure + * - write(), which parses a FileHeaderData structure into a String + * + * TODO: Use Write/Read traits? + */ pub trait FileHeaderParser : Sized + Debug + Display { fn read(&self, string: Option) -> Result; fn write(&self, data: &FileHeaderData) -> Result; } +/** + * Parser + * + * This Parser object is an abstraction which uses the FileHeaderParser to parse the whole contents + * of a file into a header (FileHeaderData) structure and the content (String). + */ pub struct Parser { headerp : HP, } @@ -100,6 +115,10 @@ impl Parser { } } + /** + * Read the String which is the contents of a file into a (FileHeaderData, String) tuple, which + * is the header and the content of the file. + */ pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError> { debug!("Reading into internal datastructure: '{}'", s); let divided = self.divide_text(&s); @@ -122,6 +141,10 @@ impl Parser { Ok((h_parseres, data.unwrap_or(String::new()))) } + /** + * Write the FileHeaderData and String (header and content) of the tuple into a String, which + * can then simply be written into the store as a file. + */ pub fn write(&self, tpl : (&FileHeaderData, &String)) -> Result { debug!("Parsing internal datastructure to String"); let (header, data) = tpl; @@ -132,6 +155,10 @@ impl Parser { Ok(text) } + /** + * Helper to parse the full-text of a file into a header part (String) and a content part + * (String) + */ fn divide_text(&self, text: &String) -> Result<(Option, Option), ParserError> { let re = Regex::new(r"(?sm)^---$(.*)^---$(.*)").unwrap(); From 6bcfc0a4b25a8206027edb1806b024f4d9a80f95 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:32:51 +0100 Subject: [PATCH 12/18] Add docs to File --- src/storage/file/mod.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/storage/file/mod.rs b/src/storage/file/mod.rs index 61a7f749..733fa376 100644 --- a/src/storage/file/mod.rs +++ b/src/storage/file/mod.rs @@ -19,43 +19,71 @@ 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 +/** + * Internal abstract view on a file. Does not neccessarily exist on the FS and is just kept * internally until it is written to disk. */ pub struct File { + /// The name of the module which owns this file pub owning_module_name : &'static str, + + /// The header of the file pub header : FileHeaderData, + + /// The content part of the file pub data : String, + + /// The ID of the file pub id : FileID, } impl File { + /** + * Get the owner module name of the file + */ pub fn owner_name(&self) -> &'static str { self.owning_module_name } + /** + * Get the header of the file + */ pub fn header(&self) -> &FileHeaderData { &self.header } + /** + * Set the header of the file + */ pub fn set_header(&mut self, new_header: FileHeaderData) { self.header = new_header; } + /** + * Set the data of the file + */ pub fn data(&self) -> &String { &self.data } + /** + * Set the (header, data) of the file + */ pub fn contents(&self) -> (&FileHeaderData, &String) { (self.header(), self.data()) } + /** + * Set the id of the file + */ pub fn id(&self) -> &FileID { &self.id } + /** + * Check whether the header or the data of the file match some regex + */ pub fn matches_with(&self, r: &Regex) -> bool { r.is_match(&self.data[..]) || self.header.matches_with(r) } From d34143e5166db41d08bac15bce1917db5be03b6a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:35:51 +0100 Subject: [PATCH 13/18] Add docs to FileID --- src/storage/file/id.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/storage/file/id.rs b/src/storage/file/id.rs index c274077e..29a6c752 100644 --- a/src/storage/file/id.rs +++ b/src/storage/file/id.rs @@ -16,6 +16,15 @@ use storage::file::hash::FileHash; #[derive(Hash)] #[derive(Eq)] #[derive(PartialEq)] +/** + * FileID + * + * A FileID contains of two parts: The ID type and the Hash. For example the FileID + * + * UUID-235-1215-1212 + * + * has a type ("UUID") and a Hash ("235-1215-1212"). + */ pub struct FileID { id: FileHash, id_type: FileIDType, @@ -30,14 +39,23 @@ impl FileID { } } + /** + * Get the type of the FileID + */ pub fn get_type(&self) -> FileIDType { self.id_type.clone() } + /** + * Get the Hash of the FileID + */ pub fn get_id(&self) -> FileHash { self.id.clone() } + /** + * Parse a String into a FileID, if possible + */ pub fn parse(string: &String) -> Option { // we assume that it is an path let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap(); From d25a0dd1c0e00c8d9a2dae538e47038f5e9a31e4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:36:53 +0100 Subject: [PATCH 14/18] Add docs to FileIDType --- src/storage/file/id_type.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/storage/file/id_type.rs b/src/storage/file/id_type.rs index 474e12a5..b9532262 100644 --- a/src/storage/file/id_type.rs +++ b/src/storage/file/id_type.rs @@ -9,6 +9,11 @@ use std::hash::Hash; #[derive(Eq)] // #[derive(Display)] #[derive(Hash)] +/** + * File ID type + * + * Currently only UUID is available. Maybe this will be the only type available at all. + */ pub enum FileIDType { UUID, } From 2334b0bc8acd392654eb78e2487a3175ce9074a9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:37:42 +0100 Subject: [PATCH 15/18] Add docs to FileHash --- src/storage/file/hash.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/storage/file/hash.rs b/src/storage/file/hash.rs index a2f1f96a..4b364b25 100644 --- a/src/storage/file/hash.rs +++ b/src/storage/file/hash.rs @@ -10,6 +10,11 @@ use uuid::Uuid; #[derive(PartialEq)] #[derive(Eq)] #[derive(Hash)] +/** + * FileHash type + * + * Simple abstraction over String by now. + */ pub struct FileHash { hash: String, } From 43bf526740dbe80458f926900ede85a5fbbf8c72 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:42:28 +0100 Subject: [PATCH 16/18] Add docs to ui/file.rs --- src/ui/file.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ui/file.rs b/src/ui/file.rs index 4b09e252..369c7164 100644 --- a/src/ui/file.rs +++ b/src/ui/file.rs @@ -5,6 +5,9 @@ use std::ops::Deref; use storage::file::File; +/** + * Trait for a printer which can be used to print data from files + */ pub trait FilePrinter { fn new(verbose: bool, debug: bool) -> Self; @@ -40,6 +43,9 @@ pub trait FilePrinter { } +/** + * Printer which prints in debug mode if enabled + */ struct DebugPrinter { debug: bool, } @@ -68,6 +74,9 @@ impl FilePrinter for DebugPrinter { } +/** + * Simple printer, which just uses the info!() macro or debug!() macro if in debug mode. + */ struct SimplePrinter { verbose: bool, debug: bool, @@ -107,6 +116,9 @@ impl FilePrinter for SimplePrinter { } +/** + * Table printer to print file information in a nice ASCII-table + */ pub struct TablePrinter { verbose: bool, debug: bool, From c4a388925ec58f19e28b9eecff5c77168d0a56b4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Dec 2015 17:43:06 +0100 Subject: [PATCH 17/18] Add doc to util::is_url() --- src/util/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/mod.rs b/src/util/mod.rs index 6bef3251..41df92d6 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,5 +1,8 @@ use url::Url; +/** + * Util: Check wether a String can be parsed as an URL + */ pub fn is_url(url: &String) -> bool { Url::parse(&url[..]).is_ok() } From 1647352a1365b4c809c7a44579a7796624dce7a8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 30 Dec 2015 02:10:50 +0100 Subject: [PATCH 18/18] Use modules publicly, so "cargo doc" generates documentation --- src/main.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 19ffa8c7..c695da28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,21 +11,21 @@ extern crate config; use std::process::exit; -use cli::CliConfig; -use configuration::Configuration; -use runtime::{ImagLogger, Runtime}; -use clap::App; -use module::Module; +pub use cli::CliConfig; +pub use configuration::Configuration; +pub use runtime::{ImagLogger, Runtime}; +pub use clap::App; +pub use module::Module; -mod cli; -mod configuration; -mod runtime; -mod module; -mod storage; -mod ui; -mod util; +pub mod cli; +pub mod configuration; +pub mod runtime; +pub mod module; +pub mod storage; +pub mod ui; +pub mod util; -use module::bm::BM; +pub use module::bm::BM; fn main() { let yaml = load_yaml!("../etc/cli.yml");