Merge branch 'minor'

This commit is contained in:
Matthias Beyer 2018-11-09 22:11:39 +01:00
commit 47707bf593
14 changed files with 270 additions and 307 deletions

View file

@ -1,165 +0,0 @@
# imag Community Code of Conduct
This document was adapted from the KDE code of conduct.
## Preamble
This document offers some guidance to ensure imag participants and contributors
can cooperate
effectively in a positive and inspiring atmosphere, and to explain how together
we can strengthen and support each other.
This Code of Conduct is shared by all contributors and users who engage with the
imag team and its community services.
## Overview
This Code of Conduct presents a summary of the shared values and “common sense”
thinking in our community. The basic social ingredients that hold our project
together include:
Be considerate
Be respectful
Be collaborative
Be pragmatic
Support others in the community
Get support from others in the community
Our community is made up of several groups of individuals and organizations
which can roughly be divided into two groups:
Contributors, or those who add value to the project through improving imag
software and its services
Users, or those who add value to the project through their support as
consumers of imag software
This Code of Conduct reflects the agreed standards of behavior for members of
the imag community, in any forum, mailing list, wiki, web site, IRC channel,
public meeting or private correspondence within the context of the imag team and
its services. The community acts according to the standards written down in this
Code of Conduct and will defend these standards for the benefit of the
community. Leaders of any group, such as moderators of mailing lists, IRC
channels, forums, etc., will exercise the right to suspend access to any person
who persistently breaks our shared Code of Conduct.
## Be considerate
Your actions and work will affect and be used by other people and you in turn
will depend on the work and actions of others. Any decision you take will affect
other community members, and we expect you to take those consequences into
account when making decisions.
As a contributor, ensure that you give full credit for the work of others and
bear in mind how your changes affect others. It is also expected that you try to
follow the development schedule and guidelines.
As a user, remember that contributors work hard on their part of imag and take
great pride in it. If you are frustrated your problems are more likely to be
resolved if you can give accurate and well-mannered information to all
concerned.
## Be respectful
In order for the imag community to stay healthy its members must feel
comfortable and accepted. Treating one another with respect is absolutely
necessary for this. In a disagreement, in the first instance assume that people
mean well.
We do not tolerate personal attacks, racism, sexism or any other form of
discrimination. Disagreement is inevitable, from time to time, but respect for
the views of others will go a long way to winning respect for your own view.
Respecting other people, their work, their contributions and assuming
well-meaning motivation will make community members feel comfortable and safe
and will result in motivation and productivity.
We expect members of our community to be respectful when dealing with other
contributors, users and communities. Remember that imag is an international
project and that you may be unaware of important aspects of other cultures.
## Be collaborative
The Free Software Movement depends on collaboration: it helps limit duplication
of effort while improving the quality of the software produced. In order to
avoid misunderstanding, try to be clear and concise when requesting help or
giving it. Remember it is easy to misunderstand emails (especially when they are
not written in your mother tongue). Ask for clarifications if unsure how
something is meant; remember the first rule — assume in the first instance that
people mean well.
As a contributor, you should aim to collaborate with other community members, as
well as with other communities that are interested in or depend on the work you
do. Your work should be transparent and be fed back into the community when
available, not just when imag releases. If you wish to work on something new
in existing projects, keep those projects informed of your ideas and progress.
It may not always be possible to reach consensus on the implementation of an
idea, so don't feel obliged to achieve this before you begin. However, always
ensure that you keep the outside world informed of your work, and publish it in
a way that allows outsiders to test, discuss and contribute to your efforts.
Contributors on every project come and go. When you leave or disengage from the
project, in whole or in part, you should do so with pride about what you have
achieved and by acting responsibly towards others who come after you to continue
the project.
As a user, your feedback is important, as is its form. Poorly thought out
comments can cause pain and the demotivation of other community members, but
considerate discussion of problems can bring positive results. An encouraging
word works wonders.
## Be pragmatic
imag is a pragmatic community. We value tangible results over having the last
word in a discussion. We defend our core values like freedom and respectful
collaboration, but we don't let arguments about minor issues get in the way of
achieving more important results. We are open to suggestions and welcome
solutions regardless of their origin. When in doubt support a solution which
helps getting things done over one which has theoretical merits, but isn't being
worked on. Use the tools and methods which help getting the job done. Let
decisions be taken by those who do the work.
## Support others in the community
Our community is made strong by mutual respect, collaboration and pragmatic,
responsible behavior. Sometimes there are situations where this has to be
defended and other community members need help.
If you witness others being attacked, think first about how you can offer them
personal support. If you feel that the situation is beyond your ability to help
individually, go privately to the victim and ask if some form of official
intervention is needed. Similarly you should support anyone who appears to be in
danger of burning out, either through work-related stress or personal problems.
When problems do arise, consider respectfully reminding those involved of our
shared Code of Conduct as a first action. Leaders are defined by their actions,
and can help set a good example by working to resolve issues in the spirit of
this Code of Conduct before they escalate.
## Get support from others in the community
Disagreements, both political and technical, happen all the time. Our community
is no exception to the rule. The goal is not to avoid disagreements or differing
views but to resolve them constructively. You should turn to the community to
seek advice and to resolve disagreements and where possible consult the team
most directly involved.
Think deeply before turning a disagreement into a public dispute. If necessary
request mediation, trying to resolve differences in a less highly-emotional
medium. If you do feel that you or your work is being attacked, take your time
to breathe through before writing heated replies. Consider a 24-hour moratorium
if emotional language is being used — a cooling off period is sometimes all that
is needed. If you really want to go a different way, then we encourage you
to publish your ideas and your work, so that it can be tried and tested.
This document is licensed under the Creative Commons Attribution - Share Alike
3.0 License.

