diff --git a/.gitignore b/.gitignore index 88f6183d..80cd5b4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Cargo.lock out target +.idea diff --git a/.travis.yml b/.travis.yml index 2d3311fc..38efdf12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,8 +29,9 @@ addons: - pkg-config 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: email: diff --git a/README.md b/README.md index ae0413b0..77ab2769 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,10 @@ Our (long-term) goal is to Yes, imag is a rather ambitious project as it tries to reimplement functionality 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 -possible. +keep that in mind. We try to use standards like vcard, icalendar and others +wherever possible. -imag consists of _modules_ (e.g. `imag-notes`, `imag-tag`, `imag-view`), where -each module covers one PIM aspect. Have a look at -[the documentation](./doc/) for some more words on this. +Have a look at [the documentation](./doc/) for some more words on this. ## 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 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 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-` (if the install-directory is in your `$PATH`), or install the `imag` binary to call `imag ` (also if everything is in your `$PATH`). + ## Staying up-to-date 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 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 updates and where discussion and questions are encouraged. + ## Documentation -This is a hobby project, so sometimes things are not optimal and might go -unrecognized and slip through. Feel free to open issues about things you notice! - -Though, we have some documentation in [the ./doc subtree](./doc/) +We have some documentation in [the ./doc subtree](./doc/) which can be compiled to PDF or a website. -These docs are not published anywhere and are not even integrated into our CI, -so it might be broken (though it's unlikely). -Developer documentation is also available -[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. +It might not be up to date, though. +Developer documentation for the last release is available +[on docs.rs](https://docs.rs/releases/search?query=imag). + ## Please contribute! We are looking for contributors! - Feel free to open issues for asking questions, suggesting features or other things! 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 -information on how to get in touch and so on. +## Contact Feel free to join our new IRC channel at freenode: #imag or our [mailinglist](https://imag-pim.org/mailinglist/). + ## License We chose to distribute this software under terms of GNU LGPLv2.1. + diff --git a/bin/core/imag-annotate/src/main.rs b/bin/core/imag-annotate/src/main.rs index 94cbd48a..92a2f92e 100644 --- a/bin/core/imag-annotate/src/main.rs +++ b/bin/core/imag-annotate/src/main.rs @@ -82,22 +82,18 @@ fn add(rt: &Runtime) { let entry_name = scmd .value_of("entry") .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 let _ = rt.store() .get(entry_name) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .ok_or(AE::from("Entry does not exist".to_owned())) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .annotate(rt.store(), annotation_name) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .edit_content(&rt) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); info!("Ok"); } @@ -109,17 +105,14 @@ fn remove(rt: &Runtime) { let delete = scmd.is_present("delete-annotation"); let mut entry = rt.store() - .get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit(1).unwrap()) - .map_err_trace_exit(1) - .unwrap() + .get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit_unwrap(1)) + .map_err_trace_exit_unwrap(1) .ok_or(AE::from("Entry does not exist".to_owned())) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); let annotation = entry .denotate(rt.store(), annotation_name) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); if delete { debug!("Deleting annotation object"); @@ -130,8 +123,7 @@ fn remove(rt: &Runtime) { let _ = rt .store() .delete(loc) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); } else { warn!("Not having annotation object, cannot delete!"); } @@ -149,17 +141,14 @@ fn list(rt: &Runtime) { Some(pb) => { let _ = rt .store() - .get(pb.into_storeid().map_err_trace_exit(1).unwrap()) - .map_err_trace_exit(1) - .unwrap() + .get(pb.into_storeid().map_err_trace_exit_unwrap(1)) + .map_err_trace_exit_unwrap(1) .ok_or(AE::from("Entry does not exist".to_owned())) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .annotations(rt.store()) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .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::>(); } @@ -168,10 +157,9 @@ fn list(rt: &Runtime) { let _ = rt .store() .all_annotations() - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .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::>(); } } diff --git a/bin/core/imag-diagnostics/src/main.rs b/bin/core/imag-diagnostics/src/main.rs index b9d2ee8f..7d3b06da 100644 --- a/bin/core/imag-diagnostics/src/main.rs +++ b/bin/core/imag-diagnostics/src/main.rs @@ -100,8 +100,7 @@ fn main() { let diags = rt.store() .entries() - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .into_get_iter(rt.store()) .map(|e| { e.map_err_trace_exit_unwrap(1) diff --git a/bin/core/imag-gps/src/main.rs b/bin/core/imag-gps/src/main.rs index 301f37a5..d3f3e532 100644 --- a/bin/core/imag-gps/src/main.rs +++ b/bin/core/imag-gps/src/main.rs @@ -103,8 +103,7 @@ fn add(rt: &Runtime) { .get(sid) .map_err_trace_exit_unwrap(1) .map(|mut entry| { - let _ = entry.set_coordinates(c) - .map_err_trace_exit(1); + let _ = entry.set_coordinates(c).map_err_trace_exit_unwrap(1); }) .unwrap_or_else(|| { error!("No such entry: {}", entry_name); diff --git a/bin/core/imag-link/src/main.rs b/bin/core/imag-link/src/main.rs index 76796a97..f775d030 100644 --- a/bin/core/imag-link/src/main.rs +++ b/bin/core/imag-link/src/main.rs @@ -106,7 +106,7 @@ fn main() { } }) .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>, StoreError> { diff --git a/bin/core/imag-mv/src/main.rs b/bin/core/imag-mv/src/main.rs index 7896e8f1..030763bf 100644 --- a/bin/core/imag-mv/src/main.rs +++ b/bin/core/imag-mv/src/main.rs @@ -75,7 +75,7 @@ fn main() { let _ = rt .store() .move_by_id(sourcename, destname) - .map_err_trace_exit(1); + .map_err_trace_exit_unwrap(1); info!("Ok."); } diff --git a/bin/core/imag-store/src/delete.rs b/bin/core/imag-store/src/delete.rs index f50cc9c0..766c1304 100644 --- a/bin/core/imag-store/src/delete.rs +++ b/bin/core/imag-store/src/delete.rs @@ -36,7 +36,7 @@ pub fn delete(rt: &Runtime) { let _ = rt.store() .delete(path) .map_warn_err(|e| format!("Error: {:?}", e)) - .map_err_trace_exit(1); + .map_err_trace_exit_unwrap(1); } #[cfg(test)] diff --git a/bin/core/imag-store/src/retrieve.rs b/bin/core/imag-store/src/retrieve.rs index 905fe98d..4c3b25c1 100644 --- a/bin/core/imag-store/src/retrieve.rs +++ b/bin/core/imag-store/src/retrieve.rs @@ -35,7 +35,7 @@ pub fn retrieve(rt: &Runtime) { let id = scmd.value_of("id").unwrap(); let path = PathBuf::from(id); 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); rt.store() diff --git a/bin/core/imag-view/src/main.rs b/bin/core/imag-view/src/main.rs index ef3b3304..eba2245a 100644 --- a/bin/core/imag-view/src/main.rs +++ b/bin/core/imag-view/src/main.rs @@ -163,7 +163,7 @@ fn main() { } else { let _ = StdoutViewer::new(view_header, view_content) .view_entry(&entry) - .map_err_trace_exit(1); + .map_err_trace_exit_unwrap(1); } } diff --git a/bin/domain/imag-contact/src/main.rs b/bin/domain/imag-contact/src/main.rs index fe8cddc5..2747b94c 100644 --- a/bin/domain/imag-contact/src/main.rs +++ b/bin/domain/imag-contact/src/main.rs @@ -107,28 +107,24 @@ fn list(rt: &Runtime) { let _ = rt .store() .all_contacts() - .map_err_trace_exit(1) - .unwrap() // safed by above call + .map_err_trace_exit_unwrap(1) .into_get_iter(rt.store()) .map(|fle| { let fle = fle - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .ok_or_else(|| CE::from("StoreId not found".to_owned())) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); fle .get_contact_data() .map(|cd| (fle, cd)) .map(|(fle, cd)| (fle, cd.into_inner())) .map(|(fle, cd)| (fle, Vcard::from_component(cd))) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) }) .enumerate() .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| { error!("Element is not a VCARD object: {:?}", e); exit(1) @@ -137,8 +133,7 @@ fn list(rt: &Runtime) { let data = build_data_object_for_handlebars(i, hash, &vcard); let s = list_format.render("format", &data) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); println!("{}", s); }) .collect::>(); @@ -157,18 +152,16 @@ fn import(rt: &Runtime) { let _ = rt .store() .create_from_path(&path) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); } else if path.is_dir() { 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() { let pb = PathBuf::from(entry.path()); let _ = rt .store() .create_from_path(&pb) - .map_err_trace_exit(1) - .unwrap(); + .map_err_trace_exit_unwrap(1); info!("Imported: {}", entry.path().to_str().unwrap_or("")); } else { warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("")); @@ -186,14 +179,11 @@ fn show(rt: &Runtime) { let contact_data = rt.store() .get_by_hash(hash.clone()) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .ok_or(CE::from(format!("No entry for hash {}", hash))) - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .get_contact_data() - .map_err_trace_exit(1) - .unwrap() + .map_err_trace_exit_unwrap(1) .into_inner(); let vcard = Vcard::from_component(contact_data) .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 data = build_data_object_for_handlebars(0, hash, &vcard); - let s = show_format.render("format", &data) - .map_err_trace_exit(1) - .unwrap(); + let s = show_format.render("format", &data).map_err_trace_exit_unwrap(1); println!("{}", s); 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 _ = hb - .register_template_string("format", fmt) - .map_err_trace_exit(1) - .unwrap(); + let _ = hb.register_template_string("format", fmt).map_err_trace_exit_unwrap(1); hb.register_escape_fn(::handlebars::no_escape); ::libimaginteraction::format::register_all_color_helpers(&mut hb); diff --git a/bin/domain/imag-contact/src/util.rs b/bin/domain/imag-contact/src/util.rs index e85a6a8a..e194a86d 100644 --- a/bin/domain/imag-contact/src/util.rs +++ b/bin/domain/imag-contact/src/util.rs @@ -25,7 +25,7 @@ pub fn build_data_object_for_handlebars<'a>(i: usize, hash: String, vcard: &Vcar { 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("ADR" , vcard.adr() diff --git a/bin/domain/imag-notes/src/main.rs b/bin/domain/imag-notes/src/main.rs index e3234393..d04208e6 100644 --- a/bin/domain/imag-notes/src/main.rs +++ b/bin/domain/imag-notes/src/main.rs @@ -79,7 +79,7 @@ fn create(rt: &Runtime) { let _ = note .edit_content(rt) .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() .delete_note(name_from_cli(rt, "delete")) .map_info_str("Ok") - .map_err_trace_exit(1); + .map_err_trace_exit_unwrap(1); } fn edit(rt: &Runtime) { @@ -100,7 +100,7 @@ fn edit(rt: &Runtime) { let _ = note .edit_content(rt) .map_warn_err_str("Editing failed") - .map_err_trace_exit(1); + .map_err_trace_exit_unwrap(1); }) .unwrap_or_else(|| { error!("Cannot find note with name '{}'", name); @@ -110,27 +110,22 @@ fn edit(rt: &Runtime) { fn list(rt: &Runtime) { use std::cmp::Ordering; - rt.store() + let _ = rt + .store() .all_notes() - .map_err_trace_exit(1) - .map(|iter| { - let notes = iter - .filter_map(|noteid| rt.store().get(noteid).map_err_trace_exit_unwrap(1)) - .sorted_by(|note_a, note_b| { - if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) { - return a.cmp(&b) - } else { - return Ordering::Greater; - } - }); - - for note in notes.iter() { - note.get_name() - .map(|name| println!("{}", name)) - .map_err_trace() - .ok(); - } + .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| if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) { + return a.cmp(&b) + } else { + return Ordering::Greater; }) - .ok(); + .iter() + .for_each(|note| { + note.get_name() + .map(|name| println!("{}", name)) + .map_err_trace() + .ok(); + }); } diff --git a/bin/domain/imag-timetrack/Cargo.toml b/bin/domain/imag-timetrack/Cargo.toml index e3708209..562310d1 100644 --- a/bin/domain/imag-timetrack/Cargo.toml +++ b/bin/domain/imag-timetrack/Cargo.toml @@ -31,3 +31,4 @@ libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore" libimagrt = { version = "0.6.0", path = "../../../lib/core/libimagrt" } libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" } libimagtimetrack = { version = "0.6.0", path = "../../../lib/domain/libimagtimetrack" } +libimagutil = { version = "0.6.0", path = "../../../lib/etc/libimagutil" } diff --git a/bin/domain/imag-timetrack/src/main.rs b/bin/domain/imag-timetrack/src/main.rs index 6d736cb0..28d659e1 100644 --- a/bin/domain/imag-timetrack/src/main.rs +++ b/bin/domain/imag-timetrack/src/main.rs @@ -30,6 +30,7 @@ extern crate libimagerror; extern crate libimagstore; extern crate libimagrt; extern crate libimagtimetrack; +extern crate libimagutil; mod cont; mod day; diff --git a/bin/domain/imag-timetrack/src/stop.rs b/bin/domain/imag-timetrack/src/stop.rs index d0f17ea8..a3ac47cb 100644 --- a/bin/domain/imag-timetrack/src/stop.rs +++ b/bin/domain/imag-timetrack/src/stop.rs @@ -29,9 +29,10 @@ use libimagrt::runtime::Runtime; use libimagtimetrack::timetracking::TimeTracking; use libimagtimetrack::tag::TimeTrackingTag; use libimagtimetrack::timetrackingstore::*; -use libimagtimetrack::iter::get::GetTimeTrackIter; use libimagtimetrack::iter::filter::has_end_time; use libimagtimetrack::iter::filter::has_one_of_tags; +use libimagutil::warn_result::*; +use libimagutil::debug_result::*; pub fn stop(rt: &Runtime) -> i32 { let (_, cmd) = rt.cli().subcommand(); @@ -74,41 +75,25 @@ pub fn stop(rt: &Runtime) -> i32 { .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)); + 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. - iter.trace_unwrap() - .filter_map(|elem| { - if filter.filter(&elem) { - Some(elem) - } else { - None - } + // Filter all timetrackings for the ones that are not yet ended. + .filter(|e| filter.filter(e)) + + // for each of these timetrackings, end them + // for each result, print the backtrace (if any) + .fold(0, |acc, mut elem| { + elem.set_end_datetime(stop_time.clone()) + .map_dbg(|e| format!("Setting end time worked: {:?}", e)) + .map(|_| acc) + .map_err_trace_exit_unwrap(1) }) - - // for each of these timetrackings, end them - // for each result, print the backtrace (if any) - .fold(0, |acc, mut elem| match elem.set_end_datetime(stop_time.clone()) { - Err(e) => { // if there was an error - trace_error(&e); // trace - 1 // set exit code to 1 - }, - Ok(_) => { - debug!("Setting end time worked: {:?}", elem); - - // Keep the exit code - acc - } - }) } diff --git a/bin/domain/imag-todo/src/main.rs b/bin/domain/imag-todo/src/main.rs index 8a2c88c1..36453c1d 100644 --- a/bin/domain/imag-todo/src/main.rs +++ b/bin/domain/imag-todo/src/main.rs @@ -30,8 +30,6 @@ 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::taskstore::TaskStore; @@ -81,7 +79,6 @@ fn tw_hook(rt: &Runtime) { } fn list(rt: &Runtime) { - use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadTypeExt; let subcmd = rt.cli().subcommand_matches("list").unwrap(); diff --git a/doc/default.nix b/doc/default.nix index 0146b71c..309682fc 100644 --- a/doc/default.nix +++ b/doc/default.nix @@ -58,7 +58,7 @@ in pkgs.stdenv.mkDerivation rec { name = "imag-doc"; - src = ./.; + src = /var/empty; version = "0.0.0"; buildInputs = [ env ]; diff --git a/doc/src/09010-contributing.md b/doc/src/09010-contributing.md index baea4872..d643aa34 100644 --- a/doc/src/09010-contributing.md +++ b/doc/src/09010-contributing.md @@ -6,30 +6,28 @@ All contributors agree to the [developer certificate of origin](#developer-certificate-of-origin) 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 -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/) and/or submit patches via mail (use `git format-patch` and `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). By adding that line, you agree to our [developer certificate of origin](#developer-certificate-of-origin). -If you do not add the "Signed-off-by: " line, -I reserve the right to reject your patch. +If you do not add the "Signed-off-by: " line, I reserve the right to kindly +reject your patch. 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 -can test it (the mailinglist is not yet used as much as github). I might come -back to you if something broke in CI or someone has a suggestion how to improve -your PR. I will keep you as author of the commits. +submit it as PR in the github repository (as long as we're using github), +so CI can test it. +I might come back to you if something broke in CI or someone has a suggestion +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 @@ -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 file issues about them or even better: Write a pull request to fix them! + ## 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), -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 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 * texlive * lmodern (font package) -* make +* (gnu) make 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. + ## Commit guidelines 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 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 -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 -not change document and code in one commit, always separate them. +Make sure to prefix your commits with `"doc: "` if you change the documentation. +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 -`CHANGELOG.md` file. +If your changes are user-visible (new commandline flags, other semantics in the +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 write minimal and readable code. 100 characters per line, as few lines as 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 -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. +## Feature branches Use feature branches. If you could name them "/", 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 @@ -129,10 +106,6 @@ We use the same Basically: Be kind, encourage others to ask questions - you are encouraged to 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 diff --git a/doc/src/09020-changelog.md b/doc/src/09020-changelog.md index 4756bc83..6a848e15 100644 --- a/doc/src/09020-changelog.md +++ b/doc/src/09020-changelog.md @@ -35,11 +35,17 @@ This section contains the changelog from the last release to the next release. * Minor changes * Internals were refactored from `match`ing all the things into function chaining - * `libimagbookmark` does not longer wrap types from the store. * The `toml-query` dependency was updated to 0.5.0 * `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 + * `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 diff --git a/lib/core/libimagerror/src/trace.rs b/lib/core/libimagerror/src/trace.rs index 2ec33a6a..7df6b288 100644 --- a/lib/core/libimagerror/src/trace.rs +++ b/lib/core/libimagerror/src/trace.rs @@ -118,7 +118,6 @@ pub trait MapErrTrace { fn map_err_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_maxdepth(self, max: u64) -> Self; } @@ -140,16 +139,9 @@ impl MapErrTrace for Result { self.map_err(|e| { trace_error_dbg(&e); e }) } - /// Simply call `trace_error_exit(code)` on the Err (if there is one). - /// - /// 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 + /// Trace the error and exit or unwrap the Ok(_). 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. diff --git a/lib/core/libimagstore/src/store.rs b/lib/core/libimagstore/src/store.rs index 9a41e75c..365576e0 100644 --- a/lib/core/libimagstore/src/store.rs +++ b/lib/core/libimagstore/src/store.rs @@ -455,9 +455,17 @@ impl Store { 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<()> { 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 /// 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<()> { let mut hsmap = self.entries.write().map_err(|_| SE::from_kind(SEK::LockPoisoned))?; diff --git a/lib/entry/libimagentrycategory/src/register.rs b/lib/entry/libimagentrycategory/src/register.rs index 4d21c37a..219d267c 100644 --- a/lib/entry/libimagentrycategory/src/register.rs +++ b/lib/entry/libimagentrycategory/src/register.rs @@ -266,7 +266,7 @@ impl<'a> Iterator for CategoryNameIter<'a> { fn next(&mut self) -> Option { // TODO: Optimize me with lazy_static - let query = String::from(CATEGORY_REGISTER_NAME_FIELD_PATH); + let query = CATEGORY_REGISTER_NAME_FIELD_PATH; self.1 .next() @@ -275,7 +275,7 @@ impl<'a> Iterator for CategoryNameIter<'a> { .get(sid)? .ok_or_else(|| CE::from_kind(CEK::StoreReadError))? .get_header() - .read_string(&query) + .read_string(query) .chain_err(|| CEK::HeaderReadError)? .map(Category::from) .ok_or_else(|| CE::from_kind(CEK::StoreReadError)) diff --git a/lib/entry/libimagentrylink/src/internal.rs b/lib/entry/libimagentrylink/src/internal.rs index dec86c1c..d7cddb69 100644 --- a/lib/entry/libimagentrylink/src/internal.rs +++ b/lib/entry/libimagentrylink/src/internal.rs @@ -634,35 +634,34 @@ pub mod store_check { // // The lambda returns an error if something fails let aggregate_link_network = |store: &Store| -> Result> { - let iter = store + store .entries()? - .into_get_iter(store); + .into_get_iter(store) + .fold(Ok(HashMap::new()), |map, element| { + map.and_then(|mut map| { + debug!("Checking element = {:?}", element); + let entry = element?.ok_or_else(|| { + LE::from(String::from("TODO: Not yet handled")) + })?; - let mut map = HashMap::new(); - for element in iter { - debug!("Checking element = {:?}", element); - let entry = element?.ok_or_else(|| { - LE::from(String::from("TODO: Not yet handled")) - })?; + debug!("Checking entry = {:?}", entry.get_location()); - debug!("Checking entry = {:?}", entry.get_location()); + let internal_links = entry + .get_internal_links()? + .into_getter(store); // get the FLEs from the Store - let internal_links = entry - .get_internal_links()? - .into_getter(store); // get the FLEs from the Store + let mut linking = Linking::default(); + for internal_link in internal_links { + debug!("internal link = {:?}", internal_link); - let mut linking = Linking::default(); - for internal_link in internal_links { - debug!("internal link = {:?}", internal_link); + linking.outgoing.push(internal_link?.get_location().clone()); + linking.incoming.push(entry.get_location().clone()); + } - linking.outgoing.push(internal_link?.get_location().clone()); - linking.incoming.push(entry.get_location().clone()); - } - - map.insert(entry.get_location().clone(), linking); - } - - Ok(map) + map.insert(entry.get_location().clone(), linking); + Ok(map) + }) + }) }; // Helper to check whethre all StoreIds in the network actually exists diff --git a/scripts/commit-template b/scripts/commit-template new file mode 100644 index 00000000..62cc46c5 --- /dev/null +++ b/scripts/commit-template @@ -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 diff --git a/scripts/new-crate.sh b/scripts/new-crate.sh new file mode 100644 index 00000000..b0178088 --- /dev/null +++ b/scripts/new-crate.sh @@ -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 < ./$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!" +