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. diff --git a/src/cli.rs b/src/cli.rs index 47636f8e..6a75b5da 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 diff --git a/src/configuration.rs b/src/configuration.rs index 2ac587b8..89b930e1 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, @@ -63,18 +72,30 @@ 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() } @@ -89,6 +110,9 @@ impl Configuration { } +/** + * 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))) @@ -98,6 +122,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; 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"); 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 { 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![]; 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] } } 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 { 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; diff --git a/src/runtime.rs b/src/runtime.rs index 28635436..b3c0a923 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 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, } 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(); 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, } 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) } 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()); 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(); 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, 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() }