View file

@ -13,7 +13,7 @@ early 2019. I hope I can continue develop imag during that time, but I cannot
guarantee that. I hope I can continue development of imag after that and I
certainly plan to do so.
But from May 2018 until early 2019, expect long response times.
But from May 2018 until February 2019, expect long response times.
## Goal / What is imag?
@ -84,7 +84,7 @@ imag diary -p private create
# Uh, I forgot something in a diary entry, select one (or multiple) and edit it
# use the `fzf` tool here (not a part of imag) to select from the IDs
imag diary -p private list | fzf -m | imag edit -I
imag diary -p private list | fzf -m | imag edit
# Link a contact to the diary entry
imag link diary/private/2018/01/01/00:00:00 contact/bc222298-casf-40a4-bda1-50aa980a68c9
@ -97,8 +97,9 @@ imag notes create "pineapple"
# Where was that contact again?
imag grep Eva # also possible with `imag contact find Eva`
# Okay, we need to add some imag-internal notes to that contact
imag grep Eva -l | imag edit -I
imag grep Eva -l | imag edit
# Now save our work
imag git add . # "imag-git" simply calls git in the imag store

View file

@ -57,6 +57,7 @@ use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{MapErrTrace, trace_error};
use libimagerror::io::ToExitCode;
use libimagerror::exit::ExitUnwrap;
use libimagutil::debug_result::DebugResult;
mod ui;
@ -152,14 +153,16 @@ fn list(rt: &Runtime) {
.report_touched(collection.get_location())
.map_err_trace_exit_unwrap(1);
let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1);
debug!("Listing...");
for (i, link) in links.enumerate() {
match link {
collection
.links(rt.store())
.map_dbg_str("Listing...")
.map_err_trace_exit_unwrap(1)
.into_iter()
.enumerate()
.for_each(|(i, link)| match link {
Ok(link) => writeln!(rt.stdout(), "{: >3}: {}", i, link).to_exit_code().unwrap_or_exit(),
Err(e) => trace_error(&e)
}
};
});
debug!("... ready with listing");
}

View file

