Merge pull request #78 into master

4316172 container: subprofile.bash.in: add TODO re: --conf (Aaron Fiore)
190ac28 container: lib_ledger: refactor for base arguments (Aaron Fiore)
b0bc67d container: lib_ledger: use PATH for hledger{-ui,-web,-flow} (Aaron Fiore)
f7d1542 container: lib_edit: create if not found, refactor (Aaron Fiore)
adebadb container: lib_edit: add hledger conf support (Aaron Fiore)
c2ac298 client: lib_gen: add hledger conf support (Aaron Fiore)
bbbecff client: docker-finance.d: add hledger.conf.in (Aaron Fiore)
This commit is contained in:
2024-07-09 18:51:21 -07:00
6 changed files with 221 additions and 27 deletions

View File

@@ -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 <https://www.gnu.org/licenses/>.
# 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

View File

@@ -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'

View File

@@ -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
#

View File

@@ -59,7 +59,7 @@ function lib_edit::__parse_args()
Configuration type:
type${global_arg_delim_2}<fetch|manual|meta|shell|rules|preprocess>
type${global_arg_delim_2}<fetch|hledger|manual|meta|shell|rules|preprocess>
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
@@ -198,18 +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_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)
[ -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"
@@ -223,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
@@ -271,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

View File

@@ -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}<all|year>
@@ -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
}
[ -z "$global_child_profile_journal" ] && lib_utils::die_fatal
time /usr/local/bin/hledger-flow import \
"$(dirname $global_child_profile_journal)" --start-year "$global_arg_year"
function lib_ledger::__ledger-import()
{
lib_ledger::__parse_ledger-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" "$@"
[ -z "${global_base_args[*]}" ] && lib_utils::die_fatal
hledger "${global_base_args[@]}" "$@"
}
function lib_ledger::__ledger-ui()
{
/usr/bin/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()
{
/usr/bin/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()
{
/usr/bin/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

View File

@@ -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"