Merge branch 'minor'
This commit is contained in:
commit
47707bf593
14 changed files with 270 additions and 307 deletions
|
@ -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.
|
|
||||||
|
|
|
@ -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
|
guarantee that. I hope I can continue development of imag after that and I
|
||||||
certainly plan to do so.
|
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?
|
## 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
|
# 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
|
# 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
|
# Link a contact to the diary entry
|
||||||
imag link diary/private/2018/01/01/00:00:00 contact/bc222298-casf-40a4-bda1-50aa980a68c9
|
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?
|
# Where was that contact again?
|
||||||
imag grep Eva # also possible with `imag contact find Eva`
|
imag grep Eva # also possible with `imag contact find Eva`
|
||||||
|
|
||||||
# Okay, we need to add some imag-internal notes to that contact
|
# 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
|
# Now save our work
|
||||||
imag git add . # "imag-git" simply calls git in the imag store
|
imag git add . # "imag-git" simply calls git in the imag store
|
||||||
|
|
|
@ -57,6 +57,7 @@ use libimagbookmark::link::Link as BookmarkLink;
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
use libimagerror::trace::{MapErrTrace, trace_error};
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use libimagerror::exit::ExitUnwrap;
|
||||||
|
use libimagutil::debug_result::DebugResult;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -152,14 +153,16 @@ fn list(rt: &Runtime) {
|
||||||
.report_touched(collection.get_location())
|
.report_touched(collection.get_location())
|
||||||
.map_err_trace_exit_unwrap(1);
|
.map_err_trace_exit_unwrap(1);
|
||||||
|
|
||||||
let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1);
|
collection
|
||||||
debug!("Listing...");
|
.links(rt.store())
|
||||||
for (i, link) in links.enumerate() {
|
.map_dbg_str("Listing...")
|
||||||
match link {
|
.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(),
|
Ok(link) => writeln!(rt.stdout(), "{: >3}: {}", i, link).to_exit_code().unwrap_or_exit(),
|
||||||
Err(e) => trace_error(&e)
|
Err(e) => trace_error(&e)
|
||||||
}
|
});
|
||||||
};
|
|
||||||
debug!("... ready with listing");
|
debug!("... ready with listing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,19 +142,15 @@ fn list(rt: &Runtime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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(|(i, dvcard)| build_data_object_for_handlebars(i, &dvcard))
|
||||||
.map(|data| list_format.render("format", &data).map_err(Error::from))
|
.map(|data| list_format.render("format", &data).map_err(Error::from))
|
||||||
.trace_unwrap_exit(1)
|
.trace_unwrap_exit(1)
|
||||||
.collect::<Vec<String>>();
|
.for_each(|s| {
|
||||||
// collect, so that we can have rendered all the things and printing is faster.
|
writeln!(output, "{}", s).to_exit_code().unwrap_or_exit()
|
||||||
|
});
|
||||||
let output = rt.stdout();
|
|
||||||
let mut output = output.lock();
|
|
||||||
|
|
||||||
rendered.into_iter().for_each(|s| {
|
|
||||||
writeln!(output, "{}", s).to_exit_code().unwrap_or_exit()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ use libimagentryedit::edit::Edit;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
use libimagerror::trace::MapErrTrace;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
use libimagutil::warn_exit::warn_exit;
|
||||||
|
use libimagutil::debug_result::DebugResult;
|
||||||
|
use libimagutil::debug_option::DebugOption;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
|
||||||
|
@ -76,7 +78,7 @@ fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLock
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|timed| {
|
.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)
|
diary.new_entry_at(&diaryname, &time)
|
||||||
.context(err_msg("Store write error"))
|
.context(err_msg("Store write error"))
|
||||||
.map_err(Error::from)
|
.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");
|
debug!("Creating non-timed entry");
|
||||||
diary.new_entry_today(diaryname)
|
diary.new_entry_today(diaryname)
|
||||||
})
|
})
|
||||||
.map(|e| {
|
.map_dbg(|e| format!("Created: {}", e.get_location()))
|
||||||
debug!("Created: {}", e.get_location());
|
|
||||||
e
|
|
||||||
})
|
|
||||||
.map_err_trace_exit_unwrap(1)
|
.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;
|
use std::str::FromStr;
|
||||||
|
|
||||||
let dt = Local::now();
|
let dt = Local::now();
|
||||||
|
@ -120,7 +119,7 @@ fn create_id_from_clispec(create: &ArgMatches, diaryname: &str, timed_type: Time
|
||||||
Timed::Minutely => {
|
Timed::Minutely => {
|
||||||
let min = create
|
let min = create
|
||||||
.value_of("minute")
|
.value_of("minute")
|
||||||
.map(|m| { debug!("minute = {:?}", m); m })
|
.map_dbg(|m| format!("minute = {:?}", m))
|
||||||
.and_then(|s| {
|
.and_then(|s| {
|
||||||
FromStr::from_str(s)
|
FromStr::from_str(s)
|
||||||
.map_err(|_| warn!("Could not parse minute: '{}'", 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 => {
|
Timed::Secondly => {
|
||||||
let min = create
|
let min = create
|
||||||
.value_of("minute")
|
.value_of("minute")
|
||||||
.map(|m| { debug!("minute = {:?}", m); m })
|
.map_dbg(|m| format!("minute = {:?}", m))
|
||||||
.and_then(|s| {
|
.and_then(|s| {
|
||||||
FromStr::from_str(s)
|
FromStr::from_str(s)
|
||||||
.map_err(|_| warn!("Could not parse minute: '{}'", 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
|
let sec = create
|
||||||
.value_of("second")
|
.value_of("second")
|
||||||
.map(|s| { debug!("second = {:?}", s); s })
|
.map_dbg(|s| format!("second = {:?}", s))
|
||||||
.and_then(|s| {
|
.and_then(|s| {
|
||||||
FromStr::from_str(s)
|
FromStr::from_str(s)
|
||||||
.map_err(|_| warn!("Could not parse second: '{}'", s))
|
.map_err(|_| warn!("Could not parse second: '{}'", s))
|
||||||
|
|
|
@ -315,7 +315,7 @@ fn today(rt: &Runtime, future: bool) {
|
||||||
info!("No Habits due today.");
|
info!("No Habits due today.");
|
||||||
info!("Upcoming:");
|
info!("Upcoming:");
|
||||||
// list `n` which are relevant in the future.
|
// 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 date = element.next_instance_date().map_err_trace_exit_unwrap(1);
|
||||||
let name = element.habit_name().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);
|
info!(" * {date}: {name}", date = date, name = name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
} else {
|
} else {
|
||||||
fn lister_fn(h: &FileLockEntry) -> Vec<String> {
|
fn lister_fn(h: &FileLockEntry) -> Vec<String> {
|
||||||
debug!("Listing: {:?}", h);
|
debug!("Listing: {:?}", h);
|
||||||
|
@ -354,34 +354,33 @@ fn today(rt: &Runtime, future: bool) {
|
||||||
table.set_titles(Row::new(header));
|
table.set_titles(Row::new(header));
|
||||||
|
|
||||||
let mut empty = true;
|
let mut empty = true;
|
||||||
for (i, e) in relevant.into_iter()
|
relevant
|
||||||
.filter(|habit| {
|
.into_iter()
|
||||||
show_done || {
|
.filter(|habit| show_done || {
|
||||||
habit
|
habit
|
||||||
.next_instance_date()
|
.next_instance_date()
|
||||||
.map_err_trace_exit_unwrap(1)
|
.map_err_trace_exit_unwrap(1)
|
||||||
.map(|date| {
|
.map(|date| {
|
||||||
habit.instance_exists_for_date(&date)
|
habit.instance_exists_for_date(&date)
|
||||||
.map_err_trace_exit_unwrap(1)
|
.map_err_trace_exit_unwrap(1)
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
.for_each(|(i, e)| {
|
||||||
let mut v = vec![format!("{}", i)];
|
let mut v = vec![format!("{}", i)];
|
||||||
let mut list = lister_fn(&e);
|
let mut list = lister_fn(&e);
|
||||||
|
|
||||||
{
|
{
|
||||||
let _ = rt
|
let _ = rt
|
||||||
.report_touched(e.get_location())
|
.report_touched(e.get_location())
|
||||||
.map_err_trace_exit_unwrap(1);
|
.map_err_trace_exit_unwrap(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
v.append(&mut list);
|
v.append(&mut list);
|
||||||
table.add_row(v.iter().map(|s| Cell::new(s)).collect());
|
table.add_row(v.iter().map(|s| Cell::new(s)).collect());
|
||||||
empty = false;
|
empty = false;
|
||||||
}
|
});
|
||||||
|
|
||||||
if !empty {
|
if !empty {
|
||||||
let _ = table.print(&mut rt.stdout()).to_exit_code().unwrap_or_exit();
|
let _ = table.print(&mut rt.stdout()).to_exit_code().unwrap_or_exit();
|
||||||
|
|
|
@ -140,42 +140,40 @@ fn show(rt: &Runtime) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for iter in iters {
|
Itertools::flatten(iters.into_iter())
|
||||||
let _ = iter
|
.into_get_iter(rt.store())
|
||||||
.into_get_iter(rt.store())
|
.trace_unwrap_exit(1)
|
||||||
.trace_unwrap_exit(1)
|
.filter_map(|opt| {
|
||||||
.filter_map(|opt| {
|
if opt.is_none() {
|
||||||
if opt.is_none() {
|
warn!("Failed to retrieve an entry from an existing store id");
|
||||||
warn!("Failed to retrieve an entry from an existing store id");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
opt
|
opt
|
||||||
})
|
})
|
||||||
.filter(|e| e.is_log().map_err_trace_exit_unwrap(1))
|
.filter(|e| e.is_log().map_err_trace_exit_unwrap(1))
|
||||||
.map(|entry| (entry.diary_id().map_err_trace_exit_unwrap(1), entry))
|
.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()
|
.into_iter()
|
||||||
.map(|(id, entry)| {
|
.map(|tpl| { debug!("Found entry: {:?}", tpl.1); tpl })
|
||||||
debug!("Found entry: {:?}", entry);
|
.map(|(id, entry)| {
|
||||||
let _ = writeln!(rt.stdout(),
|
let _ = writeln!(rt.stdout(),
|
||||||
"{dname: >10} - {y: >4}-{m:0>2}-{d:0>2}T{H:0>2}:{M:0>2} - {text}",
|
"{dname: >10} - {y: >4}-{m:0>2}-{d:0>2}T{H:0>2}:{M:0>2} - {text}",
|
||||||
dname = id.diary_name(),
|
dname = id.diary_name(),
|
||||||
y = id.year(),
|
y = id.year(),
|
||||||
m = id.month(),
|
m = id.month(),
|
||||||
d = id.day(),
|
d = id.day(),
|
||||||
H = id.hour(),
|
H = id.hour(),
|
||||||
M = id.minute(),
|
M = id.minute(),
|
||||||
text = entry.get_content())
|
text = entry.get_content())
|
||||||
.to_exit_code()?;
|
.to_exit_code()?;
|
||||||
|
|
||||||
let _ = rt
|
let _ = rt
|
||||||
.report_touched(entry.get_location())
|
.report_touched(entry.get_location())
|
||||||
.map_err_trace_exit_unwrap(1);
|
.map_err_trace_exit_unwrap(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<()>, ExitCode>>()
|
.collect::<Result<Vec<()>, ExitCode>>()
|
||||||
.unwrap_or_exit();
|
.unwrap_or_exit();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_diary_name(rt: &Runtime) -> String {
|
fn get_diary_name(rt: &Runtime) -> String {
|
||||||
|
@ -187,28 +185,6 @@ fn get_diary_name(rt: &Runtime) -> String {
|
||||||
.ok_or_else(|| Error::from(err_msg("Configuration not present, cannot continue")))
|
.ok_or_else(|| Error::from(err_msg("Configuration not present, cannot continue")))
|
||||||
.map_err_trace_exit_unwrap(1);
|
.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
|
let current_log = cfg
|
||||||
.read_string("log.default")
|
.read_string("log.default")
|
||||||
.map_err(Error::from)
|
.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'")))
|
.ok_or_else(|| Error::from(err_msg("Configuration missing: 'log.default'")))
|
||||||
.map_err_trace_exit_unwrap(1);
|
.map_err_trace_exit_unwrap(1);
|
||||||
|
|
||||||
if !logs.contains(¤t_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 == ¤t_log)
|
||||||
|
.next()
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
error!("'log.logs' does not contain 'log.default'");
|
error!("'log.logs' does not contain 'log.default'");
|
||||||
::std::process::exit(1)
|
::std::process::exit(1)
|
||||||
} else {
|
} else {
|
||||||
current_log.into()
|
current_log.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_log_text(rt: &Runtime) -> String {
|
fn get_log_text(rt: &Runtime) -> String {
|
||||||
|
|
|
@ -21,9 +21,6 @@ reject your patch.
|
||||||
Make sure to test-compile your patchset and, if available, run tests.
|
Make sure to test-compile your patchset and, if available, run tests.
|
||||||
|
|
||||||
|
|
||||||
## Finding an issue
|
|
||||||
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
The prerequisites are simple: `cargo` and `rustc` in current version (stable)
|
The prerequisites are simple: `cargo` and `rustc` in current version (stable)
|
||||||
|
|
|
@ -32,13 +32,9 @@ pub struct SetEndTimeIter<'a> {
|
||||||
datetime: NDT,
|
datetime: NDT,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SetEndTimeIter<'a>
|
impl<'a> SetEndTimeIter<'a> {
|
||||||
{
|
|
||||||
pub fn new(inner: CreateTimeTrackIter<'a>, datetime: NDT) -> SetEndTimeIter<'a> {
|
pub fn new(inner: CreateTimeTrackIter<'a>, datetime: NDT) -> SetEndTimeIter<'a> {
|
||||||
SetEndTimeIter {
|
SetEndTimeIter { inner, datetime }
|
||||||
inner: inner,
|
|
||||||
datetime: datetime,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,13 +44,11 @@ impl<'a> Iterator for SetEndTimeIter<'a> {
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.inner
|
self.inner
|
||||||
.next()
|
.next()
|
||||||
.map(|res| {
|
.map(|res| res.and_then(|mut fle| {
|
||||||
res.and_then(|mut fle| {
|
let v = Value::String(self.datetime.format(DATE_TIME_FORMAT).to_string());
|
||||||
let v = Value::String(self.datetime.format(DATE_TIME_FORMAT).to_string());
|
let _ = fle.get_header_mut().insert(DATE_TIME_END_HEADER_PATH, v)?;
|
||||||
let _ = fle.get_header_mut().insert(DATE_TIME_END_HEADER_PATH, v)?;
|
Ok(fle)
|
||||||
Ok(fle)
|
}))
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,7 @@ pub struct TagStoreIdIter {
|
||||||
impl TagStoreIdIter {
|
impl TagStoreIdIter {
|
||||||
|
|
||||||
pub fn new(inner: TagIter, datetime: NDT) -> TagStoreIdIter {
|
pub fn new(inner: TagIter, datetime: NDT) -> TagStoreIdIter {
|
||||||
TagStoreIdIter {
|
TagStoreIdIter { inner, datetime }
|
||||||
inner: inner,
|
|
||||||
datetime: datetime,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_entries<'a>(self, store: &'a Store) -> CreateTimeTrackIter<'a> {
|
pub fn create_entries<'a>(self, store: &'a Store) -> CreateTimeTrackIter<'a> {
|
||||||
|
@ -57,16 +54,14 @@ impl Iterator for TagStoreIdIter {
|
||||||
|
|
||||||
self.inner
|
self.inner
|
||||||
.next()
|
.next()
|
||||||
.map(|res| {
|
.map(|res| res.and_then(|tag| {
|
||||||
res.and_then(|tag| {
|
let dt = self.datetime.format(DATE_TIME_FORMAT).to_string();
|
||||||
let dt = self.datetime.format(DATE_TIME_FORMAT).to_string();
|
let id_str = format!("{}-{}", dt, tag.as_str());
|
||||||
let id_str = format!("{}-{}", dt, tag.as_str());
|
ModuleEntryPath::new(id_str)
|
||||||
ModuleEntryPath::new(id_str)
|
.into_storeid()
|
||||||
.into_storeid()
|
.map_err(Error::from)
|
||||||
.map_err(Error::from)
|
.map(|id| (id, self.datetime.clone()))
|
||||||
.map(|id| (id, self.datetime.clone()))
|
}))
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
lib/etc/libimagutil/src/debug_option.rs
Normal file
28
lib/etc/libimagutil/src/debug_option.rs
Normal 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); }
|
||||||
|
);
|
||||||
|
|
28
lib/etc/libimagutil/src/info_option.rs
Normal file
28
lib/etc/libimagutil/src/info_option.rs
Normal 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); }
|
||||||
|
);
|
||||||
|
|
|
@ -42,11 +42,14 @@ extern crate tempfile;
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
|
|
||||||
#[macro_use] mod log_result;
|
#[macro_use] mod log_result;
|
||||||
|
#[macro_use] mod log_option;
|
||||||
pub mod cli_validators;
|
pub mod cli_validators;
|
||||||
pub mod date;
|
pub mod date;
|
||||||
pub mod debug_result;
|
pub mod debug_result;
|
||||||
|
pub mod debug_option;
|
||||||
pub mod edit;
|
pub mod edit;
|
||||||
pub mod info_result;
|
pub mod info_result;
|
||||||
|
pub mod info_option;
|
||||||
pub mod key_value_split;
|
pub mod key_value_split;
|
||||||
pub mod variants;
|
pub mod variants;
|
||||||
pub mod warn_exit;
|
pub mod warn_exit;
|
||||||
|
|
88
lib/etc/libimagutil/src/log_option.rs
Normal file
88
lib/etc/libimagutil/src/log_option.rs
Normal 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 })
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue