commit
c4d10c7e4f
10 changed files with 250 additions and 17 deletions
42
README.md
42
README.md
|
@ -68,6 +68,48 @@ install-directory is in your `$PATH`), or install the `imag` binary to call `ima
|
|||
<modulename>` (also if everything is in your `$PATH`).
|
||||
|
||||
|
||||
## Example usage
|
||||
|
||||
As imag is a big and complex project, we cannot show all tools of the suite
|
||||
here. But to give you some idea, here's an example:
|
||||
|
||||
```bash
|
||||
# Lets initialize imag
|
||||
imag init
|
||||
|
||||
# Recursively import vcf files
|
||||
imag contact import /home/user/contacts
|
||||
|
||||
# Create a contact (vcf) in the private collection
|
||||
imag contact create --file /home/user/contacts/private
|
||||
|
||||
# Add a diary entry
|
||||
imag diary -p private create
|
||||
|
||||
# Uh, I forgot something in a diary entry, select one 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
|
||||
|
||||
# Link a contact to the diary entry
|
||||
imag link diary/private/2018/01/01/00:00:00 contact/bc222298-casf-40a4-bda1-50aa980a68c9
|
||||
|
||||
# Annotate a contact with some notes
|
||||
imag annotate add contact/bc222298-casf-40a4-bda1-50aa980a68c9 contact-notes
|
||||
|
||||
# Write down some notes named "pineapple"
|
||||
imag notes create "pineapple"
|
||||
|
||||
# Where was that contact again?
|
||||
imag grep Eva
|
||||
# Okay, we need to add some imag-internal notes to that contact
|
||||
imag grep Eva -l | imag edit -I
|
||||
|
||||
# Now save our work
|
||||
imag git add . # "imag-git" simply calls git in the imag store
|
||||
imag git commit -m 'Commit message'
|
||||
```
|
||||
|
||||
|
||||
## Staying up-to-date
|
||||
|
||||
We have a [official website for imag](https://imag-pim.org), where I post
|
||||
|
|
|
@ -3,7 +3,7 @@ name = "imag-mv"
|
|||
version = "0.8.0"
|
||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
||||
|
||||
description = "Part of the imag core distribution: imag command"
|
||||
description = "Part of the imag core distribution: imag-mv command"
|
||||
|
||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
||||
readme = "../../../README.md"
|
||||
|
|
|
@ -22,6 +22,20 @@ This section contains the changelog from the last release to the next release.
|
|||
* Minor changes
|
||||
* Bugfixes
|
||||
|
||||
## 0.7.1
|
||||
|
||||
Bugfix release for fixing:
|
||||
|
||||
* `libimagdiary` did not return the youngest, but the oldest entry id on `::get_youngest_entry_id()`.
|
||||
* `imag-view` should not always wrap the text, only if -w is passed
|
||||
* `imag-log show` should order by date
|
||||
* `imag` does not inherit stdout if detecting imag command versions.
|
||||
* `imag-contact import` does only allow absolute pathes
|
||||
* `imag-contact` has most fields optional now, only name is required
|
||||
* `imag-contact` automatically creates UID
|
||||
* `imag-contact` automatically generates/warns about missing file extension
|
||||
|
||||
|
||||
## 0.7.0
|
||||
|
||||
* Major changes
|
||||
|
|
23
etc/imag-contact-mutt-query-command-helper.sh
Normal file
23
etc/imag-contact-mutt-query-command-helper.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# A helper script for the mutt query_command
|
||||
#
|
||||
# Use
|
||||
#
|
||||
# query_command = "/path/to/this/script %s"
|
||||
#
|
||||
# in mutt to search contacts from mutt with imag.
|
||||
#
|
||||
|
||||
# mutt wants a one-line status message before the list of contacts.
|
||||
echo "Searching with imag ..."
|
||||
imag contact find "$1" --json | \
|
||||
jq --raw-output '
|
||||
map(.fullname[0] as $FN
|
||||
| .email
|
||||
| map({email: ., fullname: $FN}))
|
||||
| flatten
|
||||
| map([.email.address, .fullname, .email.properties.TYPE])
|
||||
| .[]
|
||||
| @tsv
|
||||
'
|
152
etc/ioverlander-wiki-import.sh
Normal file
152
etc/ioverlander-wiki-import.sh
Normal file
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This script imports iOverlander data into a imag-wiki
|
||||
#
|
||||
# Requirements
|
||||
# ============
|
||||
#
|
||||
# * imag-wiki
|
||||
# * imag-gps
|
||||
# * imag-store
|
||||
# * jq
|
||||
#
|
||||
# Usage
|
||||
# =====
|
||||
#
|
||||
# Download the JSON data files from app.ioverlander.com and run them through
|
||||
# this script.
|
||||
#
|
||||
# ./this/script wiki-name ioverlander-file.json
|
||||
#
|
||||
# What it does
|
||||
# ============
|
||||
#
|
||||
# It imports each location from the JSON data into one entry at:
|
||||
#
|
||||
# <wiki_name>/<country>/<location name>_<location id>
|
||||
#
|
||||
# (The location id is added because names are sometimes reused)
|
||||
#
|
||||
# * It uses imag-gps to set the GPS data
|
||||
# * It sets the header of the entry to the data it finds from the JSON object.
|
||||
# It puts all data in the "userdata.ioverlander" namespace.
|
||||
# It strips whitespace from the keys.
|
||||
# It ignores the GPS data from the JSON object though, as this was added via
|
||||
# imag-gps.
|
||||
# * It uses the "description" field as entry content.
|
||||
#
|
||||
# Warning
|
||||
# =======
|
||||
#
|
||||
# As the ioverlander data sometimes contains "/" in the name, some entries are
|
||||
# namespaced. This has to be fixed and the linkings have to be adapted. This is
|
||||
# not yet handled by this script.
|
||||
#
|
||||
#
|
||||
|
||||
WIKI_NAME="$1"
|
||||
IOVERLANDER_FILE_PATH="$2"
|
||||
|
||||
[[ -z "$WIKI_NAME" ]] && echo "Wiki name missing" && exit 1
|
||||
[[ -z "$IOVERLANDER_FILE_PATH" ]] && echo "JSON file missing" && exit 1
|
||||
|
||||
imag wiki create-wiki "$WIKI_NAME" --no-edit
|
||||
echo "Created imag wiki '$WIKI_NAME'"
|
||||
|
||||
tobool() {
|
||||
if [[ "$1" == "Yes" ]]; then
|
||||
echo "true"
|
||||
elif [[ "$1" == "No" ]]; then
|
||||
echo "false"
|
||||
else
|
||||
echo "\"$1\""
|
||||
fi
|
||||
}
|
||||
|
||||
object_to_vars() {
|
||||
jq -r -c 'to_entries | .[] | .key + "=\"" + (.value | tostring | gsub("\\\""; "")) + "\""'
|
||||
}
|
||||
|
||||
|
||||
# The comments in this function can be outcommented for debugging
|
||||
process_object() {
|
||||
read -r json
|
||||
|
||||
local location_latitude
|
||||
local location_longitude
|
||||
local location_altitude
|
||||
local location_horizontal_accuracy
|
||||
local location_vertical_accuracy
|
||||
local amenities_Open
|
||||
local amenities_Electricity
|
||||
local amenities_Wifi
|
||||
local amenities_Kitchen
|
||||
local amenities_Restaurant
|
||||
local amenities_Showers
|
||||
local amenities_Water
|
||||
local amenities_Toilets
|
||||
local amenities_Big_rig_friendly
|
||||
local amenities_Tent_friendly
|
||||
local amenities_Pet_friendly
|
||||
local id
|
||||
local name
|
||||
local description
|
||||
local date_verified
|
||||
local category_icon_path
|
||||
local category_icon_pin_path
|
||||
local country
|
||||
local category
|
||||
|
||||
#echo "----------------------------------------------------------"
|
||||
#echo "JSON = $json"
|
||||
#echo "-----------"
|
||||
#echo $json | jq '.location' | object_to_vars | sed 's,^,location_,'
|
||||
#echo $json | jq '.amenities' | object_to_vars | sed 's,^,amenities_,; s, Big,_big,; s, Rig,_rig,; s, Friendly,_friendly,'
|
||||
#echo $json | jq 'del(.location)|del(.amenities)' | object_to_vars
|
||||
|
||||
eval $(echo $json | jq '.location' | object_to_vars | sed 's,^,location_,')
|
||||
eval $(echo $json | jq '.amenities' | object_to_vars | sed 's,^,amenities_,; s, Big,_big,; s, Rig,_rig,; s, Friendly,_friendly,')
|
||||
eval $(echo $json | jq 'del(.location)|del(.amenities)' | object_to_vars)
|
||||
|
||||
local ctry_slug=$(echo $country | sed 's, ,_,g')
|
||||
local name_slug=$(echo $name | sed 's, ,_,g')
|
||||
|
||||
echo "create = $ctry_slug/${name_slug}_${id}"
|
||||
|
||||
local article=$(imag wiki --wiki "$WIKI_NAME" create "$ctry_slug/${name_slug}_${id}" --no-edit --print-id || exit 1)
|
||||
|
||||
echo "ARTICLE = $article"
|
||||
|
||||
imag gps add --lat="$location_latitude" --long="$location_longitude" "$article" || {
|
||||
echo "GPS setting failed"
|
||||
exit 1
|
||||
}
|
||||
imag store update --id "$article" \
|
||||
--header \
|
||||
"userdata.ioverlander.id=\"$id\"" \
|
||||
"userdata.ioverlander.name=\"$name\"" \
|
||||
"userdata.ioverlander.date_verified=\"$date_verified\"" \
|
||||
"userdata.ioverlander.country=\"$country\"" \
|
||||
"userdata.ioverlander.category=\"$category\"" \
|
||||
"userdata.ioverlander.amenities.open=$(tobool "$amenities_Open")" \
|
||||
"userdata.ioverlander.amenities.electricity=$(tobool "$amenities_Electricity")" \
|
||||
"userdata.ioverlander.amenities.wifi=$(tobool "$amenities_Wifi")" \
|
||||
"userdata.ioverlander.amenities.kitchen=$(tobool "$amenities_Kitchen")" \
|
||||
"userdata.ioverlander.amenities.restaurant=$(tobool "$amenities_Restaurant")" \
|
||||
"userdata.ioverlander.amenities.showers=$(tobool "$amenities_Showers")" \
|
||||
"userdata.ioverlander.amenities.water=$(tobool "$amenities_Water")" \
|
||||
"userdata.ioverlander.amenities.toilets=$(tobool "$amenities_Toilets")" \
|
||||
"userdata.ioverlander.amenities.big_rig_friendly=$(tobool "$amenities_Big_rig_friendly")" \
|
||||
"userdata.ioverlander.amenities.tent_friendly=$(tobool "$amenities_Tent_friendly")" \
|
||||
"userdata.ioverlander.amenities.pet_friendly=$(tobool "$amenities_Pet_friendly")" \
|
||||
--content \""$description\"" || {
|
||||
echo "header/content setting failed";
|
||||
exit 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cat "$IOVERLANDER_FILE_PATH" | jq -c '.[]' | while read line; do
|
||||
process_object
|
||||
done
|
||||
|
|
@ -96,6 +96,7 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
|
|||
};
|
||||
*self = FSFileAbstractionInstance::File(file, path);
|
||||
if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
|
||||
trace!("Writing buffer...");
|
||||
return f.write_all(&buf).chain_err(|| SEK::FileNotWritten);
|
||||
}
|
||||
unreachable!();
|
||||
|
@ -186,9 +187,12 @@ fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
|
|||
|
||||
fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
|
||||
if let Some(parent) = p.as_ref().parent() {
|
||||
debug!("Implicitely creating directory: {:?}", parent);
|
||||
if let Err(e) = create_dir_all(parent) {
|
||||
return Err(e);
|
||||
trace!("'{}' is directory = {}", parent.display(), parent.is_dir());
|
||||
if !parent.is_dir() {
|
||||
trace!("Implicitely creating directory: {:?}", parent);
|
||||
if let Err(e) = create_dir_all(parent) {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
OpenOptions::new().write(true).read(true).create(true).open(p)
|
||||
|
|
|
@ -177,6 +177,7 @@ impl StoreEntry {
|
|||
fn write_entry(&mut self, entry: &Entry) -> Result<()> {
|
||||
if self.is_borrowed() {
|
||||
assert_eq!(self.id, entry.location);
|
||||
trace!("Writing entry...");
|
||||
self.file
|
||||
.write_file_content(entry)
|
||||
.map(|_| ())
|
||||
|
@ -442,11 +443,13 @@ impl Store {
|
|||
|
||||
debug!("Writing Entry");
|
||||
se.write_entry(&entry.entry)?;
|
||||
trace!("Entry written");
|
||||
if modify_presence {
|
||||
debug!("Modifying presence of {} -> Present", entry.get_location());
|
||||
se.status = StoreEntryStatus::Present;
|
||||
}
|
||||
|
||||
trace!("Entry updated successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -798,6 +801,7 @@ impl<'a> Drop for FileLockEntry<'a> {
|
|||
use libimagerror::trace::trace_error_dbg;
|
||||
trace!("Dropping: {:?} - from FileLockEntry::drop()", self.get_location());
|
||||
if let Err(e) = self.store._update(self, true) {
|
||||
trace!("Error happened in FileLockEntry::drop() while Store::update()ing");
|
||||
trace_error_dbg(&e);
|
||||
if_cfg_panic!("ERROR WHILE DROPPING: {:?}", e);
|
||||
}
|
||||
|
|
|
@ -388,6 +388,8 @@ pub mod iter {
|
|||
impl InternalLinker for Entry {
|
||||
|
||||
fn get_internal_links(&self) -> Result<LinkIter> {
|
||||
debug!("Getting internal links");
|
||||
trace!("Getting internal links from header of '{}' = {:?}", self.get_location(), self.get_header());
|
||||
let res = self
|
||||
.get_header()
|
||||
.read("links.internal")
|
||||
|
@ -400,6 +402,8 @@ impl InternalLinker for Entry {
|
|||
fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<LinkIter> {
|
||||
use internal::iter::IntoValues;
|
||||
|
||||
debug!("Setting internal links");
|
||||
|
||||
let self_location = self.get_location().clone();
|
||||
let mut new_links = vec![];
|
||||
|
||||
|
@ -430,11 +434,13 @@ impl InternalLinker for Entry {
|
|||
}
|
||||
|
||||
fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
|
||||
debug!("Adding internal link: {:?}", link);
|
||||
let location = link.get_location().clone().into();
|
||||
add_internal_link_with_instance(self, link, location)
|
||||
}
|
||||
|
||||
fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
|
||||
debug!("Removing internal link: {:?}", link);
|
||||
let own_loc = self.get_location().clone().without_base();
|
||||
let other_loc = link.get_location().clone().without_base();
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "No rev list given"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for rev in $(git rev-list $1); do
|
||||
if git notes --ref=changelog list $rev &> /dev/null; then
|
||||
git log -n 1 --show-notes=* --pretty="format:* %N" $rev
|
||||
fi
|
||||
done
|
|
@ -10,7 +10,7 @@ fi
|
|||
for rev in $(git rev-list "$since"..HEAD | tac); do
|
||||
if git notes --ref=changelog list $rev &> /dev/null; then
|
||||
output=$(git notes --ref=changelog show $rev | sed '2,$s/^/ /')
|
||||
echo "* $output"
|
||||
echo "* [$(echo ${rev:0:10})] $output"
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
Loading…
Reference in a new issue