Merge pull request #1219 from matthiasbeyer/minor

Minor patches
This commit is contained in:
Matthias Beyer 2018-02-01 13:18:31 +01:00 committed by GitHub
commit da4b823048
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 301 additions and 253 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
Cargo.lock Cargo.lock
out out
target target
.idea

View file

@ -29,8 +29,9 @@ addons:
- pkg-config - pkg-config
script: script:
- cargo build --all --all-features --verbose -j 1 - |
- cargo test --all --all-features --verbose -j 1 cargo build --all --all-features -j 1 || exit 1
cargo test --all --all-features -j 1 || exit 1
notifications: notifications:
email: email:

View file

@ -23,12 +23,10 @@ Our (long-term) goal is to
Yes, imag is a rather ambitious project as it tries to reimplement functionality Yes, imag is a rather ambitious project as it tries to reimplement functionality
for several "personal information management aspects". It is a hobby project, for several "personal information management aspects". It is a hobby project,
keep that in mind. We try to use standards like vcard and icalendar wherever keep that in mind. We try to use standards like vcard, icalendar and others
possible. wherever possible.
imag consists of _modules_ (e.g. `imag-notes`, `imag-tag`, `imag-view`), where Have a look at [the documentation](./doc/) for some more words on this.
each module covers one PIM aspect. Have a look at
[the documentation](./doc/) for some more words on this.
## Building/Running ## Building/Running
@ -48,6 +46,18 @@ Make sure to use a recent `cargo`, at least one with workspace support.
Building all crates works with `cargo build --all`, building individual crates Building all crates works with `cargo build --all`, building individual crates
by `cd`ing to their directory and calling `cargo build`. by `cd`ing to their directory and calling `cargo build`.
For building all commandline applications:
```bash
find bin -maxdepth 3 -name Cargo.toml -exec cargo build --manifest-path {} \;
```
For building only the core functionality
```bash
find bin/core -maxdepth 3 -name Cargo.toml -exec cargo build --manifest-path {} \;
```
### Running ### Running
After you build the module you want to play with, you can simply call the binary After you build the module you want to play with, you can simply call the binary
@ -57,48 +67,43 @@ If you installed the module, you can either call `imag-<modulename>` (if the
install-directory is in your `$PATH`), or install the `imag` binary to call `imag install-directory is in your `$PATH`), or install the `imag` binary to call `imag
<modulename>` (also if everything is in your `$PATH`). <modulename>` (also if everything is in your `$PATH`).
## Staying up-to-date ## Staying up-to-date
We have a [official website for imag](https://imag-pim.org), where I post We have a [official website for imag](https://imag-pim.org), where I post
[release notes](http://imag-pim.org/releases/) and monthly(ish) updates what's [release notes](http://imag-pim.org/releases/) and monthly(ish) updates what's
happening in the source tree ([RSS here](https://imag-pim.org/index.xml)). happening in the source tree ([RSS here](https://imag-pim.org/index.xml)).
We also have a [mailinglist](https://imag-pim.org/mailinglist/) where I post We also have a [mailinglist](https://imag-pim.org/mailinglist/) where I post
updates and where discussion and questions are encouraged. updates and where discussion and questions are encouraged.
## Documentation ## Documentation
This is a hobby project, so sometimes things are not optimal and might go We have some documentation in [the ./doc subtree](./doc/)
unrecognized and slip through. Feel free to open issues about things you notice!
Though, we have some documentation in [the ./doc subtree](./doc/)
which can be compiled to PDF or a website. which can be compiled to PDF or a website.
These docs are not published anywhere and are not even integrated into our CI, It might not be up to date, though.
so it might be broken (though it's unlikely). Developer documentation for the last release is available
Developer documentation is also available [on docs.rs](https://docs.rs/releases/search?query=imag).
[online on github.io](https://matthiasbeyer.github.io/imag/imag_documentation/index.html)
and [on docs.rs](https://docs.rs/releases/search?query=imag), though they might
be a bit outdated.
## Please contribute! ## Please contribute!
We are looking for contributors! We are looking for contributors!
Feel free to open issues for asking questions, suggesting features or other Feel free to open issues for asking questions, suggesting features or other
things! things!
Also have a look at [the CONTRIBUTING.md file](./CONTRIBUTING.md)! Also have a look at [the CONTRIBUTING.md file](./CONTRIBUTING.md)!
## Contact
Have a look at [our website](https://imag-pim.org) where you can find some ## Contact
information on how to get in touch and so on.
Feel free to join our new IRC channel at freenode: #imag Feel free to join our new IRC channel at freenode: #imag
or our [mailinglist](https://imag-pim.org/mailinglist/). or our [mailinglist](https://imag-pim.org/mailinglist/).
## License ## License
We chose to distribute this software under terms of GNU LGPLv2.1. We chose to distribute this software under terms of GNU LGPLv2.1.

View file

@ -82,22 +82,18 @@ fn add(rt: &Runtime) {
let entry_name = scmd let entry_name = scmd
.value_of("entry") .value_of("entry")
.map(PathBuf::from) .map(PathBuf::from)
.map(|pb| pb.into_storeid().map_err_trace_exit(1).unwrap()) .map(|pb| pb.into_storeid().map_err_trace_exit_unwrap(1))
.unwrap(); // safed by clap .unwrap(); // safed by clap
let _ = rt.store() let _ = rt.store()
.get(entry_name) .get(entry_name)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.ok_or(AE::from("Entry does not exist".to_owned())) .ok_or(AE::from("Entry does not exist".to_owned()))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.annotate(rt.store(), annotation_name) .annotate(rt.store(), annotation_name)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.edit_content(&rt) .edit_content(&rt)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
info!("Ok"); info!("Ok");
} }
@ -109,17 +105,14 @@ fn remove(rt: &Runtime) {
let delete = scmd.is_present("delete-annotation"); let delete = scmd.is_present("delete-annotation");
let mut entry = rt.store() let mut entry = rt.store()
.get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit(1).unwrap()) .get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit_unwrap(1))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.ok_or(AE::from("Entry does not exist".to_owned())) .ok_or(AE::from("Entry does not exist".to_owned()))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
let annotation = entry let annotation = entry
.denotate(rt.store(), annotation_name) .denotate(rt.store(), annotation_name)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
if delete { if delete {
debug!("Deleting annotation object"); debug!("Deleting annotation object");
@ -130,8 +123,7 @@ fn remove(rt: &Runtime) {
let _ = rt let _ = rt
.store() .store()
.delete(loc) .delete(loc)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
} else { } else {
warn!("Not having annotation object, cannot delete!"); warn!("Not having annotation object, cannot delete!");
} }
@ -149,17 +141,14 @@ fn list(rt: &Runtime) {
Some(pb) => { Some(pb) => {
let _ = rt let _ = rt
.store() .store()
.get(pb.into_storeid().map_err_trace_exit(1).unwrap()) .get(pb.into_storeid().map_err_trace_exit_unwrap(1))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.ok_or(AE::from("Entry does not exist".to_owned())) .ok_or(AE::from("Entry does not exist".to_owned()))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.annotations(rt.store()) .annotations(rt.store())
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.enumerate() .enumerate()
.map(|(i, a)| list_annotation(i, a.map_err_trace_exit(1).unwrap(), with_text)) .map(|(i, a)| list_annotation(i, a.map_err_trace_exit_unwrap(1), with_text))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
@ -168,10 +157,9 @@ fn list(rt: &Runtime) {
let _ = rt let _ = rt
.store() .store()
.all_annotations() .all_annotations()
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.enumerate() .enumerate()
.map(|(i, a)| list_annotation(i, a.map_err_trace_exit(1).unwrap(), with_text)) .map(|(i, a)| list_annotation(i, a.map_err_trace_exit_unwrap(1), with_text))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
} }

View file

@ -100,8 +100,7 @@ fn main() {
let diags = rt.store() let diags = rt.store()
.entries() .entries()
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.into_get_iter(rt.store()) .into_get_iter(rt.store())
.map(|e| { .map(|e| {
e.map_err_trace_exit_unwrap(1) e.map_err_trace_exit_unwrap(1)

View file

@ -103,8 +103,7 @@ fn add(rt: &Runtime) {
.get(sid) .get(sid)
.map_err_trace_exit_unwrap(1) .map_err_trace_exit_unwrap(1)
.map(|mut entry| { .map(|mut entry| {
let _ = entry.set_coordinates(c) let _ = entry.set_coordinates(c).map_err_trace_exit_unwrap(1);
.map_err_trace_exit(1);
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
error!("No such entry: {}", entry_name); error!("No such entry: {}", entry_name);

View file

@ -106,7 +106,7 @@ fn main() {
} }
}) })
.ok_or(LE::from("No commandline call".to_owned())) .ok_or(LE::from("No commandline call".to_owned()))
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
} }
fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> { fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> {

View file

@ -75,7 +75,7 @@ fn main() {
let _ = rt let _ = rt
.store() .store()
.move_by_id(sourcename, destname) .move_by_id(sourcename, destname)
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
info!("Ok."); info!("Ok.");
} }

View file

@ -36,7 +36,7 @@ pub fn delete(rt: &Runtime) {
let _ = rt.store() let _ = rt.store()
.delete(path) .delete(path)
.map_warn_err(|e| format!("Error: {:?}", e)) .map_warn_err(|e| format!("Error: {:?}", e))
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
} }
#[cfg(test)] #[cfg(test)]

View file

@ -35,7 +35,7 @@ pub fn retrieve(rt: &Runtime) {
let id = scmd.value_of("id").unwrap(); let id = scmd.value_of("id").unwrap();
let path = PathBuf::from(id); let path = PathBuf::from(id);
let store = Some(rt.store().path().clone()); let store = Some(rt.store().path().clone());
let path = StoreId::new(store, path).map_err_trace_exit(1)?; let path = StoreId::new(store, path).map_err_trace_exit_unwrap(1);
debug!("path = {:?}", path); debug!("path = {:?}", path);
rt.store() rt.store()

View file

@ -163,7 +163,7 @@ fn main() {
} else { } else {
let _ = StdoutViewer::new(view_header, view_content) let _ = StdoutViewer::new(view_header, view_content)
.view_entry(&entry) .view_entry(&entry)
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
} }
} }

View file

@ -107,28 +107,24 @@ fn list(rt: &Runtime) {
let _ = rt let _ = rt
.store() .store()
.all_contacts() .all_contacts()
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap() // safed by above call
.into_get_iter(rt.store()) .into_get_iter(rt.store())
.map(|fle| { .map(|fle| {
let fle = fle let fle = fle
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.ok_or_else(|| CE::from("StoreId not found".to_owned())) .ok_or_else(|| CE::from("StoreId not found".to_owned()))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
fle fle
.get_contact_data() .get_contact_data()
.map(|cd| (fle, cd)) .map(|cd| (fle, cd))
.map(|(fle, cd)| (fle, cd.into_inner())) .map(|(fle, cd)| (fle, cd.into_inner()))
.map(|(fle, cd)| (fle, Vcard::from_component(cd))) .map(|(fle, cd)| (fle, Vcard::from_component(cd)))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
}) })
.enumerate() .enumerate()
.map(|(i, (fle, vcard))| { .map(|(i, (fle, vcard))| {
let hash = fle.get_path_hash().map_err_trace_exit(1).unwrap(); let hash = fle.get_path_hash().map_err_trace_exit_unwrap(1);
let vcard = vcard.unwrap_or_else(|e| { let vcard = vcard.unwrap_or_else(|e| {
error!("Element is not a VCARD object: {:?}", e); error!("Element is not a VCARD object: {:?}", e);
exit(1) exit(1)
@ -137,8 +133,7 @@ fn list(rt: &Runtime) {
let data = build_data_object_for_handlebars(i, hash, &vcard); let data = build_data_object_for_handlebars(i, hash, &vcard);
let s = list_format.render("format", &data) let s = list_format.render("format", &data)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
println!("{}", s); println!("{}", s);
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -157,18 +152,16 @@ fn import(rt: &Runtime) {
let _ = rt let _ = rt
.store() .store()
.create_from_path(&path) .create_from_path(&path)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
} else if path.is_dir() { } else if path.is_dir() {
for entry in WalkDir::new(path).min_depth(1).into_iter() { for entry in WalkDir::new(path).min_depth(1).into_iter() {
let entry = entry.map_err_trace_exit(1).unwrap(); let entry = entry.map_err_trace_exit_unwrap(1);
if entry.file_type().is_file() { if entry.file_type().is_file() {
let pb = PathBuf::from(entry.path()); let pb = PathBuf::from(entry.path());
let _ = rt let _ = rt
.store() .store()
.create_from_path(&pb) .create_from_path(&pb)
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1);
.unwrap();
info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>")); info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
} else { } else {
warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>")); warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
@ -186,14 +179,11 @@ fn show(rt: &Runtime) {
let contact_data = rt.store() let contact_data = rt.store()
.get_by_hash(hash.clone()) .get_by_hash(hash.clone())
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.ok_or(CE::from(format!("No entry for hash {}", hash))) .ok_or(CE::from(format!("No entry for hash {}", hash)))
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.get_contact_data() .get_contact_data()
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.unwrap()
.into_inner(); .into_inner();
let vcard = Vcard::from_component(contact_data) let vcard = Vcard::from_component(contact_data)
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
@ -204,9 +194,7 @@ fn show(rt: &Runtime) {
let show_format = get_contact_print_format("contact.show_format", rt, &scmd); let show_format = get_contact_print_format("contact.show_format", rt, &scmd);
let data = build_data_object_for_handlebars(0, hash, &vcard); let data = build_data_object_for_handlebars(0, hash, &vcard);
let s = show_format.render("format", &data) let s = show_format.render("format", &data).map_err_trace_exit_unwrap(1);
.map_err_trace_exit(1)
.unwrap();
println!("{}", s); println!("{}", s);
info!("Ok"); info!("Ok");
} }
@ -226,10 +214,7 @@ fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd:
}); });
let mut hb = Handlebars::new(); let mut hb = Handlebars::new();
let _ = hb let _ = hb.register_template_string("format", fmt).map_err_trace_exit_unwrap(1);
.register_template_string("format", fmt)
.map_err_trace_exit(1)
.unwrap();
hb.register_escape_fn(::handlebars::no_escape); hb.register_escape_fn(::handlebars::no_escape);
::libimaginteraction::format::register_all_color_helpers(&mut hb); ::libimaginteraction::format::register_all_color_helpers(&mut hb);

View file

@ -25,7 +25,7 @@ pub fn build_data_object_for_handlebars<'a>(i: usize, hash: String, vcard: &Vcar
{ {
data.insert("i" , format!("{}", i)); data.insert("i" , format!("{}", i));
/// The hash (as in libimagentryref) of the contact // The hash (as in libimagentryref) of the contact
data.insert("id" , hash); data.insert("id" , hash);
data.insert("ADR" , vcard.adr() data.insert("ADR" , vcard.adr()

View file

@ -79,7 +79,7 @@ fn create(rt: &Runtime) {
let _ = note let _ = note
.edit_content(rt) .edit_content(rt)
.map_warn_err_str("Editing failed") .map_warn_err_str("Editing failed")
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
} }
} }
@ -87,7 +87,7 @@ fn delete(rt: &Runtime) {
let _ = rt.store() let _ = rt.store()
.delete_note(name_from_cli(rt, "delete")) .delete_note(name_from_cli(rt, "delete"))
.map_info_str("Ok") .map_info_str("Ok")
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
} }
fn edit(rt: &Runtime) { fn edit(rt: &Runtime) {
@ -100,7 +100,7 @@ fn edit(rt: &Runtime) {
let _ = note let _ = note
.edit_content(rt) .edit_content(rt)
.map_warn_err_str("Editing failed") .map_warn_err_str("Editing failed")
.map_err_trace_exit(1); .map_err_trace_exit_unwrap(1);
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
error!("Cannot find note with name '{}'", name); error!("Cannot find note with name '{}'", name);
@ -110,27 +110,22 @@ fn edit(rt: &Runtime) {
fn list(rt: &Runtime) { fn list(rt: &Runtime) {
use std::cmp::Ordering; use std::cmp::Ordering;
rt.store() let _ = rt
.store()
.all_notes() .all_notes()
.map_err_trace_exit(1) .map_err_trace_exit_unwrap(1)
.map(|iter| {
let notes = iter
.filter_map(|noteid| rt.store().get(noteid).map_err_trace_exit_unwrap(1)) .filter_map(|noteid| rt.store().get(noteid).map_err_trace_exit_unwrap(1))
.sorted_by(|note_a, note_b| { .sorted_by(|note_a, note_b| if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) {
if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) {
return a.cmp(&b) return a.cmp(&b)
} else { } else {
return Ordering::Greater; return Ordering::Greater;
} })
}); .iter()
.for_each(|note| {
for note in notes.iter() {
note.get_name() note.get_name()
.map(|name| println!("{}", name)) .map(|name| println!("{}", name))
.map_err_trace() .map_err_trace()
.ok(); .ok();
} });
})
.ok();
} }

View file

@ -31,3 +31,4 @@ libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore"
libimagrt = { version = "0.6.0", path = "../../../lib/core/libimagrt" } libimagrt = { version = "0.6.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" }
libimagtimetrack = { version = "0.6.0", path = "../../../lib/domain/libimagtimetrack" } libimagtimetrack = { version = "0.6.0", path = "../../../lib/domain/libimagtimetrack" }
libimagutil = { version = "0.6.0", path = "../../../lib/etc/libimagutil" }

View file

@ -30,6 +30,7 @@ extern crate libimagerror;
extern crate libimagstore; extern crate libimagstore;
extern crate libimagrt; extern crate libimagrt;
extern crate libimagtimetrack; extern crate libimagtimetrack;
extern crate libimagutil;
mod cont; mod cont;
mod day; mod day;

View file

@ -29,9 +29,10 @@ use libimagrt::runtime::Runtime;
use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::timetracking::TimeTracking;
use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::tag::TimeTrackingTag;
use libimagtimetrack::timetrackingstore::*; use libimagtimetrack::timetrackingstore::*;
use libimagtimetrack::iter::get::GetTimeTrackIter;
use libimagtimetrack::iter::filter::has_end_time; use libimagtimetrack::iter::filter::has_end_time;
use libimagtimetrack::iter::filter::has_one_of_tags; use libimagtimetrack::iter::filter::has_one_of_tags;
use libimagutil::warn_result::*;
use libimagutil::debug_result::*;
pub fn stop(rt: &Runtime) -> i32 { pub fn stop(rt: &Runtime) -> i32 {
let (_, cmd) = rt.cli().subcommand(); let (_, cmd) = rt.cli().subcommand();
@ -74,41 +75,25 @@ pub fn stop(rt: &Runtime) -> i32 {
.collect() .collect()
}); });
let iter : GetTimeTrackIter = match rt.store().get_timetrackings() {
Ok(i) => i,
Err(e) => {
error!("Getting timetrackings failed");
trace_error(&e);
return 1
}
};
let filter = has_end_time.not().and(has_one_of_tags(&tags)); let filter = has_end_time.not().and(has_one_of_tags(&tags));
rt
.store()
.get_timetrackings()
.map_warn_err_str("Getting timetrackings failed")
.map_err_trace_exit_unwrap(1)
.trace_unwrap()
// Filter all timetrackings for the ones that are not yet ended. // Filter all timetrackings for the ones that are not yet ended.
iter.trace_unwrap() .filter(|e| filter.filter(e))
.filter_map(|elem| {
if filter.filter(&elem) {
Some(elem)
} else {
None
}
})
// for each of these timetrackings, end them // for each of these timetrackings, end them
// for each result, print the backtrace (if any) // for each result, print the backtrace (if any)
.fold(0, |acc, mut elem| match elem.set_end_datetime(stop_time.clone()) { .fold(0, |acc, mut elem| {
Err(e) => { // if there was an error elem.set_end_datetime(stop_time.clone())
trace_error(&e); // trace .map_dbg(|e| format!("Setting end time worked: {:?}", e))
1 // set exit code to 1 .map(|_| acc)
}, .map_err_trace_exit_unwrap(1)
Ok(_) => {
debug!("Setting end time worked: {:?}", elem);
// Keep the exit code
acc
}
}) })
} }

View file

@ -30,8 +30,6 @@ extern crate libimagtodo;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::io::stdin; use std::io::stdin;
use toml::Value;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagtodo::taskstore::TaskStore; use libimagtodo::taskstore::TaskStore;
@ -81,7 +79,6 @@ fn tw_hook(rt: &Runtime) {
} }
fn list(rt: &Runtime) { fn list(rt: &Runtime) {
use toml_query::read::TomlValueReadExt;
use toml_query::read::TomlValueReadTypeExt; use toml_query::read::TomlValueReadTypeExt;
let subcmd = rt.cli().subcommand_matches("list").unwrap(); let subcmd = rt.cli().subcommand_matches("list").unwrap();

View file

@ -58,7 +58,7 @@ in
pkgs.stdenv.mkDerivation rec { pkgs.stdenv.mkDerivation rec {
name = "imag-doc"; name = "imag-doc";
src = ./.; src = /var/empty;
version = "0.0.0"; version = "0.0.0";
buildInputs = [ env ]; buildInputs = [ env ];

View file

@ -6,30 +6,28 @@ All contributors agree to the
[developer certificate of origin](#developer-certificate-of-origin) [developer certificate of origin](#developer-certificate-of-origin)
by contributing to imag. by contributing to imag.
If you already have something in mind, go ahead with [the prerequisites
section](#prerequisites). If you don't know what you could do, start here.
## Without Github ## Without Github
Contributing without a github account is perfectly fine. Contributing without a github account is perfectly fine and actually encouraged
as we try to move away from github step by step.
Feel free to contact [us via our mailinglist](http://imag-pim.org/mailinglist/) Feel free to contact [us via our mailinglist](http://imag-pim.org/mailinglist/)
and/or submit patches via mail (use `git format-patch` and and/or submit patches via mail (use `git format-patch` and
`git send-email`, always add a cover letter to describe your submission). `git send-email`, always add a cover letter to describe your submission).
Also ensure that each commit has Also ensure that each commit submitted via email has
[a "Signed-off-by: " line](https://stackoverflow.com/questions/1962094/what-is-the-sign-off-feature-in-git-for). [a "Signed-off-by: " line](https://stackoverflow.com/questions/1962094/what-is-the-sign-off-feature-in-git-for).
By adding that line, you agree to our By adding that line, you agree to our
[developer certificate of origin](#developer-certificate-of-origin). [developer certificate of origin](#developer-certificate-of-origin).
If you do not add the "Signed-off-by: " line, If you do not add the "Signed-off-by: " line, I reserve the right to kindly
I reserve the right to reject your patch. reject your patch.
Once _I am_ okay with your patchset, I will Once _I am_ okay with your patchset, I will
submit it as PR in the github repository, so more people can review it and CI submit it as PR in the github repository (as long as we're using github),
can test it (the mailinglist is not yet used as much as github). I might come so CI can test it.
back to you if something broke in CI or someone has a suggestion how to improve I might come back to you if something broke in CI or someone has a suggestion
your PR. I will keep you as author of the commits. how to improve your PR. I will keep you as author of the commits.
The following sections describe the way how to contribute with github.
## Finding an issue ## Finding an issue
@ -43,13 +41,17 @@ code... you'll always find things to improve!
Also, if you've found bugs or outdated stuff in our documentation, feel free to Also, if you've found bugs or outdated stuff in our documentation, feel free to
file issues about them or even better: Write a pull request to fix them! file issues about them or even better: Write a pull request to fix them!
## Prerequisites ## Prerequisites
* cargo and rust compiler in current version (stable) The prerequisites are simple: `cargo` and `rustc` in current version (stable)
or newer (we do not use nighly features though).
Dependencies are listed in the Build dependencies for building are listed in the
[default.nix file](http://git.imag-pim.org/imag/tree/default.nix), [default.nix file](http://git.imag-pim.org/imag/tree/default.nix),
though you do not have to have `nix` installed to build imag. though you do not have to have the `nix` package manager installed to build
imag.
Everything else will be done by `cargo`.
Note that this software is targeted towards commandline linux users and we do Note that this software is targeted towards commandline linux users and we do
not aim to be portable to Windows or Mac OSX (though I wouldn't mind merging not aim to be portable to Windows or Mac OSX (though I wouldn't mind merging
@ -61,65 +63,40 @@ If you want to build the documentation (you don't have to) you'll need:
* pandoc-citeproc * pandoc-citeproc
* texlive * texlive
* lmodern (font package) * lmodern (font package)
* make * (gnu) make
All dependencies are installable with the nix package manager by using a All dependencies are installable with the nix package manager by using a
`nix-shell`, if you have the nix package manager installed on your system. `nix-shell`, if you have the nix package manager installed on your system.
## Commit guidelines ## Commit guidelines
Please don't refer to issues or PRs from inside a commit message, if possible. Please don't refer to issues or PRs from inside a commit message, if possible.
Make sure your PR does not contain "Fixup" commits when publishing it, but feel Make sure your PR does not contain "Fixup" commits when publishing it, but feel
free to push "Fixup" commits in the review process. We will ask you to clean free to push "Fixup" commits in the review process. We will ask you to clean
your history before merging! If you're submitting via patch-mail, I will do the your history before merging! If you're submitting via patch-mail, I will do the
fixup squashing myself. fixup squashing myself. If it fails I will come back to you.
Make sure to prefix your commits with `"doc: "` if you change the document. Do Make sure to prefix your commits with `"doc: "` if you change the documentation.
not change document and code in one commit, always separate them. Do not change document and code in one commit, always separate them.
If your changes are user-visible, make sure to add a note in the If your changes are user-visible (new commandline flags, other semantics in the
`CHANGELOG.md` file. commandline, etc), make sure to add a note in the `CHANGELOG.md` file (in the
same commit if it is a simple change).
We do not follow some official Rust styleguide for our codebase, but we try to We do not follow some official Rust styleguide for our codebase, but we try to
write minimal and readable code. 100 characters per line, as few lines as write minimal and readable code. 100 characters per line, as few lines as
possible, avoid noise in the codebase, ... you get it. possible, avoid noise in the codebase, ... you get it.
Not all of your commits have to be buildable. But your PR has to be. Not all of your commits have to be buildable. But your PR has to be before it
will be merged to master.
## PR guidelines
We'd like to have one PR per module change. This means you _should_ only change ## Feature branches
one imag module in one commit or PR (library plus belonging binary is okay).
As this is not always possible, we do not enforce this, though we might ask you
to split your commits/PR into two smaller ones.
Use feature branches. If you could name them "<module name>/<what you do>", Use feature branches. If you could name them "<module name>/<what you do>",
for example "libimagstore/add-debugging-calls", that would be awesome. for example "libimagstore/add-debugging-calls", that would be awesome.
You are welcome to publish your PR as soon as there is one commit in your
branch. This gives us the possibility to review whether your ideas go into a
nice direction or whether there are issues with your approach so we can report
them to you quickly. Rewriting a whole PR is not satisfactory and we'd
like to make your contribution process enjoyable for you.
# Merging tools which use the imag core functionality into this repo
If you're writing an application or module for imag, feel free to propose
integrating it into the imag core distribution, if it fulfills the following
requirements:
1. It is written in Rust
1. It has a commandline interface which is the main interface to the module
OR it is a utility library for creating new kinds of functionality within the
imag core.
The commandline interface should be structured like the existing interfaces
(as in commands, options and arguments).
1. It is licensed under the terms of GNU LGPLv2.1 OR all of your contributors
approve a commit which changes the license of your codebase to GNU LGPLv2.1
(The word "approve" in this sentence is to be defined).
If your tool does not fulfill these requirements, I won't merge it into the
imag core distribution.
## Code of Conduct ## Code of Conduct
@ -129,10 +106,6 @@ We use the same
Basically: Be kind, encourage others to ask questions - you are encouraged to Basically: Be kind, encourage others to ask questions - you are encouraged to
ask questions as well! ask questions as well!
## Contact
Feel free to reach out via mail/[mailinglist](http://imag-pim.org/mailinglist/)
or [IRC](irc://irc.freenode.net/#imag).
## Developer Certificate of Origin ## Developer Certificate of Origin

View file

@ -35,11 +35,17 @@ This section contains the changelog from the last release to the next release.
* Minor changes * Minor changes
* Internals were refactored from `match`ing all the things into function * Internals were refactored from `match`ing all the things into function
chaining chaining
* `libimagbookmark` does not longer wrap types from the store.
* The `toml-query` dependency was updated to 0.5.0 * The `toml-query` dependency was updated to 0.5.0
* `imag-timetrack list` lists with a table now * `imag-timetrack list` lists with a table now
* `imag-timetrack stop` now stops all runnings tags if none are specified * `imag-timetrack stop` now stops all running tags if none are specified
* The `toml-query` dependency was updated to 0.6.0
* `ResultExt::map_err_trace_exit()` was removed in favour of
`ResultExt::map_err_trace_exit_unwrap()`.
* Bugfixes * Bugfixes
* `libimagbookmark` contained a type which wrapped a `FileLockEntry` from
`libimagstore`. This was considered a bug and was fixed.
* We depended on a crate which was licensed as GPLv2, which would yield imag
GPL as well. The dependency was removed.
## 0.5.0 ## 0.5.0

View file

@ -118,7 +118,6 @@ pub trait MapErrTrace {
fn map_err_trace(self) -> Self; fn map_err_trace(self) -> Self;
fn map_err_dbg_trace(self) -> Self; fn map_err_dbg_trace(self) -> Self;
fn map_err_trace_exit(self, code: i32) -> Self;
fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output; fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output;
fn map_err_trace_maxdepth(self, max: u64) -> Self; fn map_err_trace_maxdepth(self, max: u64) -> Self;
} }
@ -140,16 +139,9 @@ impl<U, E: Error> MapErrTrace for Result<U, E> {
self.map_err(|e| { trace_error_dbg(&e); e }) self.map_err(|e| { trace_error_dbg(&e); e })
} }
/// Simply call `trace_error_exit(code)` on the Err (if there is one). /// Trace the error and exit or unwrap the Ok(_).
///
/// This does not return if there is an Err(e).
fn map_err_trace_exit(self, code: i32) -> Self {
self.map_err(|e| { trace_error_exit(&e, code) })
}
/// Helper for calling map_err_trace_exit(n).unwrap() in one call
fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output { fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output {
self.map_err_trace_exit(code).unwrap() self.map_err(|e| { trace_error_exit(&e, code) }).unwrap()
} }
/// Simply call `trace_error_maxdepth(max)` on the Err (if there is one) and return the error. /// Simply call `trace_error_maxdepth(max)` on the Err (if there is one) and return the error.

View file

@ -455,9 +455,17 @@ impl Store {
Walk::new(self.path().clone(), mod_name) Walk::new(self.path().clone(), mod_name)
} }
/// Return the `FileLockEntry` and write to disk /// Write (update) the `FileLockEntry` to disk
/// ///
/// See `Store::_update()`. /// # Return value
///
/// On success: Entry
///
/// On error:
/// - UpdateCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - IdNotFound() if the entry was not found in the stor
/// - Errors Entry::verify() might return
/// - Errors StoreEntry::write_entry() might return
/// ///
pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> { pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> {
debug!("Updating FileLockEntry at '{}'", entry.get_location()); debug!("Updating FileLockEntry at '{}'", entry.get_location());
@ -471,16 +479,6 @@ impl Store {
/// This method assumes that entry is dropped _right after_ the call, hence /// This method assumes that entry is dropped _right after_ the call, hence
/// it is not public. /// it is not public.
/// ///
/// # Return value
///
/// On success: Entry
///
/// On error:
/// - UpdateCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - IdNotFound() if the entry was not found in the stor
/// - Errors Entry::verify() might return
/// - Errors StoreEntry::write_entry() might return
///
fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> { fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?;

View file

@ -266,7 +266,7 @@ impl<'a> Iterator for CategoryNameIter<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// TODO: Optimize me with lazy_static // TODO: Optimize me with lazy_static
let query = String::from(CATEGORY_REGISTER_NAME_FIELD_PATH); let query = CATEGORY_REGISTER_NAME_FIELD_PATH;
self.1 self.1
.next() .next()
@ -275,7 +275,7 @@ impl<'a> Iterator for CategoryNameIter<'a> {
.get(sid)? .get(sid)?
.ok_or_else(|| CE::from_kind(CEK::StoreReadError))? .ok_or_else(|| CE::from_kind(CEK::StoreReadError))?
.get_header() .get_header()
.read_string(&query) .read_string(query)
.chain_err(|| CEK::HeaderReadError)? .chain_err(|| CEK::HeaderReadError)?
.map(Category::from) .map(Category::from)
.ok_or_else(|| CE::from_kind(CEK::StoreReadError)) .ok_or_else(|| CE::from_kind(CEK::StoreReadError))

View file

@ -634,12 +634,11 @@ pub mod store_check {
// //
// The lambda returns an error if something fails // The lambda returns an error if something fails
let aggregate_link_network = |store: &Store| -> Result<HashMap<StoreId, Linking>> { let aggregate_link_network = |store: &Store| -> Result<HashMap<StoreId, Linking>> {
let iter = store store
.entries()? .entries()?
.into_get_iter(store); .into_get_iter(store)
.fold(Ok(HashMap::new()), |map, element| {
let mut map = HashMap::new(); map.and_then(|mut map| {
for element in iter {
debug!("Checking element = {:?}", element); debug!("Checking element = {:?}", element);
let entry = element?.ok_or_else(|| { let entry = element?.ok_or_else(|| {
LE::from(String::from("TODO: Not yet handled")) LE::from(String::from("TODO: Not yet handled"))
@ -660,9 +659,9 @@ pub mod store_check {
} }
map.insert(entry.get_location().clone(), linking); map.insert(entry.get_location().clone(), linking);
}
Ok(map) Ok(map)
})
})
}; };
// Helper to check whethre all StoreIds in the network actually exists // Helper to check whethre all StoreIds in the network actually exists

10
scripts/commit-template Normal file
View file

@ -0,0 +1,10 @@
One line description of your change
Motivation:
Modifications:
Result:
# To use this template as commit template,
# call `git config commit.template <path of this file>

113
scripts/new-crate.sh Normal file
View file

@ -0,0 +1,113 @@
#!/usr/bin/env bash
# Helper script to create a new crate in the imag workspace
# 1. Creates a new crate
# 2. Adds the required crate meta information
# 3. Sets the version of the crate to the same version as libimagstore
# 4. Adds the crate to the top-level workspace
if [[ "$1" == "-h" || "$1" == "--help" ]];
then
echo "$0 [bin|lib] ./path/to/new/crate"
echo
echo "Execute _only_ from the top level of the repository"
exit 0
fi
crate_type="$1"
crate_location="$2"
exit_if_empty() {
[[ -z "$1" ]] && { echo "$2 not passed"; exit 1; }
}
exit_if_empty "$crate_type" "crate type"
exit_if_empty "$crate_location" "crate location"
exists_cmd() {
command -v $1 || { echo "No $1 found"; exit 1; }
}
exists_cmd "git"
exists_cmd "cargo"
{ cat ./Cargo.toml 2>/dev/null | head -n 1 | grep -q "[workspace]"; } || {
echo "Not in root of repository as it seems. Exiting";
exit 1;
}
[[ "$crate_type" == "lib" || "$crate_type" == "bin" ]] || {
echo "Invalid crate type, use 'lib' or 'bin'";
exit 1;
}
if [[ -e "$crate_location" ]]; then
echo "Crate exists: $crate_location"
exit 1;
fi
IFS=/ read -ra crate_name_parts <<< "$crate_location"
crate_name="${crate_name_parts[-1]}"
if [[ "$crate_type" == "lib" ]];
then
crate_description="Library for the imag core distribution"
else if [[ "$crate_type" == "bin" ]]; then
crate_description="Part of the imag core distribution: $crate_name command"
fi
git_name="$(git config user.name)"
git_email="$(git config user.email)"
store="lib/core/libimagstore/Cargo.toml"
crate_version=$(grep -m 1 version $store | cut -d '"' -f 2)
echo "Crate type: $crate_type"
echo "Crate location: $crate_location"
echo "Crate name: $crate_name"
echo "Crate version: $crate_version"
echo "Crate description: $crate_description"
echo "Crate author: $git_name <$git_email>"
echo "Not doing anything as this script is not ready yet."
echo "Exiting now"
exit 1
pushd "$(dirname $crate_location)"
crate new --${crate_type} $crate_name
cat <<EOS > ./$crate_name/Cargo.toml
[package]
name = "$crate_name"
version = "$crate_version"
authors = ["$git_name <$git_email>"]
description = "$crate_description"
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"
[badges]
travis-ci = { repository = "matthiasbeyer/imag" }
is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" }
is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
maintenance = { status = "actively-developed" }
[dependencies]
EOS
echo "Cargo.toml written. Please make sure that the README has the right path!"
popd
git add ${crate_location}/*
sed -i "$ s/]/ \"${crate_location}\",\n]/" Cargo.toml
echo "Top-level Cargo.toml modified. Please sort crate list manually!"