forked from EvergreenCrypto/docker-finance
284 lines
8.5 KiB
Bash
284 lines
8.5 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# docker-finance | modern accounting for the power-user
|
|
#
|
|
# Copyright (C) 2021-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/>.
|
|
|
|
#
|
|
# "Libraries"
|
|
#
|
|
|
|
[ -z "$DOCKER_FINANCE_CONTAINER_REPO" ] && exit 1
|
|
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_utils.bash" || exit 1
|
|
|
|
#
|
|
# Facade
|
|
#
|
|
|
|
function lib_edit::edit()
|
|
{
|
|
lib_edit::__parse_args "$@"
|
|
lib_edit::__edit
|
|
lib_utils::catch $?
|
|
}
|
|
|
|
#
|
|
# Implementation
|
|
#
|
|
|
|
function lib_edit::__parse_args()
|
|
{
|
|
[ -z "$global_usage" ] && lib_utils::die_fatal
|
|
[ -z "$global_arg_delim_1" ] && lib_utils::die_fatal
|
|
[ -z "$global_arg_delim_2" ] && lib_utils::die_fatal
|
|
[ -z "$global_arg_delim_3" ] && lib_utils::die_fatal
|
|
|
|
local -r _usage="
|
|
\e[32mDescription:\e[0m
|
|
|
|
Edit container configuration files and journals
|
|
|
|
\e[32mUsage:\e[0m
|
|
|
|
$ $global_usage <type${global_arg_delim_2}<type>> [account${global_arg_delim_2}<account[${global_arg_delim_1}subaccount]>]
|
|
|
|
\e[32mArguments:\e[0m
|
|
|
|
Configuration type:
|
|
|
|
type${global_arg_delim_2}<fetch|manual|meta|shell|rules|preprocess>
|
|
|
|
Account:
|
|
|
|
account${global_arg_delim_2}<user-defined for rules|preprocess (see examples)>
|
|
|
|
\e[32mExamples:\e[0m
|
|
|
|
\e[37;2m# Edit fetch configuration\e[0m
|
|
$ $global_usage type${global_arg_delim_2}fetch
|
|
|
|
\e[37;2m# Edit meta and subprofile configurations\e[0m
|
|
$ $global_usage type${global_arg_delim_2}meta${global_arg_delim_3}shell
|
|
|
|
\e[37;2m# Edit _manual_ journal for year 2023\e[0m
|
|
$ $global_usage type${global_arg_delim_2}manual year=2023
|
|
|
|
\e[37;2m# Edit subaccount rules for acccount${global_arg_delim_1}subaccount\e[0m
|
|
$ $global_usage type${global_arg_delim_2}rules account${global_arg_delim_2}gemini${global_arg_delim_1}exchange
|
|
|
|
\e[37;2m# Edit shared rules for multiple accounts\e[0m
|
|
$ $global_usage type${global_arg_delim_2}rules account${global_arg_delim_2}electrum${global_arg_delim_3}ethereum-based
|
|
|
|
\e[37;2m# Edit subaccount rules for multiple account${global_arg_delim_1}subaccount\e[0m
|
|
$ $global_usage account${global_arg_delim_2}ledger${global_arg_delim_1}nano${global_arg_delim_3}trezor${global_arg_delim_1}model type${global_arg_delim_2}rules
|
|
|
|
\e[37;2m# Edit subaccount preprocess and rules for multiple account${global_arg_delim_1}subaccount\e[0m
|
|
$ $global_usage account${global_arg_delim_2}coinbase${global_arg_delim_1}platform${global_arg_delim_3}electrum${global_arg_delim_1}wallet-1${global_arg_delim_3}coinomi${global_arg_delim_1}wallet-1 type${global_arg_delim_2}preprocess${global_arg_delim_3}rules
|
|
"
|
|
|
|
#
|
|
# Ensure supported arguments
|
|
#
|
|
|
|
[ $# -eq 0 ] && lib_utils::die_usage "$_usage"
|
|
|
|
for _arg in "$@"; do
|
|
[[ ! "$_arg" =~ ^type[s]?${global_arg_delim_2} ]] \
|
|
&& [[ ! "$_arg" =~ ^account[s]?${global_arg_delim_2} ]] \
|
|
&& [[ ! "$_arg" =~ ^year[s]?${global_arg_delim_2} ]] \
|
|
&& lib_utils::die_usage "$_usage"
|
|
done
|
|
|
|
#
|
|
# Parse arguments before testing
|
|
#
|
|
|
|
# Parse key for value
|
|
for _arg in "$@"; do
|
|
|
|
local _key="${_arg%${global_arg_delim_2}*}"
|
|
local _len="$((${#_key} + 1))"
|
|
|
|
if [[ "$_key" =~ ^type[s]?$ ]]; then
|
|
local _arg_type="${_arg:${_len}}"
|
|
[ -z "$_arg_type" ] && lib_utils::die_usage "$_usage"
|
|
fi
|
|
|
|
if [[ "$_key" =~ ^account[s]?$ ]]; then
|
|
local _arg_account="${_arg:${_len}}"
|
|
[ -z "$_arg_account" ] && lib_utils::die_usage "$_usage"
|
|
fi
|
|
|
|
if [[ "$_key" =~ ^year[s]?$ ]]; then
|
|
local _arg_year="${_arg:${_len}}"
|
|
[ -z "$_arg_year" ] && lib_utils::die_usage "$_usage"
|
|
fi
|
|
done
|
|
|
|
#
|
|
# Test for valid ordering/functionality of argument values
|
|
#
|
|
|
|
# Arg: account
|
|
if [ ! -z "$_arg_account" ]; then
|
|
if [ -z "$_arg_type" ]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
fi
|
|
|
|
# Arg: year
|
|
if [ ! -z "$_arg_year" ]; then
|
|
if [[ -z "$_arg_type" ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
fi
|
|
|
|
#
|
|
# Test argument values, set globals
|
|
#
|
|
|
|
IFS="$global_arg_delim_3"
|
|
|
|
# Arg: type
|
|
if [ ! -z "$_arg_type" ]; then
|
|
read -ra _read <<<"$_arg_type"
|
|
|
|
for _type in "${_read[@]}"; do
|
|
if [[ ! "$_type" =~ ^fetch$|^iadd$|^manual$|^meta$|^preprocess$|^rules$|^shell$ ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
if [[ ! -z "$_arg_account" ]]; then
|
|
if [[ ! "$_type" =~ ^preprocess$|^rules$ ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
fi
|
|
if [[ -z "$_arg_account" ]]; then
|
|
if [[ "$_type" =~ ^preprocess$|^rules$ ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
declare -gr global_arg_type=("${_read[@]}")
|
|
fi
|
|
|
|
# Arg: account
|
|
if [ ! -z "$_arg_account" ]; then
|
|
read -ra _read <<<"$_arg_account"
|
|
declare -gr global_arg_account=("${_read[@]}")
|
|
fi
|
|
|
|
# Arg: year
|
|
# TODO: implement range
|
|
if [ ! -z "$_arg_year" ]; then
|
|
# TODO: 20th century support
|
|
if [[ ! "$_arg_year" =~ ^20[0-9][0-9]$ || ! ${global_arg_type[*]} =~ ^manual$ ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
declare -gr global_arg_year="$_arg_year"
|
|
else
|
|
global_arg_year="$(date +%Y)" # Set default current
|
|
declare -gr global_arg_year
|
|
fi
|
|
}
|
|
|
|
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"
|
|
;;
|
|
iadd | manual)
|
|
local _path="${global_child_profile_flow}/import/${global_child_profile}/_manual_/${global_arg_year}"
|
|
[ ! -d "$_path" ] && mkdir -p "$_path"
|
|
|
|
_path+="/post-import.journal"
|
|
[ ! -f "$_path" ] && touch "$_path"
|
|
|
|
# TODO: upstream request to provide comment(N) entries
|
|
[[ "$_type" == "iadd" ]] && /usr/bin/hledger-iadd -f "$_path"
|
|
|
|
# TODO: option for editor type
|
|
[[ "$_type" == "manual" ]] && $EDITOR "$_path"
|
|
;;
|
|
meta)
|
|
# 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"
|
|
|
|
# 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"
|
|
;;
|
|
preprocess | rules)
|
|
# Run all paths through one editor instance
|
|
local _paths=()
|
|
|
|
# Prepare account/account-shared.* or account/subaccount/account-subaccount.*
|
|
for _account in "${global_arg_account[@]}"; do
|
|
local _acct="${_account%${global_arg_delim_1}*}"
|
|
|
|
# Attempting to parse out an empty arg will result in dup account as sub
|
|
[[ "$_account" =~ ${global_arg_delim_1} ]] \
|
|
&& local _sub="${_account#*${global_arg_delim_1}}"
|
|
|
|
local _path="${global_child_profile_flow}/import/${global_child_profile}/"
|
|
[ ! -z "$_sub" ] && _path+="${_acct}/${_sub}/"
|
|
|
|
case "$_type" in
|
|
preprocess)
|
|
[ -z "$_sub" ] \
|
|
&& local _file="${_acct}-shared.bash" \
|
|
|| local _file="$_type"
|
|
;;
|
|
rules)
|
|
[ -z "$_sub" ] \
|
|
&& local _file="${_acct}-shared.${_type}" \
|
|
|| local _file="${_acct}-${_sub}.${_type}"
|
|
;;
|
|
esac
|
|
|
|
_path+="$_file"
|
|
if [ ! -f "$_path" ]; then
|
|
lib_utils::die_fatal "File not found: $_path"
|
|
else
|
|
_paths+=("$_path")
|
|
fi
|
|
done
|
|
|
|
# Execute
|
|
$EDITOR "${_paths[@]}"
|
|
;;
|
|
shell)
|
|
$EDITOR "$global_conf_shell"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# vim: sw=2 sts=2 si ai et
|