@ -142,17 +142,13 @@ fn list(rt: &Runtime) {
}
}
} else {
let rendered = iterator
let output = rt.stdout();
let mut output = output.lock();
iterator
.map(|(i, dvcard)| build_data_object_for_handlebars(i, &dvcard))
.map(|data| list_format.render("format", &data).map_err(Error::from))
.trace_unwrap_exit(1)
.collect::<Vec<String>>();
// collect, so that we can have rendered all the things and printing is faster.
let output = rt.stdout();
let mut output = output.lock();
rendered.into_iter().for_each(|s| {
.for_each(|s| {
writeln!(output, "{}", s).to_exit_code().unwrap_or_exit()
});
}

View file

@ -30,6 +30,8 @@ use libimagentryedit::edit::Edit;
use libimagrt::runtime::Runtime;
use libimagerror::trace::MapErrTrace;
use libimagutil::warn_exit::warn_exit;
use libimagutil::debug_result::DebugResult;
use libimagutil::debug_option::DebugOption;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
@ -76,7 +78,7 @@ fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLock
}
})
.map(|timed| {
let time = create_id_from_clispec(&create, &diaryname, timed);
let time = create_id_from_clispec(&create, timed);
diary.new_entry_at(&diaryname, &time)
.context(err_msg("Store write error"))
.map_err(Error::from)
@ -85,15 +87,12 @@ fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLock
debug!("Creating non-timed entry");
diary.new_entry_today(diaryname)
})
.map(|e| {
debug!("Created: {}", e.get_location());
e
})
.map_dbg(|e| format!("Created: {}", e.get_location()))
.map_err_trace_exit_unwrap(1)
}
fn create_id_from_clispec(create: &ArgMatches, diaryname: &str, timed_type: Timed) -> NaiveDateTime {
fn create_id_from_clispec(create: &ArgMatches, timed_type: Timed) -> NaiveDateTime {
use std::str::FromStr;
let dt = Local::now();
@ -120,7 +119,7 @@ fn create_id_from_clispec(create: &ArgMatches, diaryname: &str, timed_type: Time
Timed::Minutely => {
let min = create
.value_of("minute")
.map(|m| { debug!("minute = {:?}", m); m })
.map_dbg(|m| format!("minute = {:?}", m))
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse minute: '{}'", s))
@ -140,7 +139,7 @@ fn create_id_from_clispec(create: &ArgMatches, diaryname: &str, timed_type: Time
Timed::Secondly => {
let min = create
.value_of("minute")
.map(|m| { debug!("minute = {:?}", m); m })
.map_dbg(|m| format!("minute = {:?}", m))
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse minute: '{}'", s))
@ -150,7 +149,7 @@ fn create_id_from_clispec(create: &ArgMatches, diaryname: &str, timed_type: Time
let sec = create
.value_of("second")
.map(|s| { debug!("second = {:?}", s); s })
.map_dbg(|s| format!("second = {:?}", s))
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse second: '{}'", s))

View file

@ -315,7 +315,7 @@ fn today(rt: &Runtime, future: bool) {
info!("No Habits due today.");
info!("Upcoming:");
// list `n` which are relevant in the future.
for element in relevant.iter().take(n) {
relevant.iter().take(n).for_each(|element| {
let date = element.next_instance_date().map_err_trace_exit_unwrap(1);
let name = element.habit_name().map_err_trace_exit_unwrap(1);
@ -328,7 +328,7 @@ fn today(rt: &Runtime, future: bool) {
info!(" * {date}: {name}", date = date, name = name);
}
}
}
});
} else {
fn lister_fn(h: &FileLockEntry) -> Vec<String> {
debug!("Listing: {:?}", h);
@ -354,9 +354,9 @@ fn today(rt: &Runtime, future: bool) {
table.set_titles(Row::new(header));
let mut empty = true;
for (i, e) in relevant.into_iter()
.filter(|habit| {
show_done || {
relevant
.into_iter()
.filter(|habit| show_done || {
habit
.next_instance_date()
.map_err_trace_exit_unwrap(1)
@ -365,10 +365,9 @@ fn today(rt: &Runtime, future: bool) {
.map_err_trace_exit_unwrap(1)
})
.unwrap_or(false)
}
})
.enumerate()
{
.for_each(|(i, e)| {
let mut v = vec![format!("{}", i)];
let mut list = lister_fn(&e);
@ -381,7 +380,7 @@ fn today(rt: &Runtime, future: bool) {
v.append(&mut list);
table.add_row(v.iter().map(|s| Cell::new(s)).collect());
empty = false;
}
});
if !empty {
let _ = table.print(&mut rt.stdout()).to_exit_code().unwrap_or_exit();

View file

@ -140,8 +140,7 @@ fn show(rt: &Runtime) {
}
};
for iter in iters {
let _ = iter
Itertools::flatten(iters.into_iter())
.into_get_iter(rt.store())
.trace_unwrap_exit(1)
.filter_map(|opt| {
@ -153,10 +152,10 @@ fn show(rt: &Runtime) {
})
.filter(|e| e.is_log().map_err_trace_exit_unwrap(1))
.map(|entry| (entry.diary_id().map_err_trace_exit_unwrap(1), entry))
.sorted_by_key(|&(ref id, _)| id.clone())
.sorted_by_key(|tpl| tpl.0.clone())
.into_iter()
.map(|tpl| { debug!("Found entry: {:?}", tpl.1); tpl })
.map(|(id, entry)| {
debug!("Found entry: {:?}", entry);
let _ = writeln!(rt.stdout(),
"{dname: >10} - {y: >4}-{m:0>2}-{d:0>2}T{H:0>2}:{M:0>2} - {text}",
dname = id.diary_name(),
@ -176,7 +175,6 @@ fn show(rt: &Runtime) {
.collect::<Result<Vec<()>, ExitCode>>()
.unwrap_or_exit();
}
}
fn get_diary_name(rt: &Runtime) -> String {
use toml_query::read::TomlValueReadExt;
@ -187,28 +185,6 @@ fn get_diary_name(rt: &Runtime) -> String {
.ok_or_else(|| Error::from(err_msg("Configuration not present, cannot continue")))
.map_err_trace_exit_unwrap(1);
let logs = cfg
.read("log.logs")
.map_err(Error::from)
.map_err_trace_exit_unwrap(1)
.ok_or_else(|| Error::from(err_msg("Configuration missing: 'log.logs'")))
.map_err_trace_exit_unwrap(1)
.as_array()
.ok_or_else(|| Error::from(err_msg("Configuration 'log.logs' is not an Array")))
.map_err_trace_exit_unwrap(1);
if !logs.iter().all(|e| is_match!(e, &Value::String(_))) {
error!("Configuration 'log.logs' is not an Array<String>!");
::std::process::exit(1);
}
let logs = logs
.into_iter()
.map(Value::as_str)
.map(Option::unwrap)
.map(String::from)
.collect::<Vec<String>>();
let current_log = cfg
.read_string("log.default")
.map_err(Error::from)
@ -216,13 +192,34 @@ fn get_diary_name(rt: &Runtime) -> String {
.ok_or_else(|| Error::from(err_msg("Configuration missing: 'log.default'")))
.map_err_trace_exit_unwrap(1);
if !logs.contains(&current_log) {
if cfg
.read("log.logs")
.map_err(Error::from)
.map_err_trace_exit_unwrap(1)
.ok_or_else(|| Error::from(err_msg("Configuration missing: 'log.logs'")))
.map_err_trace_exit_unwrap(1)
.as_array()
.ok_or_else(|| Error::from(err_msg("Configuration 'log.logs' is not an Array")))
.map_err_trace_exit_unwrap(1)
.iter()
.map(|e| if is_match!(e, &Value::String(_)) {
error!("Configuration 'log.logs' is not an Array<String>!");
::std::process::exit(1)
} else {
e
})
.map(Value::as_str)
.map(Option::unwrap) // safe by map from above
.map(String::from)
.filter(|log| log == &current_log)
.next()
.is_none()
{
error!("'log.logs' does not contain 'log.default'");
::std::process::exit(1)
} else {
current_log.into()
}
}
fn get_log_text(rt: &Runtime) -> String {

View file

@ -21,9 +21,6 @@ reject your patch.
Make sure to test-compile your patchset and, if available, run tests.
## Finding an issue
## Prerequisites
The prerequisites are simple: `cargo` and `rustc` in current version (stable)

View file

@ -32,13 +32,9 @@ pub struct SetEndTimeIter<'a> {
datetime: NDT,
}
impl<'a> SetEndTimeIter<'a>
{
impl<'a> SetEndTimeIter<'a> {
pub fn new(inner: CreateTimeTrackIter<'a>, datetime: NDT) -> SetEndTimeIter<'a> {
SetEndTimeIter {
inner: inner,
datetime: datetime,
}
SetEndTimeIter { inner, datetime }
}
}
@ -48,13 +44,11 @@ impl<'a> Iterator for SetEndTimeIter<'a> {
fn next(&mut self) -> Option<Self::Item> {
self.inner
.next()
.map(|res| {
res.and_then(|mut fle| {
.map(|res| res.and_then(|mut fle| {
let v = Value::String(self.datetime.format(DATE_TIME_FORMAT).to_string());
let _ = fle.get_header_mut().insert(DATE_TIME_END_HEADER_PATH, v)?;
Ok(fle)
})
})
}))
}
}

View file

@ -36,10 +36,7 @@ pub struct TagStoreIdIter {
impl TagStoreIdIter {
pub fn new(inner: TagIter, datetime: NDT) -> TagStoreIdIter {
TagStoreIdIter {
inner: inner,
datetime: datetime,
}
TagStoreIdIter { inner, datetime }
}
pub fn create_entries<'a>(self, store: &'a Store) -> CreateTimeTrackIter<'a> {
@ -57,16 +54,14 @@ impl Iterator for TagStoreIdIter {
self.inner
.next()
.map(|res| {
res.and_then(|tag| {
.map(|res| res.and_then(|tag| {
let dt = self.datetime.format(DATE_TIME_FORMAT).to_string();
let id_str = format!("{}-{}", dt, tag.as_str());
ModuleEntryPath::new(id_str)
.into_storeid()
.map_err(Error::from)
.map(|id| (id, self.datetime.clone()))
})
})
}))
}
}

View file

@ -0,0 +1,28 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 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
//
// Generates a extension for the `Option<T>`, named `DebugOption` which has functionality to
// print `T` via `debug!()`.
generate_option_logging_extension!(
DebugOption,
map_dbg,
map_dbg_str,
|s| { debug!("{}", s); }
);

View file

@ -0,0 +1,28 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 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
//
// Generates a extension for the `Option<T>`, named `DebugOption` which has functionality to
// print `T` via `info!()`.
generate_option_logging_extension!(
InfoResult,
map_info,
map_info_str,
|s| { info!("{}", s); }
);

View file

@ -42,11 +42,14 @@ extern crate tempfile;
extern crate chrono;
#[macro_use] mod log_result;
#[macro_use] mod log_option;
pub mod cli_validators;
pub mod date;
pub mod debug_result;
pub mod debug_option;
pub mod edit;
pub mod info_result;
pub mod info_option;
pub mod key_value_split;
pub mod variants;
pub mod warn_exit;

View file

@ -0,0 +1,88 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2018 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
//
/// This macro is used to generate extensions for the `Option<T>` type which only have
/// sideeffects.
///
/// This macro is then used to generate debug/info/log/warning/etc extensions.
///
/// It is exported, so other crates can use it to generate more specific extensions for
/// `Option<T>` types
///
/// # Parameters
///
/// The documentation for the parameters of the macro follow.
///
/// ## `$name`
///
/// name of the trait to generate
///
/// ## `$map_name`
///
/// Name of the function which is generated to call the closure with.
///
/// This function gets `&T` from `Option<T>` and can now build the argument for
/// `$closure`. So, this function can, for example, `|e| format!("Look here: {:?}", e)`, the
/// Option gets fed to `$closure`.
///
/// ## `$map_str_name`
///
/// Name of the function which is generated to call the closure with.
///
/// This function gets simply a `&str` which gets fed to the `$closure` later.
/// So it can be used to `foo().$map_str_name("Something happened")`
///
/// ## `$closure`
///
/// The closure which should be called when mapping.
///
/// This closure can now do things, but the return value of the closure is discarded.
/// So, this closure can be used for its sideeffects (logging for example) only.
///
/// An example would be: `|element| debug!("Element: {:?}", element)`.
///
#[macro_export]
macro_rules! generate_option_logging_extension {
{
$name: ident,
$map_name: ident,
$map_str_name: ident,
$closure: expr
} => {
pub trait $name<T> : Sized {
fn $map_name<F: FnOnce(&T) -> String>(self, f: F) -> Self;
fn $map_str_name(self, s: &str) -> Self {
self.$map_name(|_| format!("{}", s))
}
}
impl<T> $name<T> for Option<T> {
fn $map_name<F: FnOnce(&T) -> String>(self, f: F) -> Self {
self.map(|x| { $closure(f(&x)); x })
}
}
}
}