From bbbecff7f18a68d52d3f2ae2307575671cfbd314 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Fri, 5 Jul 2024 20:57:07 -0700 Subject: [PATCH 1/7] client: docker-finance.d: add hledger.conf.in --- .../container/hledger/hledger.conf.in | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 client/docker-finance.d/container/hledger/hledger.conf.in diff --git a/client/docker-finance.d/container/hledger/hledger.conf.in b/client/docker-finance.d/container/hledger/hledger.conf.in new file mode 100644 index 0000000..ef3e290 --- /dev/null +++ b/client/docker-finance.d/container/hledger/hledger.conf.in @@ -0,0 +1,29 @@ +# 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 . + +# NOTE: +# - File is treated as a plain configuration file (non-executable) +# - Only functional for `hledger 1.34.99-gcf0c7c2ef-20240702` or later +# - See sample: https://github.com/simonmichael/hledger/blob/master/hledger.conf.sample + +[balance] not:desc:balances not:equity:balances not:archive +[print] not:desc:balances not:equity:balances not:archive + +[ui] assets liabilities not:desc:balances not:equity:balances not:archive +[web] --serve --host=0.0.0.0 --base-url http://127.0.0.1:5000 --capabilities=view assets liabilities not:desc:balances not:equity:balances not:archive + +# vim: syn=bash sw=2 sts=2 si ai et From c2ac298f679f33469e016bb97cb6c0055ed61c5a Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Fri, 5 Jul 2024 21:24:11 -0700 Subject: [PATCH 2/7] client: lib_gen: add hledger conf support --- client/src/docker/lib/internal/lib_gen.bash | 66 ++++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index dc1686b..aedb759 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -322,7 +322,7 @@ function lib_gen::__gen_container() lib_utils::print_debug "Generating container" # - # Check to proceed + # Check to proceed with profile-specific # lib_utils::print_custom " \e[32m│\e[0m\n" @@ -377,7 +377,7 @@ function lib_gen::__gen_container() lib_utils::print_custom " \e[32m│ │ └─\e[34m Using subprofile:\e[0m ${_subprofile}\n" # - # Execute + # Execute profile-specific # lib_utils::print_custom " \e[32m│ │\e[0m\n" @@ -394,7 +394,7 @@ function lib_gen::__gen_container() fi lib_utils::print_custom " \e[32m│ │\e[0m\n" - lib_utils::print_custom " \e[32m│ ├─\e[34;1m Generate (or update) container hledger-flow configs and/or accounts? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ ├─\e[34;1m Generate (or update) hledger configuration file? [Y/n] \e[0m" read -p "" _read _confirm="${_read:-y}" if [[ "$_confirm" == [yY] ]]; then @@ -403,6 +403,19 @@ function lib_gen::__gen_container() lib_utils::print_debug "_gen_path=${_gen_path}" lib_utils::print_debug "_gen_conf_path=${_gen_conf_path}" + lib_gen::__gen_hledger "$_gen_path" "$_gen_conf_path" + fi + + lib_utils::print_custom " \e[32m│ │\e[0m\n" + lib_utils::print_custom " \e[32m│ ├─\e[34;1m Generate (or update) container hledger-flow configs and/or accounts? [Y/n] \e[0m" + read -p "" _read + _confirm="${_read:-y}" + if [[ "$_confirm" == [yY] ]]; then + local _gen_path="${DOCKER_FINANCE_CLIENT_FLOW}/profiles/${_profile}/${_subprofile}" + local _gen_conf_path="${_gen_path}/docker-finance.d" + lib_utils::print_debug "_gen_path=${_gen_path}" + lib_utils::print_debug "_gen_conf_path=${_gen_conf_path}" + lib_gen::__gen_flow "$_gen_path" "$_gen_conf_path" fi } @@ -475,6 +488,53 @@ function lib_gen::__gen_shell_write() "${global_repo_conf_dir}/container/shell/superscript.bash.in" >"$_file" } +# +# Generate hledger configuration file +# + +function lib_gen::__gen_hledger() +{ + local -r _gen_path="$1" + local -r _gen_conf_path="$2" + + local _dir="${_gen_conf_path}/hledger" + [ ! -d "$_dir" ] && mkdir -p "$_dir" + + local _file="${_dir}/hledger.conf" + if [ -f "$_file" ]; then + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m hledger configuration found, backup then generate new one? [Y/n] \e[0m" + read -p "" _read + _confirm="${_read:-y}" + + if [[ "$_confirm" == [yY] ]]; then + cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal + + lib_gen::__gen_hledger_write "$_file" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" + fi + else + lib_gen::__gen_hledger_write "$_file" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" + fi + + lib_utils::print_custom "$_print_custom" + read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" +} + +function lib_gen::__gen_hledger_write() +{ + local _file="$1" + [ -z "$_file" ] && lib_utils::die_fatal + + [ -z "$DOCKER_FINANCE_VERSION" ] && lib_utils::die_fatal + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal + sed \ + -e "s:@DOCKER_FINANCE_VERSION@:${DOCKER_FINANCE_VERSION}:g" \ + "${global_repo_conf_dir}/container/hledger/hledger.conf.in" >"$_file" +} + # # Generate hledger-flow # From adebadbaa9d5aa7104344a98609f560a498bb251 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Fri, 5 Jul 2024 21:57:39 -0700 Subject: [PATCH 3/7] container: lib_edit: add hledger conf support --- container/src/finance/lib/internal/lib_edit.bash | 11 +++++++++-- container/src/finance/lib/lib_finance.bash | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/container/src/finance/lib/internal/lib_edit.bash b/container/src/finance/lib/internal/lib_edit.bash index 7027a3d..83e0659 100644 --- a/container/src/finance/lib/internal/lib_edit.bash +++ b/container/src/finance/lib/internal/lib_edit.bash @@ -59,7 +59,7 @@ function lib_edit::__parse_args() Configuration type: - type${global_arg_delim_2} + type${global_arg_delim_2} Account: @@ -70,6 +70,9 @@ function lib_edit::__parse_args() \e[37;2m# Edit fetch configuration\e[0m $ $global_usage type${global_arg_delim_2}fetch + \e[37;2m# Edit hledger configuration\e[0m + $ $global_usage type${global_arg_delim_2}hledger + \e[37;2m# Edit meta and subprofile configurations\e[0m $ $global_usage type${global_arg_delim_2}meta${global_arg_delim_3}shell @@ -157,7 +160,7 @@ function lib_edit::__parse_args() read -ra _read <<<"$_arg_type" for _type in "${_read[@]}"; do - if [[ ! "$_type" =~ ^fetch$|^iadd$|^manual$|^meta$|^preprocess$|^rules$|^shell$ ]]; then + if [[ ! "$_type" =~ ^fetch$|^hledger$|^iadd$|^manual$|^meta$|^preprocess$|^rules$|^shell$ ]]; then lib_utils::die_usage "$_usage" fi if [[ ! -z "$_arg_account" ]]; then @@ -201,6 +204,7 @@ function lib_edit::__edit() [ -z "$global_child_profile" ] && lib_utils::die_fatal [ -z "$global_child_profile_flow" ] && lib_utils::die_fatal [ -z "$global_conf_fetch" ] && lib_utils::die_fatal + [ -z "$global_conf_hledger" ] && lib_utils::die_fatal [ -z "$global_conf_meta" ] && lib_utils::die_fatal [ -z "$global_conf_shell" ] && lib_utils::die_fatal @@ -209,6 +213,9 @@ function lib_edit::__edit() fetch) $EDITOR "$global_conf_fetch" ;; + hledger) + $EDITOR "$global_conf_hledger" + ;; iadd | manual) local _path="${global_child_profile_flow}/import/${global_child_profile}/_manual_/${global_arg_year}" [ ! -d "$_path" ] && mkdir -p "$_path" diff --git a/container/src/finance/lib/lib_finance.bash b/container/src/finance/lib/lib_finance.bash index 022afbc..3c872b1 100644 --- a/container/src/finance/lib/lib_finance.bash +++ b/container/src/finance/lib/lib_finance.bash @@ -78,6 +78,7 @@ function lib_finance::finance() # Globals (configuration) declare -grx global_conf_fetch="${global_child_profile_flow}/docker-finance.d/fetch/fetch.yaml" + declare -grx global_conf_hledger="${global_child_profile_flow}/docker-finance.d/hledger/hledger.conf" declare -grx global_conf_meta="${global_child_profile_flow}/docker-finance.d/meta/meta.csv" declare -grx global_conf_shell="${global_child_profile_flow}/docker-finance.d/shell/subprofile.bash" From f7d1542b32c03b6f10f1748fa65812dd53973e6c Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Fri, 5 Jul 2024 23:32:58 -0700 Subject: [PATCH 4/7] container: lib_edit: create if not found, refactor --- .../src/finance/lib/internal/lib_edit.bash | 75 +++++++++++++++---- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/container/src/finance/lib/internal/lib_edit.bash b/container/src/finance/lib/internal/lib_edit.bash index 83e0659..5078cda 100644 --- a/container/src/finance/lib/internal/lib_edit.bash +++ b/container/src/finance/lib/internal/lib_edit.bash @@ -201,22 +201,45 @@ function lib_edit::__parse_args() function lib_edit::__edit() { [ -z "$EDITOR" ] && lib_utils::die_fatal - [ -z "$global_child_profile" ] && lib_utils::die_fatal - [ -z "$global_child_profile_flow" ] && lib_utils::die_fatal - [ -z "$global_conf_fetch" ] && lib_utils::die_fatal - [ -z "$global_conf_hledger" ] && lib_utils::die_fatal - [ -z "$global_conf_meta" ] && lib_utils::die_fatal - [ -z "$global_conf_shell" ] && lib_utils::die_fatal for _type in "${global_arg_type[@]}"; do case "$_type" in fetch) - $EDITOR "$global_conf_fetch" + [ -z "$global_conf_fetch" ] && lib_utils::die_fatal + + local _dir + _dir="$(dirname $global_conf_fetch)" + [ ! -d "$_dir" ] && mkdir -p "$_dir" + + local _file + _file="$(basename $global_conf_fetch)" + + local _path + _path="${_dir}/${_file}" + [ ! -f "$_path" ] && touch "$_path" + + $EDITOR "$_path" || lib_utils::die_fatal ;; hledger) - $EDITOR "$global_conf_hledger" + [ -z "$global_conf_hledger" ] && lib_utils::die_fatal + + local _dir + _dir="$(dirname $global_conf_hledger)" + [ ! -d "$_dir" ] && mkdir -p "$_dir" + + local _file + _file="$(basename $global_conf_hledger)" + + local _path + _path="${_dir}/${_file}" + [ ! -f "$_path" ] && touch "$_path" + + $EDITOR "$_path" || lib_utils::die_fatal ;; iadd | manual) + [ -z "$global_child_profile" ] && lib_utils::die_fatal + [ -z "$global_child_profile_flow" ] && lib_utils::die_fatal + local _path="${global_child_profile_flow}/import/${global_child_profile}/_manual_/${global_arg_year}" [ ! -d "$_path" ] && mkdir -p "$_path" @@ -230,16 +253,29 @@ function lib_edit::__edit() [[ "$_type" == "manual" ]] && $EDITOR "$_path" ;; meta) + [ -z "$global_conf_meta" ] && lib_utils::die_fatal + + local _dir + _dir="$(dirname $global_conf_meta)" + [ ! -d "$_dir" ] && mkdir -p "$_dir" + + local _file + _file="$(basename $global_conf_meta)" + + local _path + _path="${_dir}/${_file}" + [ ! -f "$_path" ] && touch "$_path" + # NOTE: # - Expects comments to begin with format: //! # - If saved to original, opening with `--skip` will clobber the # original file's comments. - local -r _skip="$(grep -E "^//!" $global_conf_meta | wc -l)" - visidata --quitguard --motd-url file:///dev/null --filetype csv --skip "$_skip" "$global_conf_meta" + local -r _skip="$(grep -E "^//!" $_path | wc -l)" + visidata --quitguard --motd-url file:///dev/null --filetype csv --skip "$_skip" "$_path" # TODO: HACK: visidata saves w/ DOS-style carriage... # ...but there seems to be no option out of this. - sed -i 's:\r::g' "$global_conf_meta" + sed -i 's:\r::g' "$_path" ;; preprocess | rules) # Run all paths through one editor instance @@ -278,10 +314,23 @@ function lib_edit::__edit() done # Execute - $EDITOR "${_paths[@]}" + $EDITOR "${_paths[@]}" || lib_utils::die_fatal ;; shell) - $EDITOR "$global_conf_shell" + [ -z "$global_conf_shell" ] && lib_utils::die_fatal + + local _dir + _dir="$(dirname $global_conf_shell)" + [ ! -d "$_dir" ] && mkdir -p "$_dir" + + local _file + _file="$(basename $global_conf_shell)" + + local _path + _path="${_dir}/${_file}" + [ ! -f "$_path" ] && touch "$_path" + + $EDITOR "$_path" || lib_utils::die_fatal ;; esac done From b0bc67deb19365aa2e1389116897545e73210cbb Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Fri, 5 Jul 2024 23:53:01 -0700 Subject: [PATCH 5/7] container: lib_ledger: use PATH for hledger{-ui,-web,-flow} --- container/src/finance/lib/internal/lib_ledger.bash | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/container/src/finance/lib/internal/lib_ledger.bash b/container/src/finance/lib/internal/lib_ledger.bash index 7eaf7d9..68c127e 100644 --- a/container/src/finance/lib/internal/lib_ledger.bash +++ b/container/src/finance/lib/internal/lib_ledger.bash @@ -124,29 +124,29 @@ function lib_ledger::__ledger-import() fi [ -z "$global_child_profile_journal" ] && lib_utils::die_fatal - time /usr/local/bin/hledger-flow import \ + time hledger-flow import \ "$(dirname $global_child_profile_journal)" --start-year "$global_arg_year" } function lib_ledger::__ledger-cli() { - /usr/bin/hledger -f "$global_child_profile_journal" "$@" + hledger -f "$global_child_profile_journal" "$@" } function lib_ledger::__ledger-ui() { - /usr/bin/hledger-ui -f "$global_child_profile_journal" "$@" + hledger-ui -f "$global_child_profile_journal" "$@" } function lib_ledger::__ledger-vui() { - /usr/bin/hledger -f "$global_child_profile_journal" print -O csv "$@" \ + hledger -f "$global_child_profile_journal" print -O csv "$@" \ | visidata --motd-url file:///dev/null --filetype csv } function lib_ledger::__ledger-web() { - /usr/bin/hledger-web -f "$global_child_profile_journal" "$@" + hledger-web -f "$global_child_profile_journal" "$@" } # vim: sw=2 sts=2 si ai et From 190ac2864d3476f40d82457c2a79e50deee6647e Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sat, 6 Jul 2024 00:35:47 -0700 Subject: [PATCH 6/7] container: lib_ledger: refactor for base arguments - Future-proof for hledger features - Related refactoring --- .../src/finance/lib/internal/lib_ledger.bash | 67 ++++++++++++++++--- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/container/src/finance/lib/internal/lib_ledger.bash b/container/src/finance/lib/internal/lib_ledger.bash index 68c127e..7c68ba3 100644 --- a/container/src/finance/lib/internal/lib_ledger.bash +++ b/container/src/finance/lib/internal/lib_ledger.bash @@ -30,30 +30,35 @@ source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_utils.bash function lib_ledger::ledger-import() { + lib_ledger::__ledger "$@" lib_ledger::__ledger-import "$@" lib_utils::catch $? } function lib_ledger::ledger-cli() { + lib_ledger::__ledger "$@" lib_ledger::__ledger-cli "$@" lib_utils::catch $? } function lib_ledger::ledger-ui() { + lib_ledger::__ledger "$@" lib_ledger::__ledger-ui "$@" lib_utils::catch $? } function lib_ledger::ledger-vui() { + lib_ledger::__ledger "$@" lib_ledger::__ledger-vui "$@" lib_utils::catch $? } function lib_ledger::ledger-web() { + lib_ledger::__ledger "$@" lib_ledger::__ledger-web "$@" lib_utils::catch $? } @@ -62,7 +67,38 @@ function lib_ledger::ledger-web() # Implementation # -function lib_ledger::__ledger-import() +# Constructor +function lib_ledger::__ledger() +{ + # Base arguments to hledger before end-user added + [ -z "$global_child_profile_journal" ] && lib_utils::die_fatal + declare -g global_base_args=("-f" "$global_child_profile_journal") + + # + # Apply features to given hledger version. + # + # CLI version formats: + # + # hledger 1.34, linux-x86_64 + # hledger 1.34.99-gcf0c7c2ef-20240702, linux-x86_64 + # + # TODO: hope that container platforms will package 1.35 before 1.40 rolls out + # + + # 1.34.99 and above + hledger --version \ + | gawk '{ if ($2 !~ /^1.3(4.99|([5-9][\.[0-99]?))/) { exit 1 } }' FS=' ' + + if [ $? -eq 0 ]; then + # --conf is supported + [ -z "$global_conf_hledger" ] && lib_utils::die_fatal + global_base_args+=("--conf" "$global_conf_hledger") + fi + + lib_utils::print_debug "${global_base_args[*]}" "$@" +} + +function lib_ledger::__parse_ledger-import() { [ -z "$global_usage" ] && lib_utils::die_fatal [ -z "$global_arg_delim_1" ] && lib_utils::die_fatal @@ -80,7 +116,7 @@ function lib_ledger::__ledger-import() \e[32mArguments:\e[0m - Fetch year: + Import year: year${global_arg_delim_2} @@ -94,13 +130,11 @@ function lib_ledger::__ledger-import() lib_utils::die_usage "$_usage" fi - # Get/Set year if [ ! -z "$_arg" ]; then if [[ ! "$_arg" =~ ^year[s]?${global_arg_delim_2} ]]; then lib_utils::die_usage "$_usage" fi - # Parse key for value local _key="${_arg%${global_arg_delim_2}*}" local _len="$((${#_key} + 1))" if [[ "$_key" =~ ^year[s]?$ ]]; then @@ -122,31 +156,44 @@ function lib_ledger::__ledger-import() global_arg_year="$(date +%Y)" declare -gr global_arg_year fi +} + +function lib_ledger::__ledger-import() +{ + lib_ledger::__parse_ledger-import "$@" - [ -z "$global_child_profile_journal" ] && lib_utils::die_fatal time hledger-flow import \ - "$(dirname $global_child_profile_journal)" --start-year "$global_arg_year" + "$(dirname $global_child_profile_journal)" \ + --start-year "$global_arg_year" } function lib_ledger::__ledger-cli() { - hledger -f "$global_child_profile_journal" "$@" + [ -z "${global_base_args[*]}" ] && lib_utils::die_fatal + + hledger "${global_base_args[@]}" "$@" } function lib_ledger::__ledger-ui() { - hledger-ui -f "$global_child_profile_journal" "$@" + [ -z "${global_base_args[*]}" ] && lib_utils::die_fatal + + hledger-ui "${global_base_args[@]}" "$@" } function lib_ledger::__ledger-vui() { - hledger -f "$global_child_profile_journal" print -O csv "$@" \ + [ -z "${global_base_args[*]}" ] && lib_utils::die_fatal + + hledger "${global_base_args[@]}" print -O csv "$@" \ | visidata --motd-url file:///dev/null --filetype csv } function lib_ledger::__ledger-web() { - hledger-web -f "$global_child_profile_journal" "$@" + [ -z "${global_base_args[*]}" ] && lib_utils::die_fatal + + hledger-web "${global_base_args[@]}" "$@" } # vim: sw=2 sts=2 si ai et From 4316172e4c7d68f3a47c95f330d502ed71717643 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Mon, 8 Jul 2024 18:09:36 -0700 Subject: [PATCH 7/7] container: subprofile.bash.in: add TODO re: --conf --- client/docker-finance.d/container/shell/subprofile.bash.in | 1 + 1 file changed, 1 insertion(+) diff --git a/client/docker-finance.d/container/shell/subprofile.bash.in b/client/docker-finance.d/container/shell/subprofile.bash.in index 80217b6..bd77453 100644 --- a/client/docker-finance.d/container/shell/subprofile.bash.in +++ b/client/docker-finance.d/container/shell/subprofile.bash.in @@ -26,6 +26,7 @@ [ -z "$DOCKER_FINANCE_CONTAINER_CMD" ] && echo "DOCKER_FINANCE_CONTAINER_CMD not set, check installation" >&2 # NOTE: ledger-based commands ending in `\`: the escape is needed so you can add more arguments as needed +# TODO: remove default 'not:' arguments to `ledger{-ui,-web}` once distributions support hledger 1.34.99-gcf0c7c2ef-20240702 or higher (--conf support) # CLI ledger alias @DOCKER_FINANCE_SUBPROFILE@_ledger='$DOCKER_FINANCE_CONTAINER_CMD @DOCKER_FINANCE_PROFILE@/@DOCKER_FINANCE_SUBPROFILE@ ledger'