From a0c257d3b0b274aac92db36601783cf3d7df3e11 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Fri, 16 Aug 2024 00:33:15 -0700 Subject: [PATCH] container: plugins: implement 'timew_to_timeclock' plugin - Converts exported `times` into hledger timeclock format * Exported format is underlying `timew` JSON schema --- .../plugins/finance/timew_to_timeclock.bash | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100755 container/plugins/finance/timew_to_timeclock.bash diff --git a/container/plugins/finance/timew_to_timeclock.bash b/container/plugins/finance/timew_to_timeclock.bash new file mode 100755 index 0000000..cd7cced --- /dev/null +++ b/container/plugins/finance/timew_to_timeclock.bash @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +# docker-finance | modern accounting for the power-user +# +# Copyright (C) 2024 Aaron Fiore (Founder, Evergreen Crypto LLC) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation either version 3 of the License or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not see . + +# +# "Libraries" +# + +[ -z "$DOCKER_FINANCE_CONTAINER_REPO" ] && exit 1 +source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/lib_finance.bash" + +[[ -z "$global_parent_profile" || -z "$global_arg_delim_1" || -z "$global_child_profile" ]] && lib_utils::die_fatal +instance="${global_parent_profile}${global_arg_delim_1}${global_child_profile}" + +# Initialize "constructor" +lib_finance::finance "$instance" || lib_utils::die_fatal + +# +# Implementation +# + +lib_utils::deps_check "jq" # *should* be provided by dependency `yq` + +function __format_time() +{ + [[ -z "$1" || -z "$2" ]] && lib_utils::die_fatal + + local -r _direction="$1" + local -r _timestamp="$2" + + # Expects timewarrior *exported* time format + echo -n "$_direction $(echo ${_timestamp:0:4}-${_timestamp:4:2}-${_timestamp:6:2} ${_timestamp:9:2}:${_timestamp:11:2}:${_timestamp:13:2})" +} + +# - Converts exported timewarrior JSON schema into hledger timeclock format +# - Expects the following timewarrior style tags in the format of `key=value` +# +# desc="My Description" +# comment="My Comment" +# tag:type=value +# tag:... +# +# TODO: optimize: export only needed once if the majority of parsing is done within gawk +function main() +{ + # Stop tracking or else format breaks + lib_finance::times stop &>/dev/null + + # Commands and timeclock entries + local -r _cmd=("lib_finance::times" "export") + local -r _count=$("${_cmd[@]}" | jq '. | length') + local _id _start _end _tags + + # Cycle through total count of timewarrior entries + for ((_i = 1; _i <= _count; _i++)); do + + # Parse timewarrior format + local _array=() + while read _line; do + _array+=("$_line") + done < <("${_cmd[@]}" | jq -Mer ".[${_i}-1] | .id,.start,.end") + + local _id="${_array[0]}" + local _start="${_array[1]}" + local _end="${_array[2]}" + + local _tags + _tags="$("${_cmd[@]}" | jq -Mer ".[${_i}-1] | .tags.[]")" + + # Print parsed as timeclock format + __format_time "i" "$_start" + echo "$_tags" \ + | grep -E "(^profile=|^desc=|^comment=|^tag:)" \ + | gawk -F'=' -v _id="$_id" '{ + switch ($1) + { + case "profile": + account=$2 + break + case "desc": + description=$2 + break + case "comment": + comment=$2 + break + default: + # All others are considered "real" tags + tags=substr($0, 5) + sub(/=/, ":", tags) # Reconstruct to hledger tag format + # TODO: push to an array for more tags + break + } + } END { printf " " account " " description " ; " comment ", id:" _id ", " tags "\n"}' + __format_time "o" "$_end" + echo + done +} + +main "$@" + +# vim: sw=2 sts=2 si ai et