Remove stuff for the focus-shift
This commit is contained in:
parent
0cf564091e
commit
63a7f0d8a9
70 changed files with 0 additions and 4597 deletions
|
@ -15,15 +15,6 @@ homepage = "http://imag-pim.org"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
[dependencies.libimagbookmark]
|
|
||||||
path = "../libimagbookmark"
|
|
||||||
|
|
||||||
[dependencies.libimagcounter]
|
|
||||||
path = "../libimagcounter"
|
|
||||||
|
|
||||||
[dependencies.libimagdiary]
|
|
||||||
path = "../libimagdiary"
|
|
||||||
|
|
||||||
[dependencies.libimagentryfilter]
|
[dependencies.libimagentryfilter]
|
||||||
path = "../libimagentryfilter"
|
path = "../libimagentryfilter"
|
||||||
|
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -18,20 +18,12 @@ codegen-units = 2
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"bin",
|
"bin",
|
||||||
"imag-bookmark",
|
|
||||||
"imag-counter",
|
|
||||||
"imag-diary",
|
|
||||||
"imag-link",
|
"imag-link",
|
||||||
"imag-mail",
|
|
||||||
"imag-notes",
|
"imag-notes",
|
||||||
"imag-ref",
|
"imag-ref",
|
||||||
"imag-store",
|
"imag-store",
|
||||||
"imag-tag",
|
"imag-tag",
|
||||||
"imag-todo",
|
|
||||||
"imag-view",
|
"imag-view",
|
||||||
"libimagbookmark",
|
|
||||||
"libimagcounter",
|
|
||||||
"libimagdiary",
|
|
||||||
"libimagentryedit",
|
"libimagentryedit",
|
||||||
"libimagentryfilter",
|
"libimagentryfilter",
|
||||||
"libimagentrylink",
|
"libimagentrylink",
|
||||||
|
@ -41,14 +33,12 @@ members = [
|
||||||
"libimagentryview",
|
"libimagentryview",
|
||||||
"libimagerror",
|
"libimagerror",
|
||||||
"libimaginteraction",
|
"libimaginteraction",
|
||||||
"libimagmail",
|
|
||||||
"libimagnotes",
|
"libimagnotes",
|
||||||
"libimagref",
|
"libimagref",
|
||||||
"libimagrt",
|
"libimagrt",
|
||||||
"libimagstore",
|
"libimagstore",
|
||||||
"libimagstorestdhook",
|
"libimagstorestdhook",
|
||||||
"libimagtimeui",
|
"libimagtimeui",
|
||||||
"libimagtodo",
|
|
||||||
"libimagutil",
|
"libimagutil",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "imag-bookmark"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Part of the imag core distribution: imag-bookmark command"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
clap = ">=2.17"
|
|
||||||
log = "0.3"
|
|
||||||
version = "2.0.1"
|
|
||||||
|
|
||||||
[dependencies.libimagrt]
|
|
||||||
path = "../libimagrt"
|
|
||||||
|
|
||||||
[dependencies.libimagutil]
|
|
||||||
path = "../libimagutil"
|
|
||||||
|
|
||||||
[dependencies.libimagbookmark]
|
|
||||||
path = "../libimagbookmark"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagentrylink]
|
|
||||||
path = "../libimagentrylink"
|
|
||||||
|
|
||||||
[dependencies.libimagentrytag]
|
|
||||||
path = "../libimagentrytag"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/04020-module-bookmarks.md
|
|
|
@ -1,158 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_must_use,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
extern crate clap;
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
#[macro_use] extern crate version;
|
|
||||||
|
|
||||||
extern crate libimagbookmark;
|
|
||||||
extern crate libimagentrylink;
|
|
||||||
extern crate libimagentrytag;
|
|
||||||
extern crate libimagrt;
|
|
||||||
extern crate libimagerror;
|
|
||||||
extern crate libimagutil;
|
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
|
||||||
use libimagbookmark::collection::BookmarkCollection;
|
|
||||||
use libimagbookmark::link::Link as BookmarkLink;
|
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
|
|
||||||
use libimagutil::info_result::*;
|
|
||||||
use libimagutil::iter::*;
|
|
||||||
|
|
||||||
mod ui;
|
|
||||||
|
|
||||||
use ui::build_ui;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let rt = generate_runtime_setup("imag-bookmark",
|
|
||||||
&version!()[..],
|
|
||||||
"Bookmark collection tool",
|
|
||||||
build_ui);
|
|
||||||
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_name()
|
|
||||||
.map(|name| {
|
|
||||||
debug!("Call {}", name);
|
|
||||||
match name {
|
|
||||||
"add" => add(&rt),
|
|
||||||
"collection" => collection(&rt),
|
|
||||||
"list" => list(&rt),
|
|
||||||
"remove" => remove(&rt),
|
|
||||||
_ => {
|
|
||||||
debug!("Unknown command"); // More error handling
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("add").unwrap();
|
|
||||||
let coll = scmd.value_of("collection").unwrap(); // enforced by clap
|
|
||||||
|
|
||||||
BookmarkCollection::get(rt.store(), coll)
|
|
||||||
.and_then(|mut collection| {
|
|
||||||
scmd.values_of("urls")
|
|
||||||
.unwrap() // enforced by clap
|
|
||||||
.fold_defresult(|url| collection.add_link(BookmarkLink::from(url)))
|
|
||||||
})
|
|
||||||
.map_err_trace()
|
|
||||||
.map_info_str("Ready")
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collection(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("collection").unwrap();
|
|
||||||
|
|
||||||
if scmd.is_present("add") { // adding a new collection
|
|
||||||
let name = scmd.value_of("add").unwrap();
|
|
||||||
if let Ok(_) = BookmarkCollection::new(rt.store(), name) {
|
|
||||||
info!("Created: {}", name);
|
|
||||||
} else {
|
|
||||||
warn!("Creating collection {} failed", name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if scmd.is_present("remove") { // remove a collection
|
|
||||||
let name = scmd.value_of("remove").unwrap();
|
|
||||||
if let Ok(_) = BookmarkCollection::delete(rt.store(), name) {
|
|
||||||
info!("Deleted: {}", name);
|
|
||||||
} else {
|
|
||||||
warn!("Deleting collection {} failed", name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("list").unwrap();
|
|
||||||
let coll = scmd.value_of("collection").unwrap(); // enforced by clap
|
|
||||||
|
|
||||||
BookmarkCollection::get(rt.store(), coll)
|
|
||||||
.map(|collection| {
|
|
||||||
match collection.links() {
|
|
||||||
Ok(links) => {
|
|
||||||
debug!("Listing...");
|
|
||||||
for (i, link) in links.enumerate() {
|
|
||||||
match link {
|
|
||||||
Ok(link) => println!("{: >3}: {}", i, link),
|
|
||||||
Err(e) => trace_error(&e)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("... ready with listing");
|
|
||||||
},
|
|
||||||
Err(e) => trace_error_exit(&e, 1),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
info!("Ready");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("remove").unwrap();
|
|
||||||
let coll = scmd.value_of("collection").unwrap(); // enforced by clap
|
|
||||||
|
|
||||||
BookmarkCollection::get(rt.store(), coll)
|
|
||||||
.map(|mut collection| {
|
|
||||||
for url in scmd.values_of("urls").unwrap() { // enforced by clap
|
|
||||||
collection.remove_link(BookmarkLink::from(url)).map_err(|e| trace_error(&e)).ok();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
info!("Ready");
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use clap::{Arg, App, SubCommand};
|
|
||||||
|
|
||||||
use libimagentrytag::ui::tag_add_arg;
|
|
||||||
use libimagutil::cli_validators::*;
|
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|
||||||
app
|
|
||||||
.subcommand(SubCommand::with_name("add")
|
|
||||||
.about("Add bookmarks")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("collection")
|
|
||||||
.long("collection")
|
|
||||||
.short("c")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.multiple(false)
|
|
||||||
.value_name("COLLECTION")
|
|
||||||
.help("Add to this collection"))
|
|
||||||
.arg(Arg::with_name("urls")
|
|
||||||
.long("urls")
|
|
||||||
.short("u")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.multiple(true)
|
|
||||||
.value_name("URL")
|
|
||||||
.validator(is_url)
|
|
||||||
.help("Add this URL, multiple possible"))
|
|
||||||
.arg(tag_add_arg())
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("remove")
|
|
||||||
.about("Remove bookmarks")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("collection")
|
|
||||||
.long("collection")
|
|
||||||
.short("c")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.multiple(false)
|
|
||||||
.value_name("COLLECTION")
|
|
||||||
.help("Remove from this collection"))
|
|
||||||
.arg(Arg::with_name("urls")
|
|
||||||
.long("urls")
|
|
||||||
.short("u")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.multiple(true)
|
|
||||||
.value_name("URL")
|
|
||||||
.validator(is_url)
|
|
||||||
.help("Remove these urls, regex supported"))
|
|
||||||
)
|
|
||||||
|
|
||||||
// .subcommand(SubCommand::with_name("open")
|
|
||||||
// .about("Open bookmarks (via xdg-open)")
|
|
||||||
// .version("0.1")
|
|
||||||
// .arg(Arg::with_name("collection")
|
|
||||||
// .long("collection")
|
|
||||||
// .short("c")
|
|
||||||
// .takes_value(true)
|
|
||||||
// .required(true)
|
|
||||||
// .multiple(false)
|
|
||||||
// .value_name("COLLECTION")
|
|
||||||
// .help("Select from this collection"))
|
|
||||||
// )
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("list")
|
|
||||||
.about("List bookmarks")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("collection")
|
|
||||||
.long("collection")
|
|
||||||
.short("c")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.multiple(false)
|
|
||||||
.value_name("COLLECTION")
|
|
||||||
.help("Select from this collection"))
|
|
||||||
.arg(Arg::with_name("tags")
|
|
||||||
.long("tags")
|
|
||||||
.short("t")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.multiple(true)
|
|
||||||
.value_name("TAGS")
|
|
||||||
.help("Filter links to contain these tags. When multiple tags are specified, all of them must be set for the link to match."))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("collection")
|
|
||||||
.about("Collection commands")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("add")
|
|
||||||
.long("add")
|
|
||||||
.short("a")
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("NAME")
|
|
||||||
.help("Add a collection with this name"))
|
|
||||||
.arg(Arg::with_name("remove")
|
|
||||||
.long("remove")
|
|
||||||
.short("r")
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("NAME")
|
|
||||||
.help("Remove a collection with this name (and all links)"))
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "imag-counter"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Part of the imag core distribution: imag-counter command"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
clap = ">=2.17"
|
|
||||||
log = "0.3"
|
|
||||||
version = "2.0.1"
|
|
||||||
|
|
||||||
[dependencies.libimagrt]
|
|
||||||
path = "../libimagrt"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagutil]
|
|
||||||
path = "../libimagutil"
|
|
||||||
|
|
||||||
[dependencies.libimagcounter]
|
|
||||||
path = "../libimagcounter"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/04020-module-counter.md
|
|
|
@ -1,50 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::trace_error_exit;
|
|
||||||
use libimagcounter::counter::Counter;
|
|
||||||
use libimagcounter::counter::CounterUnit;
|
|
||||||
|
|
||||||
pub fn create(rt: &Runtime) {
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_matches("create")
|
|
||||||
.map(|scmd| {
|
|
||||||
debug!("Found 'create' subcommand...");
|
|
||||||
|
|
||||||
let name = scmd.value_of("name").unwrap(); // safe because clap enforces
|
|
||||||
let init : i64 = scmd
|
|
||||||
.value_of("initval")
|
|
||||||
.and_then(|i| FromStr::from_str(i).ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
let unit = scmd
|
|
||||||
.value_of("unit")
|
|
||||||
.map(CounterUnit::new);
|
|
||||||
|
|
||||||
Counter::new(rt.store(), String::from(name), init)
|
|
||||||
.and_then(|c| c.with_unit(unit))
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
warn!("Could not create Counter '{}' with initial value '{}'", name, init);
|
|
||||||
trace_error_exit(&e, 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::trace_error_exit;
|
|
||||||
use libimagcounter::counter::Counter;
|
|
||||||
|
|
||||||
pub fn delete(rt: &Runtime) {
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_matches("delete")
|
|
||||||
.map(|scmd| {
|
|
||||||
debug!("Found 'delete' subcommand...");
|
|
||||||
|
|
||||||
let name = String::from(scmd.value_of("name").unwrap()); // safe because clap enforces
|
|
||||||
|
|
||||||
if let Err(e) = Counter::delete(name, rt.store()) {
|
|
||||||
trace_error_exit(&e, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Ok");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,174 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::fmt::{Display, Formatter, Error};
|
|
||||||
use std::io::Write;
|
|
||||||
use std::io::stderr;
|
|
||||||
use std::io::stdin;
|
|
||||||
use std::process::exit;
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use libimagcounter::counter::Counter;
|
|
||||||
use libimagcounter::error::CounterError;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagutil::key_value_split::IntoKeyValue;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
use libimagerror::trace::{trace_error, trace_error_exit};
|
|
||||||
|
|
||||||
type Result<T> = RResult<T, CounterError>;
|
|
||||||
|
|
||||||
pub fn interactive(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("interactive");
|
|
||||||
if scmd.is_none() {
|
|
||||||
warn_exit("No subcommand", 1);
|
|
||||||
}
|
|
||||||
let scmd = scmd.unwrap();
|
|
||||||
debug!("Found 'interactive' command");
|
|
||||||
|
|
||||||
let mut pairs : BTreeMap<char, Binding> = BTreeMap::new();
|
|
||||||
|
|
||||||
for spec in scmd.values_of("spec").unwrap() {
|
|
||||||
match compute_pair(rt, &spec) {
|
|
||||||
Ok((k, v)) => { pairs.insert(k, v); },
|
|
||||||
Err(e) => { trace_error(&e); },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_quit_binding(&pairs) {
|
|
||||||
pairs.insert('q', Binding::Function(String::from("quit"), Box::new(quit)));
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr().flush().ok();
|
|
||||||
loop {
|
|
||||||
println!("---");
|
|
||||||
for (k, v) in &pairs {
|
|
||||||
println!("\t[{}] => {}", k, v);
|
|
||||||
}
|
|
||||||
println!("---");
|
|
||||||
print!("counter > ");
|
|
||||||
|
|
||||||
let mut input = String::new();
|
|
||||||
if let Err(e) = stdin().read_line(&mut input) {
|
|
||||||
trace_error_exit(&e, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cont = if !input.is_empty() {
|
|
||||||
let increment = match input.chars().next() { Some('-') => false, _ => true };
|
|
||||||
input.chars().all(|chr| {
|
|
||||||
match pairs.get_mut(&chr) {
|
|
||||||
Some(&mut Binding::Counter(ref mut ctr)) => {
|
|
||||||
if increment {
|
|
||||||
debug!("Incrementing");
|
|
||||||
if let Err(e) = ctr.inc() {
|
|
||||||
trace_error(&e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug!("Decrementing");
|
|
||||||
if let Err(e) = ctr.dec() {
|
|
||||||
trace_error(&e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
Some(&mut Binding::Function(ref name, ref f)) => {
|
|
||||||
debug!("Calling {}", name);
|
|
||||||
f()
|
|
||||||
},
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
println!("No input...");
|
|
||||||
println!("\tUse a single character to increment the counter which is bound to it");
|
|
||||||
println!("\tUse 'q' (or the character bound to quit()) to exit");
|
|
||||||
println!("\tPrefix the line with '-' to decrement instead of increment the counters");
|
|
||||||
println!("");
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
if !cont {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_quit_binding(pairs: &BTreeMap<char, Binding>) -> bool {
|
|
||||||
pairs.iter()
|
|
||||||
.any(|(_, bind)| {
|
|
||||||
match *bind {
|
|
||||||
Binding::Function(ref name, _) => name == "quit",
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Binding<'a> {
|
|
||||||
Counter(Counter<'a>),
|
|
||||||
Function(String, Box<Fn() -> bool>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Display for Binding<'a> {
|
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), Error> {
|
|
||||||
match *self {
|
|
||||||
Binding::Counter(ref c) => {
|
|
||||||
match c.name() {
|
|
||||||
Ok(name) => {
|
|
||||||
try!(write!(fmt, "{}", name));
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
Ok(()) // TODO: Find a better way to escalate here.
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Binding::Function(ref name, _) => write!(fmt, "{}()", name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_pair<'a>(rt: &'a Runtime, spec: &str) -> Result<(char, Binding<'a>)> {
|
|
||||||
let kv = String::from(spec).into_kv();
|
|
||||||
if kv.is_none() {
|
|
||||||
warn_exit("Key-Value parsing failed!", 1);
|
|
||||||
}
|
|
||||||
let kv = kv.unwrap();
|
|
||||||
|
|
||||||
let (k, v) = kv.into();
|
|
||||||
if !k.len() == 1 {
|
|
||||||
// We have a key which is not only a single character!
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if v == "quit" {
|
|
||||||
// TODO uncaught unwrap()
|
|
||||||
Ok((k.chars().next().unwrap(), Binding::Function(String::from("quit"), Box::new(quit))))
|
|
||||||
} else {
|
|
||||||
// TODO uncaught unwrap()
|
|
||||||
Counter::load(v, rt.store()).and_then(|ctr| Ok((k.chars().next().unwrap(), Binding::Counter(ctr))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quit() -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
|
||||||
use libimagcounter::counter::Counter;
|
|
||||||
|
|
||||||
pub fn list(rt: &Runtime) {
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_matches("list")
|
|
||||||
.map(|_| {
|
|
||||||
debug!("Found 'list' subcommand...");
|
|
||||||
|
|
||||||
Counter::all_counters(rt.store()).map(|iterator| {
|
|
||||||
for counter in iterator {
|
|
||||||
counter.map(|c| {
|
|
||||||
let name = c.name();
|
|
||||||
let value = c.value();
|
|
||||||
let unit = c.unit();
|
|
||||||
|
|
||||||
if name.is_err() {
|
|
||||||
trace_error(&name.unwrap_err());
|
|
||||||
} else if value.is_err() {
|
|
||||||
trace_error(&value.unwrap_err());
|
|
||||||
} else if unit.is_none() {
|
|
||||||
println!("{} - {}", name.unwrap(), value.unwrap());
|
|
||||||
} else {
|
|
||||||
println!("{} - {} {}", name.unwrap(), value.unwrap(), unit.unwrap());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map_err_trace()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map_err_trace()
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_must_use,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
#[macro_use] extern crate version;
|
|
||||||
extern crate clap;
|
|
||||||
|
|
||||||
extern crate libimagcounter;
|
|
||||||
extern crate libimagrt;
|
|
||||||
extern crate libimagerror;
|
|
||||||
extern crate libimagutil;
|
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
|
||||||
use libimagcounter::counter::Counter;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagutil::key_value_split::IntoKeyValue;
|
|
||||||
use libimagutil::info_result::*;
|
|
||||||
|
|
||||||
mod create;
|
|
||||||
mod delete;
|
|
||||||
mod interactive;
|
|
||||||
mod list;
|
|
||||||
mod ui;
|
|
||||||
|
|
||||||
use ui::build_ui;
|
|
||||||
use create::create;
|
|
||||||
use delete::delete;
|
|
||||||
use interactive::interactive;
|
|
||||||
use list::list;
|
|
||||||
|
|
||||||
enum Action {
|
|
||||||
Inc,
|
|
||||||
Dec,
|
|
||||||
Reset,
|
|
||||||
Set,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let rt = generate_runtime_setup("imag-counter",
|
|
||||||
&version!()[..],
|
|
||||||
"Counter tool to count things",
|
|
||||||
build_ui);
|
|
||||||
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_name()
|
|
||||||
.map_or_else(|| {
|
|
||||||
let (action, name) = {
|
|
||||||
if rt.cli().is_present("increment") {
|
|
||||||
(Action::Inc, rt.cli().value_of("increment").unwrap())
|
|
||||||
} else if rt.cli().is_present("decrement") {
|
|
||||||
(Action::Dec, rt.cli().value_of("decrement").unwrap())
|
|
||||||
} else if rt.cli().is_present("reset") {
|
|
||||||
(Action::Reset, rt.cli().value_of("reset").unwrap())
|
|
||||||
} else /* rt.cli().is_present("set") */ {
|
|
||||||
(Action::Set, rt.cli().value_of("set").unwrap())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match action {
|
|
||||||
Action::Inc => {
|
|
||||||
Counter::load(String::from(name), rt.store())
|
|
||||||
.map(|mut c| c.inc().map_err_trace_exit(1).map_info_str("Ok"))
|
|
||||||
},
|
|
||||||
Action::Dec => {
|
|
||||||
Counter::load(String::from(name), rt.store())
|
|
||||||
.map(|mut c| c.dec().map_err_trace_exit(1).map_info_str("Ok"))
|
|
||||||
},
|
|
||||||
Action::Reset => {
|
|
||||||
Counter::load(String::from(name), rt.store())
|
|
||||||
.map(|mut c| c.reset().map_err_trace_exit(1).map_info_str("Ok"))
|
|
||||||
},
|
|
||||||
Action::Set => {
|
|
||||||
let kv = String::from(name).into_kv();
|
|
||||||
if kv.is_none() {
|
|
||||||
warn!("Not a key-value pair: '{}'", name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
let (key, value) = kv.unwrap().into();
|
|
||||||
let value = FromStr::from_str(&value[..]);
|
|
||||||
if value.is_err() {
|
|
||||||
warn!("Not a integer: '{:?}'", value);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
let value : i64 = value.unwrap();
|
|
||||||
Counter::load(String::from(key), rt.store())
|
|
||||||
.map(|mut c| c.set(value).map_err_trace_exit(1).map_info_str("Ok"))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
.map_err_trace()
|
|
||||||
.ok();
|
|
||||||
},
|
|
||||||
|name| {
|
|
||||||
debug!("Call: {}", name);
|
|
||||||
match name {
|
|
||||||
"create" => create(&rt),
|
|
||||||
"delete" => delete(&rt),
|
|
||||||
"interactive" => interactive(&rt),
|
|
||||||
"list" => list(&rt),
|
|
||||||
_ => {
|
|
||||||
debug!("Unknown command"); // More error handling
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use clap::{Arg, App, SubCommand};
|
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|
||||||
app
|
|
||||||
.arg(Arg::with_name("increment")
|
|
||||||
.long("inc")
|
|
||||||
.short("i")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Increment a counter")
|
|
||||||
.value_name("COUNTER"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("decrement")
|
|
||||||
.long("dec")
|
|
||||||
.short("d")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Decrement a counter")
|
|
||||||
.value_name("COUNTER"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("reset")
|
|
||||||
.long("reset")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Reset a counter")
|
|
||||||
.value_name("COUNTER"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("set")
|
|
||||||
.long("set")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Set a counter")
|
|
||||||
.value_name("COUNTER"))
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("create")
|
|
||||||
.about("Create a counter")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("name")
|
|
||||||
.long("name")
|
|
||||||
.short("n")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("Create counter with this name")
|
|
||||||
.value_name("NAME"))
|
|
||||||
.arg(Arg::with_name("initval")
|
|
||||||
.long("init")
|
|
||||||
.short("i")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Initial value")
|
|
||||||
.value_name("VALUE"))
|
|
||||||
.arg(Arg::with_name("unit")
|
|
||||||
.long("unit")
|
|
||||||
.short("u")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("measurement unit")
|
|
||||||
.value_name("UNIT")))
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("delete")
|
|
||||||
.about("Delete a counter")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("name")
|
|
||||||
.long("name")
|
|
||||||
.short("n")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("Create counter with this name")
|
|
||||||
.value_name("NAME")))
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("list")
|
|
||||||
.about("List counters")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("name")
|
|
||||||
.long("name")
|
|
||||||
.short("n")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("List counters with this name (foo/bar and baz/bar would match 'bar')")
|
|
||||||
.value_name("NAME"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("greater-than")
|
|
||||||
.long("greater")
|
|
||||||
.short("g")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("List counters which are greater than VALUE")
|
|
||||||
.value_name("VALUE"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("lower-than")
|
|
||||||
.long("lower")
|
|
||||||
.short("l")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("List counters which are lower than VALUE")
|
|
||||||
.value_name("VALUE"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("equals")
|
|
||||||
.long("equal")
|
|
||||||
.short("e")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("List counters which equal VALUE")
|
|
||||||
.value_name("VALUE"))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("interactive")
|
|
||||||
.about("Interactively count things")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("spec")
|
|
||||||
.long("spec")
|
|
||||||
.short("s")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.required(true)
|
|
||||||
.help("Specification for key-bindings. Use <KEY>=<VALUE> where KEY is the
|
|
||||||
key to bind (single character) and VALUE is the path to the counter to bind
|
|
||||||
to.")
|
|
||||||
.value_name("KEY=VALUE")))
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "imag-diary"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Part of the imag core distribution: imag-diary command"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
chrono = "0.2"
|
|
||||||
version = "2.0"
|
|
||||||
clap = "2.*"
|
|
||||||
log = "0.3"
|
|
||||||
|
|
||||||
[dependencies.libimagrt]
|
|
||||||
path = "../libimagrt"
|
|
||||||
|
|
||||||
[dependencies.libimagdiary]
|
|
||||||
path = "../libimagdiary"
|
|
||||||
|
|
||||||
[dependencies.libimagentryedit]
|
|
||||||
path = "../libimagentryedit"
|
|
||||||
|
|
||||||
[dependencies.libimagentrylist]
|
|
||||||
path = "../libimagentrylist"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimaginteraction]
|
|
||||||
path = "../libimaginteraction"
|
|
||||||
|
|
||||||
[dependencies.libimagutil]
|
|
||||||
path = "../libimagutil"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagtimeui]
|
|
||||||
path = "../libimagtimeui"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/04020-module-diary.md
|
|
|
@ -1,123 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
|
||||||
use libimagdiary::diaryid::DiaryId;
|
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
|
||||||
use libimagdiary::error::MapErrInto;
|
|
||||||
use libimagentryedit::edit::Edit;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::trace_error;
|
|
||||||
use libimagdiary::entry::Entry;
|
|
||||||
use libimagdiary::result::Result;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
|
|
||||||
use util::get_diary_name;
|
|
||||||
|
|
||||||
pub fn create(rt: &Runtime) {
|
|
||||||
let diaryname = get_diary_name(rt)
|
|
||||||
.unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
|
|
||||||
|
|
||||||
let prevent_edit = rt.cli().subcommand_matches("create").unwrap().is_present("no-edit");
|
|
||||||
|
|
||||||
fn create_entry<'a>(diary: &'a Diary, rt: &Runtime) -> Result<Entry<'a>> {
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
let create = rt.cli().subcommand_matches("create").unwrap();
|
|
||||||
if !create.is_present("timed") {
|
|
||||||
debug!("Creating non-timed entry");
|
|
||||||
diary.new_entry_today()
|
|
||||||
} else {
|
|
||||||
let id = match create.value_of("timed") {
|
|
||||||
Some("h") | Some("hourly") => {
|
|
||||||
debug!("Creating hourly-timed entry");
|
|
||||||
let time = DiaryId::now(String::from(diary.name()));
|
|
||||||
let hr = create
|
|
||||||
.value_of("hour")
|
|
||||||
.map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
|
|
||||||
.and_then(|s| {
|
|
||||||
FromStr::from_str(s)
|
|
||||||
.map_err(|_| warn!("Could not parse hour: '{}'", s))
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.unwrap_or(time.hour());
|
|
||||||
|
|
||||||
time.with_hour(hr).with_minute(0)
|
|
||||||
},
|
|
||||||
|
|
||||||
Some("m") | Some("minutely") => {
|
|
||||||
debug!("Creating minutely-timed entry");
|
|
||||||
let time = DiaryId::now(String::from(diary.name()));
|
|
||||||
let hr = create
|
|
||||||
.value_of("hour")
|
|
||||||
.map(|h| { debug!("hour = {:?}", h); h })
|
|
||||||
.and_then(|s| {
|
|
||||||
FromStr::from_str(s)
|
|
||||||
.map_err(|_| warn!("Could not parse hour: '{}'", s))
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.unwrap_or(time.hour());
|
|
||||||
|
|
||||||
let min = create
|
|
||||||
.value_of("minute")
|
|
||||||
.map(|m| { debug!("minute = {:?}", m); m })
|
|
||||||
.and_then(|s| {
|
|
||||||
FromStr::from_str(s)
|
|
||||||
.map_err(|_| warn!("Could not parse minute: '{}'", s))
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.unwrap_or(time.minute());
|
|
||||||
|
|
||||||
time.with_hour(hr).with_minute(min)
|
|
||||||
},
|
|
||||||
|
|
||||||
Some(_) => {
|
|
||||||
warn!("Timed creation failed: Unknown spec '{}'",
|
|
||||||
create.value_of("timed").unwrap());
|
|
||||||
exit(1);
|
|
||||||
},
|
|
||||||
|
|
||||||
None => warn_exit("Unexpected error, cannot continue", 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
diary.new_entry_by_id(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let diary = Diary::open(rt.store(), &diaryname[..]);
|
|
||||||
let res = create_entry(&diary, rt)
|
|
||||||
.and_then(|mut entry| {
|
|
||||||
if prevent_edit {
|
|
||||||
debug!("Not editing new diary entry");
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
debug!("Editing new diary entry");
|
|
||||||
entry.edit_content(rt).map_err_into(DEK::DiaryEditError)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Err(e) = res {
|
|
||||||
trace_error(&e);
|
|
||||||
} else {
|
|
||||||
info!("Ok!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use chrono::naive::datetime::NaiveDateTime;
|
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
|
||||||
use libimagdiary::diaryid::DiaryId;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::trace_error_exit;
|
|
||||||
use libimagtimeui::datetime::DateTime;
|
|
||||||
use libimagtimeui::parse::Parse;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
|
|
||||||
use util::get_diary_name;
|
|
||||||
|
|
||||||
pub fn delete(rt: &Runtime) {
|
|
||||||
use libimaginteraction::ask::ask_bool;
|
|
||||||
|
|
||||||
let diaryname = get_diary_name(rt)
|
|
||||||
.unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
|
|
||||||
|
|
||||||
let diary = Diary::open(rt.store(), &diaryname[..]);
|
|
||||||
debug!("Diary opened: {:?}", diary);
|
|
||||||
|
|
||||||
let datetime : Option<NaiveDateTime> = rt
|
|
||||||
.cli()
|
|
||||||
.subcommand_matches("delete")
|
|
||||||
.unwrap()
|
|
||||||
.value_of("datetime")
|
|
||||||
.map(|dt| { debug!("DateTime = {:?}", dt); dt })
|
|
||||||
.and_then(DateTime::parse)
|
|
||||||
.map(|dt| dt.into());
|
|
||||||
|
|
||||||
let to_del = match datetime {
|
|
||||||
Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
|
|
||||||
None => diary.get_youngest_entry(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_del = match to_del {
|
|
||||||
Some(Ok(e)) => e,
|
|
||||||
|
|
||||||
Some(Err(e)) => trace_error_exit(&e, 1),
|
|
||||||
None => warn_exit("No entry", 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) {
|
|
||||||
info!("Aborting delete action");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = diary.delete_entry(to_del) {
|
|
||||||
trace_error_exit(&e, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Ok!");
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use chrono::naive::datetime::NaiveDateTime;
|
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
|
||||||
use libimagdiary::diaryid::DiaryId;
|
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
|
||||||
use libimagdiary::error::MapErrInto;
|
|
||||||
use libimagentryedit::edit::Edit;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
use libimagtimeui::datetime::DateTime;
|
|
||||||
use libimagtimeui::parse::Parse;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
|
|
||||||
use util::get_diary_name;
|
|
||||||
|
|
||||||
pub fn edit(rt: &Runtime) {
|
|
||||||
let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1));
|
|
||||||
let diary = Diary::open(rt.store(), &diaryname[..]);
|
|
||||||
|
|
||||||
let datetime : Option<NaiveDateTime> = rt
|
|
||||||
.cli()
|
|
||||||
.subcommand_matches("edit")
|
|
||||||
.unwrap()
|
|
||||||
.value_of("datetime")
|
|
||||||
.and_then(DateTime::parse)
|
|
||||||
.map(|dt| dt.into());
|
|
||||||
|
|
||||||
let to_edit = match datetime {
|
|
||||||
Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
|
|
||||||
None => diary.get_youngest_entry(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match to_edit {
|
|
||||||
Some(Ok(mut e)) => e.edit_content(rt).map_err_into(DEK::IOError),
|
|
||||||
|
|
||||||
Some(Err(e)) => Err(e),
|
|
||||||
None => Err(DEK::EntryNotInDiary.into_error()),
|
|
||||||
}
|
|
||||||
.map_err_trace().ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
|
||||||
use libimagdiary::error::MapErrInto;
|
|
||||||
use libimagentrylist::listers::core::CoreLister;
|
|
||||||
use libimagentrylist::lister::Lister;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagstore::store::Entry;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagutil::debug_result::*;
|
|
||||||
|
|
||||||
use util::get_diary_name;
|
|
||||||
|
|
||||||
pub fn list(rt: &Runtime) {
|
|
||||||
let diaryname = get_diary_name(rt)
|
|
||||||
.unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
|
|
||||||
|
|
||||||
fn entry_to_location_listing_string(e: &Entry) -> String {
|
|
||||||
e.get_location().clone()
|
|
||||||
.without_base()
|
|
||||||
.to_str()
|
|
||||||
.map_err_trace()
|
|
||||||
.unwrap_or(String::from("<<Path Parsing Error>>"))
|
|
||||||
}
|
|
||||||
|
|
||||||
let diary = Diary::open(rt.store(), &diaryname[..]);
|
|
||||||
debug!("Diary opened: {:?}", diary);
|
|
||||||
diary.entries()
|
|
||||||
.and_then(|es| {
|
|
||||||
debug!("Iterator for listing: {:?}", es);
|
|
||||||
|
|
||||||
let es = es
|
|
||||||
.filter_map(|entry| {
|
|
||||||
entry
|
|
||||||
.map_dbg(|e| format!("Filtering: {:?}", e))
|
|
||||||
.map_err_trace() // error tracing here
|
|
||||||
.ok() // so we can ignore errors here
|
|
||||||
})
|
|
||||||
.map(|e| e.into());
|
|
||||||
|
|
||||||
CoreLister::new(&entry_to_location_listing_string)
|
|
||||||
.list(es)
|
|
||||||
.map_err_into(DEK::IOError)
|
|
||||||
})
|
|
||||||
.map_dbg_str("Ok")
|
|
||||||
.map_err_trace()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_must_use,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
#[macro_use] extern crate version;
|
|
||||||
extern crate clap;
|
|
||||||
extern crate chrono;
|
|
||||||
|
|
||||||
extern crate libimagdiary;
|
|
||||||
extern crate libimagentryedit;
|
|
||||||
extern crate libimagentrylist;
|
|
||||||
extern crate libimaginteraction;
|
|
||||||
extern crate libimagrt;
|
|
||||||
extern crate libimagstore;
|
|
||||||
extern crate libimagutil;
|
|
||||||
extern crate libimagtimeui;
|
|
||||||
#[macro_use] extern crate libimagerror;
|
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
|
|
||||||
mod create;
|
|
||||||
mod delete;
|
|
||||||
mod edit;
|
|
||||||
mod list;
|
|
||||||
mod ui;
|
|
||||||
mod util;
|
|
||||||
mod view;
|
|
||||||
|
|
||||||
use create::create;
|
|
||||||
use delete::delete;
|
|
||||||
use edit::edit;
|
|
||||||
use list::list;
|
|
||||||
use ui::build_ui;
|
|
||||||
use view::view;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let name = "imag-diary";
|
|
||||||
let version = &version!()[..];
|
|
||||||
let about = "Personal Diary/Diaries";
|
|
||||||
let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
|
|
||||||
let rt = {
|
|
||||||
let rt = Runtime::new(ui);
|
|
||||||
if rt.is_ok() {
|
|
||||||
rt.unwrap()
|
|
||||||
} else {
|
|
||||||
println!("Could not set up Runtime");
|
|
||||||
println!("{:?}", rt.err().unwrap());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_name()
|
|
||||||
.map(|name| {
|
|
||||||
debug!("Call {}", name);
|
|
||||||
match name {
|
|
||||||
"create" => create(&rt),
|
|
||||||
"delete" => delete(&rt),
|
|
||||||
"edit" => edit(&rt),
|
|
||||||
"list" => list(&rt),
|
|
||||||
"view" => view(&rt),
|
|
||||||
_ => {
|
|
||||||
debug!("Unknown command"); // More error handling
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use clap::{Arg, ArgGroup, App, SubCommand};
|
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|
||||||
app
|
|
||||||
.arg(Arg::with_name("diaryname")
|
|
||||||
.long("diary")
|
|
||||||
.short("d")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Use other than default diary"))
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("create")
|
|
||||||
.about("Create a diary entry")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("no-edit")
|
|
||||||
.long("no-edit")
|
|
||||||
.short("e")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("Do not edit after creating"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("timed")
|
|
||||||
.long("timed")
|
|
||||||
.short("t")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("By default, one entry is created per day. With --timed=h[ourly] or
|
|
||||||
--timed=m[inutely] one can create per-hour and per-minute entries (more like
|
|
||||||
a microblog then"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("hour")
|
|
||||||
.long("hour")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("When using --timed, override the hour component"))
|
|
||||||
.arg(Arg::with_name("minute")
|
|
||||||
.long("minute")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("When using --timed, override the minute component"))
|
|
||||||
|
|
||||||
// When using --hour or --minute, --timed must be present
|
|
||||||
.group(ArgGroup::with_name("timing-hourly")
|
|
||||||
.args(&["hour"])
|
|
||||||
.requires("timed"))
|
|
||||||
.group(ArgGroup::with_name("timing-minutely")
|
|
||||||
.args(&["minute"])
|
|
||||||
.requires("timed"))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("edit")
|
|
||||||
.about("Edit a diary entry")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("datetime")
|
|
||||||
.long("datetime")
|
|
||||||
.short("d")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Specify the date and time which entry should be edited. If none is
|
|
||||||
specified, the last entry is edited. If the diary entry does not exist for
|
|
||||||
this time, this fails. Format: YYYY-MM-DDT[HH[:mm[:ss]]]"))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("list")
|
|
||||||
.about("List diary entries")
|
|
||||||
.version("0.1"))
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("delete")
|
|
||||||
.about("Delete a diary entry")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("datetime")
|
|
||||||
.long("datetime")
|
|
||||||
.short("d")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(false)
|
|
||||||
.help("Specify the date and time which entry should be deleted. If none is
|
|
||||||
specified, the last entry is deleted. If the diary entry does not exist for
|
|
||||||
this time, this fails. Format: YYYY-MM-DDT[HH[:mm[:ss]]]"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("select")
|
|
||||||
.long("select")
|
|
||||||
.short("s")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("Use interactive selection"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("yes")
|
|
||||||
.long("yes")
|
|
||||||
.short("y")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("Do not ask for confirmation."))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("view")
|
|
||||||
.about("View entries, currently only supports plain viewing")
|
|
||||||
.version("0.1")
|
|
||||||
|
|
||||||
.arg(Arg::with_name("show-header")
|
|
||||||
.long("header")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("Show the header when printing the entries"))
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
|
|
||||||
pub fn get_diary_name(rt: &Runtime) -> Option<String> {
|
|
||||||
use libimagdiary::config::get_default_diary_name;
|
|
||||||
|
|
||||||
get_default_diary_name(rt)
|
|
||||||
.or(rt.cli().value_of("diaryname").map(String::from))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
|
||||||
use libimagdiary::viewer::DiaryViewer as DV;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
|
|
||||||
use util::get_diary_name;
|
|
||||||
|
|
||||||
pub fn view(rt: &Runtime) {
|
|
||||||
let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1));
|
|
||||||
let diary = Diary::open(rt.store(), &diaryname[..]);
|
|
||||||
let hdr = rt.cli().subcommand_matches("view").unwrap().is_present("show-header");
|
|
||||||
|
|
||||||
diary.entries()
|
|
||||||
.and_then(|entries| DV::new(hdr).view_entries(entries.into_iter().filter_map(Result::ok)))
|
|
||||||
.map_err_trace()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "imag-mail"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
semver = "0.5"
|
|
||||||
clap = "2.*"
|
|
||||||
log = "0.3"
|
|
||||||
version = "2.0.1"
|
|
||||||
toml = "0.2.*"
|
|
||||||
url = "1.2"
|
|
||||||
|
|
||||||
[dependencies.libimagrt]
|
|
||||||
path = "../libimagrt"
|
|
||||||
|
|
||||||
[dependencies.libimagmail]
|
|
||||||
path = "../libimagmail"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagutil]
|
|
||||||
path = "../libimagutil"
|
|
||||||
|
|
||||||
[dependencies.libimagref]
|
|
||||||
path = "../libimagref"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/04020-module-mails.md
|
|
|
@ -1,151 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
extern crate semver;
|
|
||||||
extern crate clap;
|
|
||||||
extern crate toml;
|
|
||||||
extern crate url;
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
#[macro_use] extern crate version;
|
|
||||||
|
|
||||||
extern crate libimagrt;
|
|
||||||
extern crate libimagmail;
|
|
||||||
extern crate libimagerror;
|
|
||||||
extern crate libimagutil;
|
|
||||||
extern crate libimagref;
|
|
||||||
|
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
|
|
||||||
use libimagmail::mail::Mail;
|
|
||||||
use libimagref::reference::Ref;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
|
||||||
use libimagutil::debug_result::*;
|
|
||||||
use libimagutil::info_result::*;
|
|
||||||
|
|
||||||
mod ui;
|
|
||||||
|
|
||||||
use ui::build_ui;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let rt = generate_runtime_setup("imag-mail",
|
|
||||||
&version!()[..],
|
|
||||||
"Mail collection tool",
|
|
||||||
build_ui);
|
|
||||||
|
|
||||||
rt.cli()
|
|
||||||
.subcommand_name()
|
|
||||||
.map(|name| {
|
|
||||||
debug!("Call {}", name);
|
|
||||||
match name {
|
|
||||||
"import-mail" => import_mail(&rt),
|
|
||||||
"list" => list(&rt),
|
|
||||||
"mail-store" => mail_store(&rt),
|
|
||||||
_ => debug!("Unknown command") // More error handling
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn import_mail(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("import-mail").unwrap();
|
|
||||||
let path = scmd.value_of("path").unwrap(); // enforced by clap
|
|
||||||
|
|
||||||
Mail::import_from_path(rt.store(), path)
|
|
||||||
.map_err_trace()
|
|
||||||
.map_info_str("Ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list(rt: &Runtime) {
|
|
||||||
use libimagmail::error::MailErrorKind as MEK;
|
|
||||||
use libimagmail::error::MapErrInto;
|
|
||||||
|
|
||||||
let scmd = rt.cli().subcommand_matches("list").unwrap();
|
|
||||||
let do_check_dead = scmd.is_present("check-dead");
|
|
||||||
let do_check_changed = scmd.is_present("check-changed");
|
|
||||||
let do_check_changed_content = scmd.is_present("check-changed-content");
|
|
||||||
let do_check_changed_permiss = scmd.is_present("check-changed-permissions");
|
|
||||||
let store = rt.store();
|
|
||||||
|
|
||||||
let iter = match store.retrieve_for_module("ref") {
|
|
||||||
Ok(iter) => iter.filter_map(|id| {
|
|
||||||
Ref::get(store, id)
|
|
||||||
.map_err_into(MEK::RefHandlingError)
|
|
||||||
.and_then(|rf| Mail::from_ref(rf))
|
|
||||||
.map_err_trace()
|
|
||||||
.ok()
|
|
||||||
}),
|
|
||||||
Err(e) => trace_error_exit(&e, 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
fn list_mail(m: Mail) {
|
|
||||||
let id = match m.get_message_id() {
|
|
||||||
Ok(Some(f)) => f,
|
|
||||||
Ok(None) => "<no id>".to_owned(),
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
"<error>".to_owned()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let from = match m.get_from() {
|
|
||||||
Ok(Some(f)) => f,
|
|
||||||
Ok(None) => "<no from>".to_owned(),
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
"<error>".to_owned()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let to = match m.get_to() {
|
|
||||||
Ok(Some(f)) => f,
|
|
||||||
Ok(None) => "<no to>".to_owned(),
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
"<error>".to_owned()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let subject = match m.get_subject() {
|
|
||||||
Ok(Some(f)) => f,
|
|
||||||
Ok(None) => "<no subject>".to_owned(),
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
"<error>".to_owned()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("Mail: {id}\n\tFrom: {from}\n\tTo: {to}\n\t{subj}\n",
|
|
||||||
from = from,
|
|
||||||
id = id,
|
|
||||||
subj = subject,
|
|
||||||
to = to
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement lister type in libimagmail for this
|
|
||||||
for mail in iter {
|
|
||||||
list_mail(mail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mail_store(rt: &Runtime) {
|
|
||||||
let scmd = rt.cli().subcommand_matches("mail-store").unwrap();
|
|
||||||
error!("This feature is currently not implemented.");
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use clap::{Arg, ArgGroup, App, SubCommand};
|
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|
||||||
app
|
|
||||||
.subcommand(SubCommand::with_name("import-mail")
|
|
||||||
.about("Import a mail (create a reference to it) (Maildir)")
|
|
||||||
.version("0.1")
|
|
||||||
.arg(Arg::with_name("path")
|
|
||||||
.long("path")
|
|
||||||
.short("p")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("Path to the mail file or a directory which is then searched recursively")
|
|
||||||
.value_name("PATH"))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("list")
|
|
||||||
.about("List all stored references to mails")
|
|
||||||
.version("0.1")
|
|
||||||
|
|
||||||
// TODO: Thee following four arguments are the same as in imag-ref.
|
|
||||||
// We should make these importable from libimagref.
|
|
||||||
|
|
||||||
.arg(Arg::with_name("check-dead")
|
|
||||||
.long("check-dead")
|
|
||||||
.short("d")
|
|
||||||
.help("Check each reference whether it is dead"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("check-changed")
|
|
||||||
.long("check-changed")
|
|
||||||
.short("c")
|
|
||||||
.help("Check whether a reference had changed (content or permissions)"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("check-changed-content")
|
|
||||||
.long("check-changed-content")
|
|
||||||
.short("C")
|
|
||||||
.help("Check whether the content of the referenced file changed"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("check-changed-permissions")
|
|
||||||
.long("check-changed-perms")
|
|
||||||
.short("P")
|
|
||||||
.help("Check whether the permissions of the referenced file changed"))
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("mail-store")
|
|
||||||
.about("Operations on (subsets of) all mails")
|
|
||||||
.version("0.1")
|
|
||||||
.subcommand(SubCommand::with_name("update-refs")
|
|
||||||
.about("Create references based on Message-IDs for all loaded mails")
|
|
||||||
.version("0.1"))
|
|
||||||
// TODO: We really should be able to filter here.
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
[package]
|
|
||||||
authors = ["mario <mario-krehl@gmx.de>"]
|
|
||||||
name = "imag-todo"
|
|
||||||
version = "0.2.0"
|
|
||||||
|
|
||||||
description = "Part of the imag core distribution: imag-todo command"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
clap = ">=2.17"
|
|
||||||
glob = "0.2.11"
|
|
||||||
log = "0.3.6"
|
|
||||||
semver = "0.5.1"
|
|
||||||
serde_json = "0.8.3"
|
|
||||||
task-hookrs = "0.2.2"
|
|
||||||
toml = "0.2.*"
|
|
||||||
version = "2.0.1"
|
|
||||||
|
|
||||||
[dependencies.libimagrt]
|
|
||||||
path = "../libimagrt"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagtodo]
|
|
||||||
path = "../libimagtodo"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
|
@ -1,4 +0,0 @@
|
||||||
#/!usr/bin/env bash
|
|
||||||
|
|
||||||
imag todo tw-hook --add
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#/!usr/bin/env bash
|
|
||||||
|
|
||||||
imag todo tw-hook --delete
|
|
||||||
|
|
|
@ -1,138 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
extern crate clap;
|
|
||||||
extern crate glob;
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate semver;
|
|
||||||
extern crate toml;
|
|
||||||
#[macro_use] extern crate version;
|
|
||||||
|
|
||||||
extern crate task_hookrs;
|
|
||||||
|
|
||||||
extern crate libimagrt;
|
|
||||||
extern crate libimagstore;
|
|
||||||
extern crate libimagerror;
|
|
||||||
extern crate libimagtodo;
|
|
||||||
|
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
use std::io::stdin;
|
|
||||||
|
|
||||||
use toml::Value;
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
|
||||||
use libimagtodo::task::Task;
|
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
|
|
||||||
|
|
||||||
mod ui;
|
|
||||||
|
|
||||||
use ui::build_ui;
|
|
||||||
fn main() {
|
|
||||||
let rt = generate_runtime_setup("imag-todo",
|
|
||||||
&version!()[..],
|
|
||||||
"Interface with taskwarrior",
|
|
||||||
build_ui);
|
|
||||||
|
|
||||||
match rt.cli().subcommand_name() {
|
|
||||||
Some("tw-hook") => tw_hook(&rt),
|
|
||||||
Some("list") => list(&rt),
|
|
||||||
None => {
|
|
||||||
warn!("No command");
|
|
||||||
},
|
|
||||||
_ => unreachable!(),
|
|
||||||
} // end match scmd
|
|
||||||
} // end main
|
|
||||||
|
|
||||||
fn tw_hook(rt: &Runtime) {
|
|
||||||
let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
|
|
||||||
if subcmd.is_present("add") {
|
|
||||||
let stdin = stdin();
|
|
||||||
let stdin = stdin.lock(); // implements BufRead which is required for `Task::import()`
|
|
||||||
|
|
||||||
match Task::import(rt.store(), stdin) {
|
|
||||||
Ok((_, line, uuid)) => println!("{}\nTask {} stored in imag", line, uuid),
|
|
||||||
Err(e) => trace_error_exit(&e, 1),
|
|
||||||
}
|
|
||||||
} else if subcmd.is_present("delete") {
|
|
||||||
// The used hook is "on-modify". This hook gives two json-objects
|
|
||||||
// per usage und wants one (the second one) back.
|
|
||||||
let stdin = stdin();
|
|
||||||
Task::delete_by_imports(rt.store(), stdin.lock()).map_err_trace().ok();
|
|
||||||
} else {
|
|
||||||
// Should not be possible, as one argument is required via
|
|
||||||
// ArgGroup
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list(rt: &Runtime) {
|
|
||||||
let subcmd = rt.cli().subcommand_matches("list").unwrap();
|
|
||||||
let verbose = subcmd.is_present("verbose");
|
|
||||||
|
|
||||||
let res = Task::all(rt.store()) // get all tasks
|
|
||||||
.map(|iter| { // and if this succeeded
|
|
||||||
// filter out the ones were we can read the uuid
|
|
||||||
let uuids : Vec<_> = iter.filter_map(|t| match t {
|
|
||||||
Ok(v) => match v.get_header().read("todo.uuid") {
|
|
||||||
Ok(Some(Value::String(ref u))) => Some(u.clone()),
|
|
||||||
Ok(Some(_)) => {
|
|
||||||
warn!("Header type error");
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Ok(None) => None,
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// compose a `task` call with them, ...
|
|
||||||
let outstring = if verbose { // ... if verbose
|
|
||||||
let output = Command::new("task")
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.args(&uuids)
|
|
||||||
.spawn()
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
trace_error(&e);
|
|
||||||
panic!("Failed to execute `task` on the commandline. I'm dying now.");
|
|
||||||
})
|
|
||||||
.wait_with_output()
|
|
||||||
.unwrap_or_else(|e| panic!("failed to unwrap output: {}", e));
|
|
||||||
|
|
||||||
String::from_utf8(output.stdout)
|
|
||||||
.unwrap_or_else(|e| panic!("failed to execute: {}", e))
|
|
||||||
} else { // ... else just join them
|
|
||||||
uuids.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
// and then print that
|
|
||||||
println!("{}", outstring);
|
|
||||||
});
|
|
||||||
|
|
||||||
res.map_err_trace().ok();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use clap::{Arg, App, ArgGroup, SubCommand};
|
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|
||||||
app
|
|
||||||
.subcommand(SubCommand::with_name("tw-hook")
|
|
||||||
.about("For use in a taskwarrior hook")
|
|
||||||
.version("0.1")
|
|
||||||
|
|
||||||
.arg(Arg::with_name("add")
|
|
||||||
.long("add")
|
|
||||||
.short("a")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("For use in an on-add hook"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("delete")
|
|
||||||
.long("delete")
|
|
||||||
.short("d")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("For use in an on-delete hook"))
|
|
||||||
|
|
||||||
.group(ArgGroup::with_name("taskwarrior hooks")
|
|
||||||
.args(&[ "add",
|
|
||||||
"delete",
|
|
||||||
])
|
|
||||||
.required(true))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("list")
|
|
||||||
.about("List all tasks")
|
|
||||||
.version("0.1")
|
|
||||||
|
|
||||||
.arg(Arg::with_name("verbose")
|
|
||||||
.long("verbose")
|
|
||||||
.short("v")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("Asks taskwarrior for all the details")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libimagbookmark"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Library for the imag core distribution"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
log = "0.3"
|
|
||||||
semver = "0.5"
|
|
||||||
url = "1.2"
|
|
||||||
regex = "0.1"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagentrylink]
|
|
||||||
path = "../libimagentrylink"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/05100-lib-bookmark.md
|
|
|
@ -1,222 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
//! BookmarkCollection module
|
|
||||||
//!
|
|
||||||
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
|
|
||||||
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
|
|
||||||
//!
|
|
||||||
//! The BookmarkCollection type offers helper functions to get all links or such things.
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use error::BookmarkErrorKind as BEK;
|
|
||||||
use error::MapErrInto;
|
|
||||||
use result::Result;
|
|
||||||
use module_path::ModuleEntryPath;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
use libimagstore::storeid::IntoStoreId;
|
|
||||||
use libimagstore::store::FileLockEntry;
|
|
||||||
use libimagentrylink::external::ExternalLinker;
|
|
||||||
use libimagentrylink::external::iter::UrlIter;
|
|
||||||
use libimagentrylink::internal::InternalLinker;
|
|
||||||
use libimagentrylink::internal::Link as StoreLink;
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use link::Link;
|
|
||||||
|
|
||||||
use self::iter::LinksMatchingRegexIter;
|
|
||||||
|
|
||||||
pub struct BookmarkCollection<'a> {
|
|
||||||
fle: FileLockEntry<'a>,
|
|
||||||
store: &'a Store,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// {Internal, External}Linker is implemented as Deref is implemented
|
|
||||||
impl<'a> Deref for BookmarkCollection<'a> {
|
|
||||||
type Target = FileLockEntry<'a>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &FileLockEntry<'a> {
|
|
||||||
&self.fle
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DerefMut for BookmarkCollection<'a> {
|
|
||||||
|
|
||||||
fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
|
|
||||||
&mut self.fle
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> BookmarkCollection<'a> {
|
|
||||||
|
|
||||||
pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
|
|
||||||
ModuleEntryPath::new(name)
|
|
||||||
.into_storeid()
|
|
||||||
.and_then(|id| store.create(id))
|
|
||||||
.map(|fle| {
|
|
||||||
BookmarkCollection {
|
|
||||||
fle: fle,
|
|
||||||
store: store,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map_err_into(BEK::StoreReadError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
|
|
||||||
ModuleEntryPath::new(name)
|
|
||||||
.into_storeid()
|
|
||||||
.and_then(|id| store.get(id))
|
|
||||||
.map_err_into(BEK::StoreReadError)
|
|
||||||
.and_then(|fle| {
|
|
||||||
match fle {
|
|
||||||
None => Err(BEK::CollectionNotFound.into_error()),
|
|
||||||
Some(e) => Ok(BookmarkCollection {
|
|
||||||
fle: e,
|
|
||||||
store: store,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete(store: &Store, name: &str) -> Result<()> {
|
|
||||||
ModuleEntryPath::new(name)
|
|
||||||
.into_storeid()
|
|
||||||
.and_then(|id| store.delete(id))
|
|
||||||
.map_err_into(BEK::StoreReadError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn links(&self) -> Result<UrlIter> {
|
|
||||||
self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
|
|
||||||
use libimagentrylink::external::is_external_link_storeid;
|
|
||||||
|
|
||||||
self.fle
|
|
||||||
.get_internal_links()
|
|
||||||
.map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
|
|
||||||
.map_err_into(BEK::StoreReadError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_link(&mut self, l: Link) -> Result<()> {
|
|
||||||
use link::IntoUrl;
|
|
||||||
|
|
||||||
l.into_url()
|
|
||||||
.and_then(|url| self.add_external_link(self.store, url).map_err_into(BEK::LinkingError))
|
|
||||||
.map_err_into(BEK::LinkError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_links_matching(&self, r: Regex) -> Result<LinksMatchingRegexIter<'a>> {
|
|
||||||
use self::iter::IntoLinksMatchingRegexIter;
|
|
||||||
|
|
||||||
self.get_external_links(self.store)
|
|
||||||
.map_err_into(BEK::LinkError)
|
|
||||||
.map(|iter| iter.matching_regex(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_link(&mut self, l: Link) -> Result<()> {
|
|
||||||
use link::IntoUrl;
|
|
||||||
|
|
||||||
l.into_url()
|
|
||||||
.and_then(|url| {
|
|
||||||
self.remove_external_link(self.store, url).map_err_into(BEK::LinkingError)
|
|
||||||
})
|
|
||||||
.map_err_into(BEK::LinkError)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod iter {
|
|
||||||
use link::Link;
|
|
||||||
use result::Result;
|
|
||||||
use error::{MapErrInto, BookmarkErrorKind as BEK};
|
|
||||||
|
|
||||||
pub struct LinkIter<I>(I)
|
|
||||||
where I: Iterator<Item = Link>;
|
|
||||||
|
|
||||||
impl<I: Iterator<Item = Link>> LinkIter<I> {
|
|
||||||
pub fn new(i: I) -> LinkIter<I> {
|
|
||||||
LinkIter(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator<Item = Link>> Iterator for LinkIter<I> {
|
|
||||||
type Item = Link;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.0.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> From<I> for LinkIter<I> where I: Iterator<Item = Link> {
|
|
||||||
fn from(i: I) -> LinkIter<I> {
|
|
||||||
LinkIter(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use libimagentrylink::external::iter::UrlIter;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
pub struct LinksMatchingRegexIter<'a>(UrlIter<'a>, Regex);
|
|
||||||
|
|
||||||
impl<'a> LinksMatchingRegexIter<'a> {
|
|
||||||
pub fn new(i: UrlIter<'a>, r: Regex) -> LinksMatchingRegexIter<'a> {
|
|
||||||
LinksMatchingRegexIter(i, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for LinksMatchingRegexIter<'a> {
|
|
||||||
type Item = Result<Link>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
loop {
|
|
||||||
let n = match self.0.next() {
|
|
||||||
Some(Ok(n)) => n,
|
|
||||||
Some(Err(e)) => return Some(Err(e).map_err_into(BEK::LinkError)),
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let s = n.into_string();
|
|
||||||
if self.1.is_match(&s[..]) {
|
|
||||||
return Some(Ok(Link::from(s)))
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IntoLinksMatchingRegexIter<'a> {
|
|
||||||
fn matching_regex(self, Regex) -> LinksMatchingRegexIter<'a>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoLinksMatchingRegexIter<'a> for UrlIter<'a> {
|
|
||||||
fn matching_regex(self, r: Regex) -> LinksMatchingRegexIter<'a> {
|
|
||||||
LinksMatchingRegexIter(self, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
generate_error_module!(
|
|
||||||
generate_error_types!(BookmarkError, BookmarkErrorKind,
|
|
||||||
StoreReadError => "Store read error",
|
|
||||||
LinkError => "Link error",
|
|
||||||
LinkParsingError => "Link parsing error",
|
|
||||||
LinkingError => "Error while linking",
|
|
||||||
CollectionNotFound => "Link-Collection not found"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::BookmarkError;
|
|
||||||
pub use self::error::BookmarkErrorKind;
|
|
||||||
pub use self::error::MapErrInto;
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
extern crate semver;
|
|
||||||
extern crate url;
|
|
||||||
extern crate regex;
|
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
|
||||||
#[macro_use] extern crate libimagerror;
|
|
||||||
extern crate libimagentrylink;
|
|
||||||
|
|
||||||
module_entry_path_mod!("bookmark");
|
|
||||||
|
|
||||||
pub mod collection;
|
|
||||||
pub mod error;
|
|
||||||
pub mod link;
|
|
||||||
pub mod result;
|
|
|
@ -1,76 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use result::Result;
|
|
||||||
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Link(String);
|
|
||||||
|
|
||||||
impl From<String> for Link {
|
|
||||||
|
|
||||||
fn from(s: String) -> Link {
|
|
||||||
Link(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Link {
|
|
||||||
|
|
||||||
fn from(s: &'a str) -> Link {
|
|
||||||
Link(String::from(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Link {
|
|
||||||
type Target = String;
|
|
||||||
|
|
||||||
fn deref(&self) -> &String {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Link {
|
|
||||||
|
|
||||||
fn deref_mut(&mut self) -> &mut String {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IntoUrl {
|
|
||||||
fn into_url(self) -> Result<Url>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoUrl for Link {
|
|
||||||
|
|
||||||
fn into_url(self) -> Result<Url> {
|
|
||||||
use error::BookmarkErrorKind as BEK;
|
|
||||||
use error::MapErrInto;
|
|
||||||
|
|
||||||
Url::parse(&self[..]).map_err_into(BEK::LinkParsingError)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::BookmarkError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, BookmarkError>;
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libimagcounter"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Library for the imag core distribution"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
log = "0.3"
|
|
||||||
toml = "0.2.*"
|
|
||||||
semver = "0.5"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/05100-lib-counter.md
|
|
|
@ -1,257 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use toml::Value;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
|
||||||
use libimagstore::store::FileLockEntry;
|
|
||||||
use libimagstore::storeid::StoreId;
|
|
||||||
use libimagstore::storeid::IntoStoreId;
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use module_path::ModuleEntryPath;
|
|
||||||
use result::Result;
|
|
||||||
use error::CounterError as CE;
|
|
||||||
use error::CounterErrorKind as CEK;
|
|
||||||
use error::error::MapErrInto;
|
|
||||||
|
|
||||||
pub type CounterName = String;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
|
||||||
pub struct CounterUnit(String);
|
|
||||||
|
|
||||||
impl Display for CounterUnit {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "({})", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CounterUnit {
|
|
||||||
pub fn new<S: Into<String>>(unit: S) -> CounterUnit {
|
|
||||||
CounterUnit(unit.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Counter<'a> {
|
|
||||||
fle: FileLockEntry<'a>,
|
|
||||||
unit: Option<CounterUnit>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Counter<'a> {
|
|
||||||
|
|
||||||
pub fn new(store: &Store, name: CounterName, init: i64) -> Result<Counter> {
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
debug!("Creating new counter: '{}' with value: {}", name, init);
|
|
||||||
let fle = {
|
|
||||||
let id = try!(ModuleEntryPath::new(name.clone())
|
|
||||||
.into_storeid()
|
|
||||||
.map_err_into(CEK::StoreWriteError));
|
|
||||||
let mut lockentry = try!(store.create(id).map_err_into(CEK::StoreWriteError));
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut entry = lockentry.deref_mut();
|
|
||||||
let mut header = entry.get_header_mut();
|
|
||||||
let setres = header.set("counter", Value::Table(BTreeMap::new()));
|
|
||||||
if setres.is_err() {
|
|
||||||
return Err(CEK::StoreWriteError.into_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let setres = header.set("counter.name", Value::String(name));
|
|
||||||
if setres.is_err() {
|
|
||||||
return Err(CEK::StoreWriteError.into_error())
|
|
||||||
}
|
|
||||||
|
|
||||||
let setres = header.set("counter.value", Value::Integer(init));
|
|
||||||
if setres.is_err() {
|
|
||||||
return Err(CEK::StoreWriteError.into_error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lockentry
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Counter { fle: fle, unit: None })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_unit(mut self, unit: Option<CounterUnit>) -> Result<Counter<'a>> {
|
|
||||||
self.unit = unit;
|
|
||||||
|
|
||||||
if let Some(u) = self.unit.clone() {
|
|
||||||
let mut header = self.fle.deref_mut().get_header_mut();
|
|
||||||
let setres = header.set("counter.unit", Value::String(u.0));
|
|
||||||
if setres.is_err() {
|
|
||||||
self.unit = None;
|
|
||||||
return Err(CEK::StoreWriteError.into_error())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inc(&mut self) -> Result<()> {
|
|
||||||
let mut header = self.fle.deref_mut().get_header_mut();
|
|
||||||
match header.read("counter.value") {
|
|
||||||
Ok(Some(Value::Integer(i))) => {
|
|
||||||
header.set("counter.value", Value::Integer(i + 1))
|
|
||||||
.map_err_into(CEK::StoreWriteError)
|
|
||||||
.map(|_| ())
|
|
||||||
},
|
|
||||||
Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))),
|
|
||||||
_ => Err(CE::new(CEK::StoreReadError, None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dec(&mut self) -> Result<()> {
|
|
||||||
let mut header = self.fle.deref_mut().get_header_mut();
|
|
||||||
match header.read("counter.value") {
|
|
||||||
Ok(Some(Value::Integer(i))) => {
|
|
||||||
header.set("counter.value", Value::Integer(i - 1))
|
|
||||||
.map_err_into(CEK::StoreWriteError)
|
|
||||||
.map(|_| ())
|
|
||||||
},
|
|
||||||
Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))),
|
|
||||||
_ => Err(CE::new(CEK::StoreReadError, None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) -> Result<()> {
|
|
||||||
self.set(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, v: i64) -> Result<()> {
|
|
||||||
let mut header = self.fle.deref_mut().get_header_mut();
|
|
||||||
header.set("counter.value", Value::Integer(v))
|
|
||||||
.map_err_into(CEK::StoreWriteError)
|
|
||||||
.map(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<CounterName> {
|
|
||||||
self.read_header_at("counter.name", |v| match v {
|
|
||||||
Some(Value::String(s)) => Ok(s),
|
|
||||||
_ => Err(CEK::HeaderTypeError.into_error()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value(&self) -> Result<i64> {
|
|
||||||
self.read_header_at("counter.value", |v| match v {
|
|
||||||
Some(Value::Integer(i)) => Ok(i),
|
|
||||||
_ => Err(CEK::HeaderTypeError.into_error()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unit(&self) -> Option<&CounterUnit> {
|
|
||||||
self.unit.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_unit(&self) -> Result<Option<CounterUnit>> {
|
|
||||||
self.read_header_at("counter.unit", |s| match s {
|
|
||||||
Some(Value::String(s)) => Ok(Some(CounterUnit::new(s))),
|
|
||||||
Some(_) => Err(CEK::HeaderTypeError.into_error()),
|
|
||||||
None => Ok(None),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_header_at<T, F>(&self, name: &str, f: F) -> Result<T>
|
|
||||||
where F: FnOnce(Option<Value>) -> Result<T>
|
|
||||||
{
|
|
||||||
self.fle.get_header().read(name).map_err_into(CEK::StoreWriteError).and_then(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(name: CounterName, store: &Store) -> Result<Counter> {
|
|
||||||
debug!("Loading counter: '{}'", name);
|
|
||||||
let id = try!(ModuleEntryPath::new(name)
|
|
||||||
.into_storeid()
|
|
||||||
.map_err_into(CEK::StoreWriteError));
|
|
||||||
Counter::from_storeid(store, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete(name: CounterName, store: &Store) -> Result<()> {
|
|
||||||
debug!("Deleting counter: '{}'", name);
|
|
||||||
let id = try!(ModuleEntryPath::new(name)
|
|
||||||
.into_storeid()
|
|
||||||
.map_err_into(CEK::StoreWriteError));
|
|
||||||
store.delete(id).map_err_into(CEK::StoreWriteError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn all_counters(store: &Store) -> Result<CounterIterator> {
|
|
||||||
store.retrieve_for_module("counter")
|
|
||||||
.map(|iter| CounterIterator::new(store, iter))
|
|
||||||
.map_err_into(CEK::StoreReadError)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
trait FromStoreId {
|
|
||||||
fn from_storeid(&Store, StoreId) -> Result<Counter>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromStoreId for Counter<'a> {
|
|
||||||
|
|
||||||
fn from_storeid(store: &Store, id: StoreId) -> Result<Counter> {
|
|
||||||
debug!("Loading counter from storeid: '{:?}'", id);
|
|
||||||
match store.retrieve(id) {
|
|
||||||
Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))),
|
|
||||||
Ok(c) => {
|
|
||||||
let mut counter = Counter { fle: c, unit: None };
|
|
||||||
counter.read_unit()
|
|
||||||
.map_err_into(CEK::StoreReadError)
|
|
||||||
.and_then(|u| {
|
|
||||||
counter.unit = u;
|
|
||||||
Ok(counter)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CounterIterator<'a> {
|
|
||||||
store: &'a Store,
|
|
||||||
iditer: StoreIdIterator,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CounterIterator<'a> {
|
|
||||||
|
|
||||||
pub fn new(store: &'a Store, iditer: StoreIdIterator) -> CounterIterator<'a> {
|
|
||||||
CounterIterator {
|
|
||||||
store: store,
|
|
||||||
iditer: iditer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for CounterIterator<'a> {
|
|
||||||
type Item = Result<Counter<'a>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<Counter<'a>>> {
|
|
||||||
self.iditer
|
|
||||||
.next()
|
|
||||||
.map(|id| Counter::from_storeid(self.store, id))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
generate_error_module!(
|
|
||||||
generate_error_types!(CounterError, CounterErrorKind,
|
|
||||||
StoreIdError => "StoreId error",
|
|
||||||
StoreReadError => "Store read error",
|
|
||||||
StoreWriteError => "Store write error",
|
|
||||||
HeaderTypeError => "Header type error",
|
|
||||||
HeaderFieldMissingError => "Header field missing error"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::CounterError;
|
|
||||||
pub use self::error::CounterErrorKind;
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
extern crate toml;
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
#[macro_use] extern crate semver;
|
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
|
||||||
#[macro_use] extern crate libimagerror;
|
|
||||||
|
|
||||||
module_entry_path_mod!("counter");
|
|
||||||
|
|
||||||
pub mod counter;
|
|
||||||
pub mod error;
|
|
||||||
pub mod result;
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::CounterError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, CounterError>;
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libimagdiary"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Library for the imag core distribution"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
chrono = "0.2"
|
|
||||||
log = "0.3"
|
|
||||||
semver = "0.5"
|
|
||||||
toml = "0.2.*"
|
|
||||||
regex = "0.1"
|
|
||||||
lazy_static = "0.2"
|
|
||||||
itertools = "0.5"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagutil]
|
|
||||||
path = "../libimagutil"
|
|
||||||
|
|
||||||
[dependencies.libimagrt]
|
|
||||||
path = "../libimagrt"
|
|
||||||
|
|
||||||
[dependencies.libimagentryedit]
|
|
||||||
path = "../libimagentryedit"
|
|
||||||
|
|
||||||
[dependencies.libimagentryview]
|
|
||||||
path = "../libimagentryview"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../doc/src/05100-lib-diary.md
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use toml::Value;
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
|
|
||||||
pub fn get_default_diary_name(rt: &Runtime) -> Option<String> {
|
|
||||||
get_diary_config_section(rt)
|
|
||||||
.and_then(|config| {
|
|
||||||
match config.lookup("default_diary") {
|
|
||||||
Some(&Value::String(ref s)) => Some(s.clone()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_diary_config_section<'a>(rt: &'a Runtime) -> Option<&'a Value> {
|
|
||||||
rt.config()
|
|
||||||
.map(|config| config.config())
|
|
||||||
.and_then(|config| config.lookup("diary"))
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
use libimagstore::storeid::IntoStoreId;
|
|
||||||
use libimagerror::trace::trace_error;
|
|
||||||
|
|
||||||
use chrono::offset::local::Local;
|
|
||||||
use chrono::Datelike;
|
|
||||||
use itertools::Itertools;
|
|
||||||
use chrono::naive::datetime::NaiveDateTime;
|
|
||||||
|
|
||||||
use entry::Entry;
|
|
||||||
use diaryid::DiaryId;
|
|
||||||
use error::DiaryError as DE;
|
|
||||||
use error::DiaryErrorKind as DEK;
|
|
||||||
use result::Result;
|
|
||||||
use iter::DiaryEntryIterator;
|
|
||||||
use is_in_diary::IsInDiary;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Diary<'a> {
|
|
||||||
store: &'a Store,
|
|
||||||
name: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Diary<'a> {
|
|
||||||
|
|
||||||
pub fn open(store: &'a Store, name: &'a str) -> Diary<'a> {
|
|
||||||
Diary {
|
|
||||||
store: store,
|
|
||||||
name: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create or get a new entry for today
|
|
||||||
pub fn new_entry_today(&self) -> Result<Entry> {
|
|
||||||
let dt = Local::now();
|
|
||||||
let ndt = dt.naive_local();
|
|
||||||
let id = DiaryId::new(String::from(self.name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
|
|
||||||
self.new_entry_by_id(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_entry_by_id(&self, id: DiaryId) -> Result<Entry> {
|
|
||||||
self.retrieve(id.with_diary_name(String::from(self.name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retrieve(&self, id: DiaryId) -> Result<Entry> {
|
|
||||||
id.into_storeid()
|
|
||||||
.and_then(|id| self.store.retrieve(id))
|
|
||||||
.map(|fle| Entry::new(fle))
|
|
||||||
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an iterator for iterating over all entries
|
|
||||||
pub fn entries(&self) -> Result<DiaryEntryIterator<'a>> {
|
|
||||||
self.store
|
|
||||||
.retrieve_for_module("diary")
|
|
||||||
.map(|iter| DiaryEntryIterator::new(self.name, self.store, iter))
|
|
||||||
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete_entry(&self, entry: Entry) -> Result<()> {
|
|
||||||
if !entry.is_in_diary(self.name) {
|
|
||||||
return Err(DE::new(DEK::EntryNotInDiary, None));
|
|
||||||
}
|
|
||||||
let id = entry.get_location().clone();
|
|
||||||
drop(entry);
|
|
||||||
|
|
||||||
self.store.delete(id)
|
|
||||||
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_youngest_entry(&self) -> Option<Result<Entry>> {
|
|
||||||
match self.entries() {
|
|
||||||
Err(e) => Some(Err(e)),
|
|
||||||
Ok(entries) => {
|
|
||||||
entries.sorted_by(|a, b| {
|
|
||||||
match (a, b) {
|
|
||||||
(&Ok(ref a), &Ok(ref b)) => {
|
|
||||||
let a : NaiveDateTime = a.diary_id().into();
|
|
||||||
let b : NaiveDateTime = b.diary_id().into();
|
|
||||||
|
|
||||||
a.cmp(&b)
|
|
||||||
},
|
|
||||||
|
|
||||||
(&Ok(_), &Err(ref e)) => {
|
|
||||||
trace_error(e);
|
|
||||||
Ordering::Less
|
|
||||||
},
|
|
||||||
(&Err(ref e), &Ok(_)) => {
|
|
||||||
trace_error(e);
|
|
||||||
Ordering::Greater
|
|
||||||
},
|
|
||||||
(&Err(ref e1), &Err(ref e2)) => {
|
|
||||||
trace_error(e1);
|
|
||||||
trace_error(e2);
|
|
||||||
Ordering::Equal
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}).into_iter().next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &'a str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,257 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::convert::Into;
|
|
||||||
use std::fmt::{Display, Formatter, Error as FmtError};
|
|
||||||
|
|
||||||
use chrono::naive::datetime::NaiveDateTime;
|
|
||||||
use chrono::naive::time::NaiveTime;
|
|
||||||
use chrono::naive::date::NaiveDate;
|
|
||||||
use chrono::Datelike;
|
|
||||||
use chrono::Timelike;
|
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
|
||||||
use libimagstore::storeid::IntoStoreId;
|
|
||||||
use libimagstore::store::Result as StoreResult;
|
|
||||||
|
|
||||||
use error::DiaryError as DE;
|
|
||||||
use error::DiaryErrorKind as DEK;
|
|
||||||
use error::MapErrInto;
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use module_path::ModuleEntryPath;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DiaryId {
|
|
||||||
name: String,
|
|
||||||
year: i32,
|
|
||||||
month: u32,
|
|
||||||
day: u32,
|
|
||||||
hour: u32,
|
|
||||||
minute: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DiaryId {
|
|
||||||
|
|
||||||
pub fn new(name: String, y: i32, m: u32, d: u32, h: u32, min: u32) -> DiaryId {
|
|
||||||
DiaryId {
|
|
||||||
name: name,
|
|
||||||
year: y,
|
|
||||||
month: m,
|
|
||||||
day: d,
|
|
||||||
hour: h,
|
|
||||||
minute: min,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_datetime<DT: Datelike + Timelike>(diary_name: String, dt: DT) -> DiaryId {
|
|
||||||
DiaryId::new(diary_name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn diary_name(&self) -> &String {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn year(&self) -> i32 {
|
|
||||||
self.year
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn month(&self) -> u32 {
|
|
||||||
self.month
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn day(&self) -> u32 {
|
|
||||||
self.day
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hour(&self) -> u32 {
|
|
||||||
self.hour
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minute(&self) -> u32 {
|
|
||||||
self.minute
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_diary_name(mut self, name: String) -> DiaryId {
|
|
||||||
self.name = name;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_year(mut self, year: i32) -> DiaryId {
|
|
||||||
self.year = year;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_month(mut self, month: u32) -> DiaryId {
|
|
||||||
self.month = month;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_day(mut self, day: u32) -> DiaryId {
|
|
||||||
self.day = day;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_hour(mut self, hour: u32) -> DiaryId {
|
|
||||||
self.hour = hour;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_minute(mut self, minute: u32) -> DiaryId {
|
|
||||||
self.minute = minute;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn now(name: String) -> DiaryId {
|
|
||||||
use chrono::offset::local::Local;
|
|
||||||
|
|
||||||
let now = Local::now();
|
|
||||||
let now_date = now.date().naive_local();
|
|
||||||
let now_time = now.time();
|
|
||||||
let dt = NaiveDateTime::new(now_date, now_time);
|
|
||||||
|
|
||||||
DiaryId::new(name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for DiaryId {
|
|
||||||
|
|
||||||
/// Create a default DiaryId which is a diaryid for a diary named "default" with
|
|
||||||
/// time = 0000-00-00 00:00:00
|
|
||||||
fn default() -> DiaryId {
|
|
||||||
let dt = NaiveDateTime::new(NaiveDate::from_ymd(0, 0, 0), NaiveTime::from_hms(0, 0, 0));
|
|
||||||
DiaryId::from_datetime(String::from("default"), dt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoStoreId for DiaryId {
|
|
||||||
|
|
||||||
fn into_storeid(self) -> StoreResult<StoreId> {
|
|
||||||
let s : String = self.into();
|
|
||||||
ModuleEntryPath::new(s).into_storeid()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<String> for DiaryId {
|
|
||||||
|
|
||||||
fn into(self) -> String {
|
|
||||||
format!("{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
|
|
||||||
self.name, self.year, self.month, self.day, self.hour, self.minute)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for DiaryId {
|
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
|
|
||||||
self.name, self.year, self.month, self.day, self.hour, self.minute)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<NaiveDateTime> for DiaryId {
|
|
||||||
|
|
||||||
fn into(self) -> NaiveDateTime {
|
|
||||||
let d = NaiveDate::from_ymd(self.year, self.month, self.day);
|
|
||||||
let t = NaiveTime::from_hms(self.hour, self.minute, 0);
|
|
||||||
NaiveDateTime::new(d, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait FromStoreId : Sized {
|
|
||||||
|
|
||||||
fn from_storeid(&StoreId) -> Result<Self, DE>;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::path::Component;
|
|
||||||
|
|
||||||
fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str, DE> {
|
|
||||||
match com {
|
|
||||||
Component::Normal(s) => Some(s),
|
|
||||||
_ => None,
|
|
||||||
}.and_then(|s| s.to_str())
|
|
||||||
.ok_or(DEK::IdParseError.into_error())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStoreId for DiaryId {
|
|
||||||
|
|
||||||
fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> {
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use std::path::Components;
|
|
||||||
use std::iter::Rev;
|
|
||||||
|
|
||||||
fn next_component<'a>(components: &'a mut Rev<Components>) -> Result<&'a str, DE> {
|
|
||||||
components.next()
|
|
||||||
.ok_or(DEK::IdParseError.into_error())
|
|
||||||
.and_then(component_to_str)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cmps = s.components().rev();
|
|
||||||
|
|
||||||
let (hour, minute) = try!(next_component(&mut cmps).and_then(|time| {
|
|
||||||
let mut time = time.split(":");
|
|
||||||
let hour = time.next().and_then(|s| FromStr::from_str(s).ok());
|
|
||||||
let minute = time.next()
|
|
||||||
.and_then(|s| s.split("~").next())
|
|
||||||
.and_then(|s| FromStr::from_str(s).ok());
|
|
||||||
|
|
||||||
debug!("Hour = {:?}", hour);
|
|
||||||
debug!("Minute = {:?}", minute);
|
|
||||||
|
|
||||||
match (hour, minute) {
|
|
||||||
(Some(h), Some(m)) => Ok((h, m)),
|
|
||||||
_ => return Err(DE::new(DEK::IdParseError, None)),
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
let day: Result<u32,_> = next_component(&mut cmps)
|
|
||||||
.and_then(|s| s.parse::<u32>()
|
|
||||||
.map_err_into(DEK::IdParseError));
|
|
||||||
|
|
||||||
let month: Result<u32,_> = next_component(&mut cmps)
|
|
||||||
.and_then(|s| s.parse::<u32>()
|
|
||||||
.map_err_into(DEK::IdParseError));
|
|
||||||
|
|
||||||
let year: Result<i32,_> = next_component(&mut cmps)
|
|
||||||
.and_then(|s| s.parse::<i32>()
|
|
||||||
.map_err_into(DEK::IdParseError));
|
|
||||||
|
|
||||||
let name = next_component(&mut cmps).map(String::from);
|
|
||||||
|
|
||||||
debug!("Day = {:?}", day);
|
|
||||||
debug!("Month = {:?}", month);
|
|
||||||
debug!("Year = {:?}", year);
|
|
||||||
debug!("Name = {:?}", name);
|
|
||||||
|
|
||||||
let day = try!(day);
|
|
||||||
let month = try!(month);
|
|
||||||
let year = try!(year);
|
|
||||||
let name = try!(name);
|
|
||||||
|
|
||||||
Ok(DiaryId::new(name, year, month, day, hour, minute))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
|
||||||
use libimagentryedit::edit::Edit;
|
|
||||||
use libimagentryedit::result::Result as EditResult;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
|
||||||
use diaryid::FromStoreId;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Entry<'a>(FileLockEntry<'a>);
|
|
||||||
|
|
||||||
impl<'a> Deref for Entry<'a> {
|
|
||||||
type Target = FileLockEntry<'a>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &FileLockEntry<'a> {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DerefMut for Entry<'a> {
|
|
||||||
|
|
||||||
fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Entry<'a> {
|
|
||||||
|
|
||||||
pub fn new(fle: FileLockEntry<'a>) -> Entry<'a> {
|
|
||||||
Entry(fle)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the diary id for this entry.
|
|
||||||
///
|
|
||||||
/// TODO: calls Option::unwrap() as it assumes that an existing Entry has an ID that is parsable
|
|
||||||
pub fn diary_id(&self) -> DiaryId {
|
|
||||||
DiaryId::from_storeid(&self.0.get_location().clone()).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Into<FileLockEntry<'a>> for Entry<'a> {
|
|
||||||
|
|
||||||
fn into(self) -> FileLockEntry<'a> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<FileLockEntry<'a>> for Entry<'a> {
|
|
||||||
|
|
||||||
fn from(fle: FileLockEntry<'a>) -> Entry<'a> {
|
|
||||||
Entry::new(fle)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Edit for Entry<'a> {
|
|
||||||
|
|
||||||
fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
|
|
||||||
self.0.edit_content(rt)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
generate_error_module!(
|
|
||||||
generate_error_types!(DiaryError, DiaryErrorKind,
|
|
||||||
StoreWriteError => "Error writing store",
|
|
||||||
StoreReadError => "Error reading store",
|
|
||||||
CannotFindDiary => "Cannot find diary",
|
|
||||||
CannotCreateNote => "Cannot create Note object for diary entry",
|
|
||||||
DiaryEditError => "Cannot edit diary entry",
|
|
||||||
PathConversionError => "Error while converting paths internally",
|
|
||||||
EntryNotInDiary => "Entry not in Diary",
|
|
||||||
IOError => "IO Error",
|
|
||||||
ViewError => "Error viewing diary entry",
|
|
||||||
IdParseError => "Error while parsing ID"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::DiaryError;
|
|
||||||
pub use self::error::DiaryErrorKind;
|
|
||||||
pub use self::error::MapErrInto;
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
|
||||||
use libimagstore::storeid::StoreId;
|
|
||||||
|
|
||||||
pub trait IsInDiary {
|
|
||||||
|
|
||||||
fn is_in_diary(&self, name: &str) -> bool;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IsInDiary for Entry {
|
|
||||||
|
|
||||||
fn is_in_diary(&self, name: &str) -> bool {
|
|
||||||
self.get_location().clone().is_in_diary(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IsInDiary for StoreId {
|
|
||||||
|
|
||||||
fn is_in_diary(&self, name: &str) -> bool {
|
|
||||||
self.local().starts_with(format!("diary/{}", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter, Error as FmtError};
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
|
||||||
use diaryid::FromStoreId;
|
|
||||||
use is_in_diary::IsInDiary;
|
|
||||||
use entry::Entry as DiaryEntry;
|
|
||||||
use error::DiaryError as DE;
|
|
||||||
use error::DiaryErrorKind as DEK;
|
|
||||||
use result::Result;
|
|
||||||
use libimagerror::trace::trace_error;
|
|
||||||
|
|
||||||
/// A iterator for iterating over diary entries
|
|
||||||
pub struct DiaryEntryIterator<'a> {
|
|
||||||
store: &'a Store,
|
|
||||||
name: &'a str,
|
|
||||||
iter: StoreIdIterator,
|
|
||||||
|
|
||||||
year: Option<i32>,
|
|
||||||
month: Option<u32>,
|
|
||||||
day: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Debug for DiaryEntryIterator<'a> {
|
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
|
|
||||||
write!(fmt, "DiaryEntryIterator<name = {}, year = {:?}, month = {:?}, day = {:?}>",
|
|
||||||
self.name, self.year, self.month, self.day)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DiaryEntryIterator<'a> {
|
|
||||||
|
|
||||||
pub fn new(diaryname: &'a str, store: &'a Store, iter: StoreIdIterator) -> DiaryEntryIterator<'a> {
|
|
||||||
DiaryEntryIterator {
|
|
||||||
store: store,
|
|
||||||
name: diaryname,
|
|
||||||
iter: iter,
|
|
||||||
|
|
||||||
year: None,
|
|
||||||
month: None,
|
|
||||||
day: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter by year, get all diary entries for this year
|
|
||||||
pub fn year(mut self, year: i32) -> DiaryEntryIterator<'a> {
|
|
||||||
self.year = Some(year);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter by month, get all diary entries for this month (every year)
|
|
||||||
pub fn month(mut self, month: u32) -> DiaryEntryIterator<'a> {
|
|
||||||
self.month = Some(month);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter by day, get all diary entries for this day (every year, every year)
|
|
||||||
pub fn day(mut self, day: u32) -> DiaryEntryIterator<'a> {
|
|
||||||
self.day = Some(day);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for DiaryEntryIterator<'a> {
|
|
||||||
type Item = Result<DiaryEntry<'a>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<DiaryEntry<'a>>> {
|
|
||||||
loop {
|
|
||||||
let next = match self.iter.next() {
|
|
||||||
Some(s) => s,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
debug!("Next element: {:?}", next);
|
|
||||||
|
|
||||||
if next.is_in_diary(self.name) {
|
|
||||||
debug!("Seems to be in diary: {:?}", next);
|
|
||||||
let id = match DiaryId::from_storeid(&next) {
|
|
||||||
Ok(i) => i,
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
debug!("Couldn't parse {:?} into DiaryId: {:?}", next, e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("Success parsing id = {:?}", id);
|
|
||||||
|
|
||||||
let y = match self.year { None => true, Some(y) => y == id.year() };
|
|
||||||
let m = match self.month { None => true, Some(m) => m == id.month() };
|
|
||||||
let d = match self.day { None => true, Some(d) => d == id.day() };
|
|
||||||
|
|
||||||
if y && m && d {
|
|
||||||
debug!("Return = {:?}", id);
|
|
||||||
return Some(self
|
|
||||||
.store
|
|
||||||
.retrieve(next)
|
|
||||||
.map(|fle| DiaryEntry::new(fle))
|
|
||||||
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug!("Not in the requested diary ({}): {:?}", self.name, next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
dead_code,
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_must_use,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
extern crate chrono;
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
#[macro_use] extern crate lazy_static;
|
|
||||||
extern crate semver;
|
|
||||||
extern crate toml;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate itertools;
|
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
|
||||||
#[macro_use] extern crate libimagutil;
|
|
||||||
#[macro_use] extern crate libimagerror;
|
|
||||||
extern crate libimagentryedit;
|
|
||||||
extern crate libimagentryview;
|
|
||||||
extern crate libimagrt;
|
|
||||||
|
|
||||||
module_entry_path_mod!("diary");
|
|
||||||
|
|
||||||
pub mod config;
|
|
||||||
pub mod error;
|
|
||||||
pub mod diaryid;
|
|
||||||
pub mod diary;
|
|
||||||
pub mod is_in_diary;
|
|
||||||
pub mod entry;
|
|
||||||
pub mod iter;
|
|
||||||
pub mod result;
|
|
||||||
pub mod viewer;
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::DiaryError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, DiaryError>;
|
|
|
@ -1,64 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
//! A diary viewer built on libimagentryview.
|
|
||||||
|
|
||||||
use entry::Entry;
|
|
||||||
use error::DiaryErrorKind as DEK;
|
|
||||||
use error::MapErrInto;
|
|
||||||
use result::Result;
|
|
||||||
|
|
||||||
use libimagentryview::viewer::Viewer;
|
|
||||||
use libimagentryview::builtin::plain::PlainViewer;
|
|
||||||
|
|
||||||
/// This viewer does _not_ implement libimagentryview::viewer::Viewer because we need to be able to
|
|
||||||
/// call some diary-type specific functions on the entries passed to this.
|
|
||||||
///
|
|
||||||
/// This type is mainly just written to be constructed-called-deleted in one go:
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// DiaryViewer::new(show_header).view_entries(entries);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub struct DiaryViewer(PlainViewer);
|
|
||||||
|
|
||||||
impl DiaryViewer {
|
|
||||||
|
|
||||||
pub fn new(show_header: bool) -> DiaryViewer {
|
|
||||||
DiaryViewer(PlainViewer::new(show_header))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// View all entries from the iterator, or stop immediately if an error occurs, returning that
|
|
||||||
/// error.
|
|
||||||
pub fn view_entries<'a, I: Iterator<Item = Entry<'a>>>(&self, entries: I) -> Result<()> {
|
|
||||||
for entry in entries {
|
|
||||||
let id = entry.diary_id();
|
|
||||||
println!("{} :\n", id);
|
|
||||||
let _ = try!(self.0
|
|
||||||
.view_entry(&entry)
|
|
||||||
.map_err_into(DEK::ViewError)
|
|
||||||
.map_err_into(DEK::IOError));
|
|
||||||
println!("\n---\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libimagmail"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
|
||||||
|
|
||||||
description = "Library for the imag core distribution"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
log = "0.3"
|
|
||||||
mailparse = "0.4"
|
|
||||||
semver = "0.5"
|
|
||||||
toml = "0.2.*"
|
|
||||||
filters = "0.1.*"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagref]
|
|
||||||
path = "../libimagref"
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
generate_error_module!(
|
|
||||||
generate_error_types!(MailError, MailErrorKind,
|
|
||||||
RefCreationError => "Error creating a reference to a file/directory",
|
|
||||||
RefHandlingError => "Error while handling the internal reference object",
|
|
||||||
MailParsingError => "Error while parsing mail",
|
|
||||||
|
|
||||||
FetchByHashError => "Error fetching mail from Store by hash",
|
|
||||||
FetchError => "Error fetching mail from Store",
|
|
||||||
IOError => "IO Error"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::MailError;
|
|
||||||
pub use self::error::MailErrorKind;
|
|
||||||
pub use self::error::MapErrInto;
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
use std::io::Read;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use mailparse::{MailHeader, parse_mail};
|
|
||||||
|
|
||||||
use libimagref::hasher::Hasher;
|
|
||||||
use libimagref::hasher::DefaultHasher;
|
|
||||||
use libimagref::error::RefErrorKind as REK;
|
|
||||||
use libimagref::error::MapErrInto;
|
|
||||||
use libimagref::result::Result as RResult;
|
|
||||||
use libimagerror::into::IntoError;
|
|
||||||
|
|
||||||
use error::MailErrorKind as MEK;
|
|
||||||
|
|
||||||
pub struct MailHasher {
|
|
||||||
defaulthasher: DefaultHasher,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MailHasher {
|
|
||||||
|
|
||||||
pub fn new() -> MailHasher {
|
|
||||||
MailHasher { defaulthasher: DefaultHasher::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hasher for MailHasher {
|
|
||||||
|
|
||||||
fn hash_name(&self) -> &'static str {
|
|
||||||
"default_mail_hasher"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_hash<R: Read>(&mut self, pb: &PathBuf, c: &mut R) -> RResult<String> {
|
|
||||||
use filters::filter::Filter;
|
|
||||||
|
|
||||||
let mut s = String::new();
|
|
||||||
try!(c.read_to_string(&mut s).map_err_into(REK::UTF8Error).map_err_into(REK::IOError));
|
|
||||||
|
|
||||||
parse_mail(&s.as_bytes())
|
|
||||||
.map_err(Box::new)
|
|
||||||
.map_err(|e| MEK::MailParsingError.into_error_with_cause(e))
|
|
||||||
.map_err_into(REK::RefHashingError)
|
|
||||||
.and_then(|mail| {
|
|
||||||
let has_key = |hdr: &MailHeader, exp: &str|
|
|
||||||
hdr.get_key().map(|s| s == exp).unwrap_or(false);
|
|
||||||
|
|
||||||
let subject_filter = |hdr: &MailHeader| has_key(hdr, "Subject");
|
|
||||||
let from_filter = |hdr: &MailHeader| has_key(hdr, "From");
|
|
||||||
let to_filter = |hdr: &MailHeader| has_key(hdr, "To");
|
|
||||||
|
|
||||||
let filter = subject_filter.or(from_filter).or(to_filter);
|
|
||||||
|
|
||||||
let mut v = vec![];
|
|
||||||
for hdr in mail.headers.iter().filter(|item| filter.filter(item)) {
|
|
||||||
let s = try!(hdr.get_value()
|
|
||||||
.map_err(Box::new)
|
|
||||||
.map_err(|e| REK::RefHashingError.into_error_with_cause(e)));
|
|
||||||
|
|
||||||
v.push(s);
|
|
||||||
}
|
|
||||||
let s : String = v.join("");
|
|
||||||
|
|
||||||
self.defaulthasher.create_hash(pb, &mut s.as_bytes())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
//! Module for the MailIter
|
|
||||||
//!
|
|
||||||
//! MailIter is a iterator which takes an Iterator that yields `Ref` and yields itself
|
|
||||||
//! `Result<Mail>`, where `Err(_)` is returned if the Ref is not a Mail or parsing of the
|
|
||||||
//! referenced mail file failed.
|
|
||||||
//!
|
|
||||||
|
|
||||||
use mail::Mail;
|
|
||||||
use result::Result;
|
|
||||||
|
|
||||||
use libimagref::reference::Ref;
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
struct MailIter<'a, I: 'a + Iterator<Item = Ref<'a>>> {
|
|
||||||
_marker: PhantomData<&'a I>,
|
|
||||||
i: I,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Iterator<Item = Ref<'a>>> MailIter<'a, I> {
|
|
||||||
|
|
||||||
pub fn new(i: I) -> MailIter<'a, I> {
|
|
||||||
MailIter { _marker: PhantomData, i: i }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Iterator<Item = Ref<'a>>> Iterator for MailIter<'a, I> {
|
|
||||||
|
|
||||||
type Item = Result<Mail<'a>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<Mail<'a>>> {
|
|
||||||
self.i.next().map(Mail::from_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#[macro_use] extern crate log;
|
|
||||||
extern crate mailparse;
|
|
||||||
extern crate semver;
|
|
||||||
extern crate toml;
|
|
||||||
extern crate filters;
|
|
||||||
|
|
||||||
#[macro_use] extern crate libimagerror;
|
|
||||||
extern crate libimagstore;
|
|
||||||
extern crate libimagref;
|
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
pub mod hasher;
|
|
||||||
pub mod iter;
|
|
||||||
pub mod mail;
|
|
||||||
pub mod result;
|
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
use std::result::Result as RResult;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Read;
|
|
||||||
|
|
||||||
use libimagstore::store::{FileLockEntry, Store};
|
|
||||||
use libimagref::reference::Ref;
|
|
||||||
use libimagref::flags::RefFlags;
|
|
||||||
|
|
||||||
use mailparse::{MailParseError, ParsedMail, parse_mail};
|
|
||||||
|
|
||||||
use hasher::MailHasher;
|
|
||||||
use result::Result;
|
|
||||||
use error::{MapErrInto, MailErrorKind as MEK};
|
|
||||||
|
|
||||||
struct Buffer(String);
|
|
||||||
|
|
||||||
impl Buffer {
|
|
||||||
pub fn parsed<'a>(&'a self) -> RResult<ParsedMail<'a>, MailParseError> {
|
|
||||||
parse_mail(self.0.as_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for Buffer {
|
|
||||||
fn from(data: String) -> Buffer {
|
|
||||||
Buffer(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Mail<'a>(Ref<'a>, Buffer);
|
|
||||||
|
|
||||||
impl<'a> Mail<'a> {
|
|
||||||
|
|
||||||
/// Imports a mail from the Path passed
|
|
||||||
pub fn import_from_path<P: AsRef<Path>>(store: &Store, p: P) -> Result<Mail> {
|
|
||||||
let h = MailHasher::new();
|
|
||||||
let f = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
|
|
||||||
let p = PathBuf::from(p.as_ref());
|
|
||||||
|
|
||||||
Ref::create_with_hasher(store, p, f, h)
|
|
||||||
.map_err_into(MEK::RefCreationError)
|
|
||||||
.and_then(|reference| {
|
|
||||||
reference.fs_file()
|
|
||||||
.map_err_into(MEK::RefHandlingError)
|
|
||||||
.and_then(|path| File::open(path).map_err_into(MEK::IOError))
|
|
||||||
.and_then(|mut file| {
|
|
||||||
let mut s = String::new();
|
|
||||||
file.read_to_string(&mut s)
|
|
||||||
.map(|_| s)
|
|
||||||
.map_err_into(MEK::IOError)
|
|
||||||
})
|
|
||||||
.map(Buffer::from)
|
|
||||||
.map(|buffer| Mail(reference, buffer))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Opens a mail by the passed hash
|
|
||||||
pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
|
|
||||||
Ref::get_by_hash(store, String::from(hash.as_ref()))
|
|
||||||
.map_err_into(MEK::FetchByHashError)
|
|
||||||
.map_err_into(MEK::FetchError)
|
|
||||||
.and_then(|o| match o {
|
|
||||||
Some(r) => Mail::from_ref(r).map(Some),
|
|
||||||
None => Ok(None),
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implement me as TryFrom as soon as it is stable
|
|
||||||
pub fn from_ref(r: Ref<'a>) -> Result<Mail> {
|
|
||||||
r.fs_file()
|
|
||||||
.map_err_into(MEK::RefHandlingError)
|
|
||||||
.and_then(|path| File::open(path).map_err_into(MEK::IOError))
|
|
||||||
.and_then(|mut file| {
|
|
||||||
let mut s = String::new();
|
|
||||||
file.read_to_string(&mut s)
|
|
||||||
.map(|_| s)
|
|
||||||
.map_err_into(MEK::IOError)
|
|
||||||
})
|
|
||||||
.map(Buffer::from)
|
|
||||||
.map(|buffer| Mail(r, buffer))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field(&self, field: &str) -> Result<Option<String>> {
|
|
||||||
use mailparse::MailHeader;
|
|
||||||
|
|
||||||
self.1
|
|
||||||
.parsed()
|
|
||||||
.map_err_into(MEK::MailParsingError)
|
|
||||||
.map(|parsed| {
|
|
||||||
parsed.headers
|
|
||||||
.iter()
|
|
||||||
.filter(|hdr| hdr.get_key().map(|n| n == field).unwrap_or(false))
|
|
||||||
.next()
|
|
||||||
.and_then(|field| field.get_value().ok())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_from(&self) -> Result<Option<String>> {
|
|
||||||
self.get_field("From")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_to(&self) -> Result<Option<String>> {
|
|
||||||
self.get_field("To")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_subject(&self) -> Result<Option<String>> {
|
|
||||||
self.get_field("Subject")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_message_id(&self) -> Result<Option<String>> {
|
|
||||||
self.get_field("Message-ID")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_in_reply_to(&self) -> Result<Option<String>> {
|
|
||||||
self.get_field("In-Reply-To")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use error::MailError;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, MailError>;
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libimagtodo"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["mario <mario-krehl@gmx.de>"]
|
|
||||||
|
|
||||||
description = "Library for the imag core distribution"
|
|
||||||
|
|
||||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
|
||||||
readme = "../README.md"
|
|
||||||
license = "LGPL-2.1"
|
|
||||||
|
|
||||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
|
||||||
homepage = "http://imag-pim.org"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
semver = "0.2"
|
|
||||||
task-hookrs = "0.2.2"
|
|
||||||
uuid = "0.3"
|
|
||||||
toml = "0.2.*"
|
|
||||||
log = "0.3"
|
|
||||||
serde_json = "0.8"
|
|
||||||
|
|
||||||
[dependencies.libimagstore]
|
|
||||||
path = "../libimagstore"
|
|
||||||
|
|
||||||
[dependencies.libimagerror]
|
|
||||||
path = "../libimagerror"
|
|
||||||
|
|
||||||
[dependencies.libimagutil]
|
|
||||||
path = "../libimagutil"
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
generate_error_module!(
|
|
||||||
generate_error_types!(TodoError, TodoErrorKind,
|
|
||||||
ConversionError => "Conversion Error",
|
|
||||||
StoreError => "Store Error",
|
|
||||||
StoreIdError => "Store Id handling error",
|
|
||||||
ImportError => "Error importing"
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
pub use self::error::TodoError;
|
|
||||||
pub use self::error::TodoErrorKind;
|
|
||||||
pub use self::error::MapErrInto;
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
non_camel_case_types,
|
|
||||||
non_snake_case,
|
|
||||||
path_statements,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unstable_features,
|
|
||||||
unused_allocation,
|
|
||||||
unused_import_braces,
|
|
||||||
unused_imports,
|
|
||||||
unused_mut,
|
|
||||||
unused_qualifications,
|
|
||||||
while_true,
|
|
||||||
)]
|
|
||||||
|
|
||||||
extern crate semver;
|
|
||||||
extern crate uuid;
|
|
||||||
extern crate toml;
|
|
||||||
#[macro_use] extern crate log;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
|
||||||
#[macro_use] extern crate libimagerror;
|
|
||||||
extern crate libimagutil;
|
|
||||||
extern crate task_hookrs;
|
|
||||||
|
|
||||||
module_entry_path_mod!("todo");
|
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
pub mod result;
|
|
||||||
pub mod task;
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use error::TodoError;
|
|
||||||
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
pub type Result<T> = RResult<T, TodoError>;
|
|
|
@ -1,293 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; version
|
|
||||||
// 2.1 of the License.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use std::io::BufRead;
|
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use toml::Value;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use task_hookrs::task::Task as TTask;
|
|
||||||
use task_hookrs::import::{import_task, import_tasks};
|
|
||||||
|
|
||||||
use libimagstore::store::{FileLockEntry, Store};
|
|
||||||
use libimagstore::storeid::{IntoStoreId, StoreIdIterator, StoreId};
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagutil::debug_result::DebugResult;
|
|
||||||
use module_path::ModuleEntryPath;
|
|
||||||
|
|
||||||
use error::{TodoError, TodoErrorKind, MapErrInto};
|
|
||||||
use result::Result;
|
|
||||||
|
|
||||||
/// Task struct containing a `FileLockEntry`
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Task<'a>(FileLockEntry<'a>);
|
|
||||||
|
|
||||||
impl<'a> Task<'a> {
|
|
||||||
|
|
||||||
/// Concstructs a new `Task` with a `FileLockEntry`
|
|
||||||
pub fn new(fle: FileLockEntry<'a>) -> Task<'a> {
|
|
||||||
Task(fle)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn import<R: BufRead>(store: &'a Store, mut r: R) -> Result<(Task<'a>, String, Uuid)> {
|
|
||||||
let mut line = String::new();
|
|
||||||
r.read_line(&mut line);
|
|
||||||
import_task(&line.as_str())
|
|
||||||
.map_err_into(TodoErrorKind::ImportError)
|
|
||||||
.map_dbg_err_str("Error while importing task")
|
|
||||||
.map_err_dbg_trace()
|
|
||||||
.and_then(|t| {
|
|
||||||
let uuid = t.uuid().clone();
|
|
||||||
t.into_task(store).map(|t| (t, line, uuid))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a task from an import string. That is: read the imported string, get the UUID from it
|
|
||||||
/// and try to load this UUID from store.
|
|
||||||
///
|
|
||||||
/// Possible return values are:
|
|
||||||
///
|
|
||||||
/// * Ok(Ok(Task))
|
|
||||||
/// * Ok(Err(String)) - where the String is the String read from the `r` parameter
|
|
||||||
/// * Err(_) - where the error is an error that happened during evaluation
|
|
||||||
///
|
|
||||||
pub fn get_from_import<R: BufRead>(store: &'a Store, mut r: R) -> Result<RResult<Task<'a>, String>>
|
|
||||||
{
|
|
||||||
let mut line = String::new();
|
|
||||||
r.read_line(&mut line);
|
|
||||||
Task::get_from_string(store, line)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a task from a String. The String is expected to contain the JSON-representation of the
|
|
||||||
/// Task to get from the store (only the UUID really matters in this case)
|
|
||||||
///
|
|
||||||
/// For an explanation on the return values see `Task::get_from_import()`.
|
|
||||||
pub fn get_from_string(store: &'a Store, s: String) -> Result<RResult<Task<'a>, String>> {
|
|
||||||
import_task(s.as_str())
|
|
||||||
.map_err_into(TodoErrorKind::ImportError)
|
|
||||||
.map_dbg_err_str("Error while importing task")
|
|
||||||
.map_err_dbg_trace()
|
|
||||||
.map(|t| t.uuid().clone())
|
|
||||||
.and_then(|uuid| Task::get_from_uuid(store, uuid))
|
|
||||||
.and_then(|o| match o {
|
|
||||||
None => Ok(Err(s)),
|
|
||||||
Some(t) => Ok(Ok(t)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a task from an UUID.
|
|
||||||
///
|
|
||||||
/// If there is no task with this UUID, this returns `Ok(None)`.
|
|
||||||
pub fn get_from_uuid(store: &'a Store, uuid: Uuid) -> Result<Option<Task<'a>>> {
|
|
||||||
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
|
||||||
.into_storeid()
|
|
||||||
.and_then(|store_id| store.get(store_id))
|
|
||||||
.map(|o| o.map(Task::new))
|
|
||||||
.map_err_into(TodoErrorKind::StoreError)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
|
|
||||||
/// implicitely create the task if it does not exist.
|
|
||||||
pub fn retrieve_from_import<R: BufRead>(store: &'a Store, mut r: R) -> Result<Task<'a>> {
|
|
||||||
let mut line = String::new();
|
|
||||||
r.read_line(&mut line);
|
|
||||||
Task::retrieve_from_string(store, line)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve a task from a String. The String is expected to contain the JSON-representation of
|
|
||||||
/// the Task to retrieve from the store (only the UUID really matters in this case)
|
|
||||||
pub fn retrieve_from_string(store: &'a Store, s: String) -> Result<Task<'a>> {
|
|
||||||
Task::get_from_string(store, s)
|
|
||||||
.and_then(|opt| match opt {
|
|
||||||
Ok(task) => Ok(task),
|
|
||||||
Err(string) => import_task(string.as_str())
|
|
||||||
.map_err_into(TodoErrorKind::ImportError)
|
|
||||||
.map_dbg_err_str("Error while importing task")
|
|
||||||
.map_err_dbg_trace()
|
|
||||||
.and_then(|t| t.into_task(store)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete_by_imports<R: BufRead>(store: &Store, r: R) -> Result<()> {
|
|
||||||
use serde_json::ser::to_string as serde_to_string;
|
|
||||||
use task_hookrs::status::TaskStatus;
|
|
||||||
|
|
||||||
for (counter, res_ttask) in import_tasks(r).into_iter().enumerate() {
|
|
||||||
match res_ttask {
|
|
||||||
Ok(ttask) => {
|
|
||||||
if counter % 2 == 1 {
|
|
||||||
// Only every second task is needed, the first one is the
|
|
||||||
// task before the change, and the second one after
|
|
||||||
// the change. The (maybe modified) second one is
|
|
||||||
// expected by taskwarrior.
|
|
||||||
match serde_to_string(&ttask).map_err_into(TodoErrorKind::ImportError) {
|
|
||||||
// use println!() here, as we talk with TW
|
|
||||||
Ok(val) => println!("{}", val),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Taskwarrior does not have the concept of deleted tasks, but only modified
|
|
||||||
// ones.
|
|
||||||
//
|
|
||||||
// Here we check if the status of a task is deleted and if yes, we delete it
|
|
||||||
// from the store.
|
|
||||||
if *ttask.status() == TaskStatus::Deleted {
|
|
||||||
match Task::delete_by_uuid(store, *ttask.uuid()) {
|
|
||||||
Ok(_) => info!("Deleted task {}", *ttask.uuid()),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end if c % 2
|
|
||||||
},
|
|
||||||
Err(e) => return Err(e).map_err_into(TodoErrorKind::ImportError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete_by_uuid(store: &Store, uuid: Uuid) -> Result<()> {
|
|
||||||
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
|
||||||
.into_storeid()
|
|
||||||
.and_then(|id| store.delete(id))
|
|
||||||
.map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn all_as_ids(store: &Store) -> Result<StoreIdIterator> {
|
|
||||||
store.retrieve_for_module("todo/taskwarrior")
|
|
||||||
.map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn all(store: &Store) -> Result<TaskIterator> {
|
|
||||||
Task::all_as_ids(store)
|
|
||||||
.map(|iter| TaskIterator::new(store, iter))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Deref for Task<'a> {
|
|
||||||
type Target = FileLockEntry<'a>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &FileLockEntry<'a> {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DerefMut for Task<'a> {
|
|
||||||
|
|
||||||
fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
|
|
||||||
pub trait IntoTask<'a> {
|
|
||||||
|
|
||||||
/// # Usage
|
|
||||||
/// ```ignore
|
|
||||||
/// use std::io::stdin;
|
|
||||||
///
|
|
||||||
/// use task_hookrs::task::Task;
|
|
||||||
/// use task_hookrs::import::import;
|
|
||||||
/// use libimagstore::store::{Store, FileLockEntry};
|
|
||||||
///
|
|
||||||
/// if let Ok(task_hookrs_task) = import(stdin()) {
|
|
||||||
/// // Store is given at runtime
|
|
||||||
/// let task = task_hookrs_task.into_filelockentry(store);
|
|
||||||
/// println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn into_task(self, store : &'a Store) -> Result<Task<'a>>;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoTask<'a> for TTask {
|
|
||||||
|
|
||||||
fn into_task(self, store : &'a Store) -> Result<Task<'a>> {
|
|
||||||
let uuid = self.uuid();
|
|
||||||
ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
|
|
||||||
.into_storeid()
|
|
||||||
.map_err_into(TodoErrorKind::StoreIdError)
|
|
||||||
.and_then(|id| {
|
|
||||||
store.retrieve(id)
|
|
||||||
.map_err_into(TodoErrorKind::StoreError)
|
|
||||||
.and_then(|mut fle| {
|
|
||||||
{
|
|
||||||
let mut hdr = fle.get_header_mut();
|
|
||||||
let read = hdr.read("todo").map_err_into(TodoErrorKind::StoreError);
|
|
||||||
if try!(read).is_none() {
|
|
||||||
try!(hdr
|
|
||||||
.set("todo", Value::Table(BTreeMap::new()))
|
|
||||||
.map_err_into(TodoErrorKind::StoreError));
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(hdr.set("todo.uuid", Value::String(format!("{}",uuid)))
|
|
||||||
.map_err_into(TodoErrorKind::StoreError));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If none of the errors above have returned the function, everything is fine
|
|
||||||
Ok(Task::new(fle))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
trait FromStoreId {
|
|
||||||
fn from_storeid<'a>(&'a Store, StoreId) -> Result<Task<'a>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromStoreId for Task<'a> {
|
|
||||||
|
|
||||||
fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Task<'b>> {
|
|
||||||
match store.retrieve(id) {
|
|
||||||
Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
|
|
||||||
Ok(c) => Ok(Task::new( c )),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TaskIterator<'a> {
|
|
||||||
store: &'a Store,
|
|
||||||
iditer: StoreIdIterator,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TaskIterator<'a> {
|
|
||||||
|
|
||||||
pub fn new(store: &'a Store, iditer: StoreIdIterator) -> TaskIterator<'a> {
|
|
||||||
TaskIterator {
|
|
||||||
store: store,
|
|
||||||
iditer: iditer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for TaskIterator<'a> {
|
|
||||||
type Item = Result<Task<'a>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<Task<'a>>> {
|
|
||||||
self.iditer.next().map(|id| Task::from_storeid(self.store, id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue