client: src: lib_gen: add args and args parsing

- Allows for a dynamic `gen` experience
  * All configs/accounts can now be (re)generated on-the-fly
    - Individually, by section, or all at once
  * Adds prompt confirmation option
  * Adds developer profile option
This commit is contained in:
2024-09-22 18:34:19 -07:00
parent 9f6ad19112
commit e8509384d2
2 changed files with 332 additions and 1 deletions

View File

@@ -33,15 +33,346 @@ source "${DOCKER_FINANCE_CLIENT_REPO}/container/src/finance/lib/internal/lib_uti
# Implementation
#
function lib_gen::__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
# All available hledger-flow accounts
local _accounts
mapfile -t _accounts < <(find ${DOCKER_FINANCE_CLIENT_REPO}/container/src/hledger-flow/accounts -name template | sort | rev | cut -d/ -f2 | rev)
declare -r _accounts
local -r _usage="
\e[32mDescription:\e[0m
Generate environment and configurations
\e[32mUsage:\e[0m
$ $global_usage <<[all${global_arg_delim_2}<type1[{${global_arg_delim_2}type2${global_arg_delim_3}...}]>] [type${global_arg_delim_3}<type1[${global_arg_delim_3}type2...]>]> [<[profile${global_arg_delim_2}<profile>]> [config${global_arg_delim_2}<config1[${global_arg_delim_3}config2...]>] [account${global_arg_delim_2}<account1[${global_arg_delim_3}account2...]>]] [confirm${global_arg_delim_2}<{on|yes|true} | {off|no|false}>] [dev${global_arg_delim_2}<{on|yes|true} | {off|no|false}>]
\e[32mArguments:\e[0m
All categories and data:
all${global_arg_delim_2}<all | type>
Note: 'type' is currently the same as 'all'
Category type:
type${global_arg_delim_2}<env | build | flow | superscript>
Flow (only):
Full profile (w/ subprofile):
profile${global_arg_delim_2}<parent${global_arg_delim_1}child>
Configuration type:
config${global_arg_delim_2}<fetch | hledger | meta | subprofile>
Accounts:
account${global_arg_delim_2}<$(echo "${_accounts[@]}" | sed 's: : | :g')>
Enable developer profile w/ mockups:
dev${global_arg_delim_2}<{on|yes|true} | {off|no|false}> # (default disabled)
Enable confirmations:
confirm${global_arg_delim_2}<{on|yes|true} | {off|no|false}> # (default enabled)
\e[32mExamples:\e[0m
\e[37;2m#\e[0m
\e[37;2m# All (client, container)\e[0m
\e[37;2m#\e[0m
\e[37;2m# Generate all client and container data\e[0m
$ $global_usage all${global_arg_delim_2}all
\e[37;2m# Generate all client and container data, skipping confirmations (using a default profile/subprofile name)\e[0m
$ $global_usage all${global_arg_delim_2}all confirm${global_arg_delim_2}no
\e[37;2m# Generate all client and container data for profile called 'parent/child', skipping confirmations\e[0m
$ $global_usage all${global_arg_delim_2}all profile${global_arg_delim_2}parent${global_arg_delim_1}child confirm${global_arg_delim_2}off
\e[37;2m#\e[0m
\e[37;2m# Client (joint container)\e[0m
\e[37;2m#\e[0m
\e[37;2m# Generate only the Docker environment\e[0m
$ $global_usage type${global_arg_delim_2}env
\e[37;2m# Generate custom Dockerfile and joint client/container superscript\e[0m
$ $global_usage type${global_arg_delim_2}build${global_arg_delim_3}superscript
\e[37;2m# Generate all client related data\e[0m
$ $global_usage type${global_arg_delim_2}env${global_arg_delim_3}build${global_arg_delim_3}superscript
\e[37;2m#\e[0m
\e[37;2m# Flow: Profile -> Configs / Accounts\e[0m
\e[37;2m#\e[0m
\e[37;2m# Generate all client related and all flow related for profile/subprofile called 'parent/child'\e[0m
$ $global_usage type${global_arg_delim_2}env${global_arg_delim_3}build${global_arg_delim_3}superscript${global_arg_delim_3}flow profile${global_arg_delim_2}parent${global_arg_delim_1}child
\e[37;2m# Same command as above but without confirmations and with developer mockups\e[0m
$ $global_usage type${global_arg_delim_2}env${global_arg_delim_3}build${global_arg_delim_3}superscript${global_arg_delim_3}flow profile${global_arg_delim_2}parent${global_arg_delim_1}child confirm${global_arg_delim_2}false dev${global_arg_delim_2}true
\e[37;2m# Generate only the given configurations for 'parent/child'\e[0m
$ $global_usage type${global_arg_delim_2}flow profile${global_arg_delim_2}parent${global_arg_delim_1}child config${global_arg_delim_2}fetch${global_arg_delim_3}hledger${global_arg_delim_3}meta${global_arg_delim_3}subprofile
\e[37;2m# Generate only the given accounts for 'parent/child'\e[0m
$ $global_usage type${global_arg_delim_2}flow profile${global_arg_delim_2}parent${global_arg_delim_1}child account${global_arg_delim_2}capital-one${global_arg_delim_3}chase${global_arg_delim_3}coinbase
\e[37;2m# Generate the given configs and accounts for given 'parent/child'\e[0m
$ $global_usage type${global_arg_delim_2}flow profile${global_arg_delim_2}parent${global_arg_delim_1}child config${global_arg_delim_2}meta${global_arg_delim_3}subprofile account${global_arg_delim_2}ethereum-based${global_arg_delim_3}metamask
\e[32mNotes:\e[0m
- The 'profile' argument is limited to 'type' flow
- The 'config' and 'account' arguments require 'profile'
"
#
# Ensure supported arguments
#
[ $# -eq 0 ] && lib_utils::die_usage "$_usage"
for _arg in "$@"; do
[[ ! "$_arg" =~ ^all${global_arg_delim_2} ]] \
&& [[ ! "$_arg" =~ ^type${global_arg_delim_2} ]] \
&& [[ ! "$_arg" =~ ^profile${global_arg_delim_2} ]] \
&& [[ ! "$_arg" =~ ^config[s]?${global_arg_delim_2} ]] \
&& [[ ! "$_arg" =~ ^account[s]?${global_arg_delim_2} ]] \
&& [[ ! "$_arg" =~ ^confirm${global_arg_delim_2} ]] \
&& [[ ! "$_arg" =~ ^dev${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" =~ ^all$ ]]; then
local _arg_all="${_arg:${_len}}"
[ -z "$_arg_all" ] && lib_utils::die_usage "$_usage"
fi
if [[ "$_key" =~ ^type$ ]]; then
local _arg_type="${_arg:${_len}}"
[ -z "$_arg_type" ] && lib_utils::die_usage "$_usage"
fi
if [[ "$_key" =~ ^profile$ ]]; then
local _arg_profile="${_arg:${_len}}"
[ -z "$_arg_profile" ] && lib_utils::die_usage "$_usage"
fi
if [[ "$_key" =~ ^config[s]?$ ]]; then
local _arg_config="${_arg:${_len}}"
[ -z "$_arg_config" ] && 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" =~ ^confirm$ ]]; then
local _arg_confirm="${_arg:${_len}}"
[ -z "$_arg_confirm" ] && lib_utils::die_usage "$_usage"
fi
if [[ "$_key" =~ ^dev$ ]]; then
local _arg_dev="${_arg:${_len}}"
[ -z "$_arg_dev" ] && lib_utils::die_usage "$_usage"
fi
done
#
# Test for valid ordering/functionality of argument values
#
[[ -z "$_arg_all" && -z "$_arg_type" ]] && lib_utils::die_usage "$_usage"
# Arg: all
if [ ! -z "$_arg_all" ]; then
# If all= then no need for type= or config= or account=
if [[ ! -z "$_arg_type" || ! -z "$_arg_config" || ! -z "$_arg_account" ]]; then
lib_utils::die_usage "$_usage"
fi
fi
# Arg: type
# Note: check not needed
# Arg: profile
if [ ! -z "$_arg_profile" ]; then
# Requires type to be set
if [[ ! "${_arg_all[*]}" =~ all|type && -z "$_arg_type" ]]; then
lib_utils::die_usage "$_usage"
fi
fi
# Arg: config
if [ ! -z "$_arg_config" ]; then
# Requires profile to be set
if [ -z "$_arg_profile" ]; then
lib_utils::die_usage "$_usage"
fi
fi
# Arg: account
if [ ! -z "$_arg_account" ]; then
# Requires profile to be set
if [ -z "$_arg_profile" ]; then
lib_utils::die_usage "$_usage"
fi
fi
# Arg: confirm
# Note: optional argument, check not needed
# Arg: dev
# Note: optional argument, check not needed
#
# Test argument values, set globals
#
IFS="$global_arg_delim_3"
# Arg: all
if [ ! -z "$_arg_all" ]; then
read -ra _read <<<"$_arg_all"
for _arg in "${_read[@]}"; do
# Supported values
[[ ! "$_arg" =~ ^all$|^type[s]?$ ]] \
&& lib_utils::die_usage "$_usage"
# If all=all then no need for all={type}
[[ "$_arg" == "all" && "${#_read[@]}" -gt 1 ]] \
&& lib_utils::die_usage "$_usage"
done
# TODO: currently, 'all' will be equivalent 'type'
declare -gr global_arg_all=("${_read[@]}")
fi
# Arg: type
if [ ! -z "$_arg_type" ]; then
read -ra _read <<<"$_arg_type"
for _arg in "${_read[@]}"; do
if [[ ! "$_arg" =~ ^env$|^build$|^flow$|^superscript$ ]]; then
lib_utils::die_usage "$_usage"
fi
done
declare -gr global_arg_type=("${_read[@]}")
fi
# Arg: profile
if [ ! -z "$_arg_profile" ]; then
# Requires flow type
if [[ ! "${global_arg_all[*]}" =~ all|type && ! "${global_arg_type[*]}" =~ flow ]]; then
lib_utils::die_usage "$_usage"
fi
if [[ ! "$_arg_profile" =~ $global_arg_delim_1 ]]; then
lib_utils::die_usage "$_usage"
fi
declare -gr global_arg_profile="${_arg_profile%${global_arg_delim_1}*}"
declare -gr global_arg_subprofile="${_arg_profile##*${global_arg_delim_1}}"
fi
# Arg: config
if [ ! -z "$_arg_config" ]; then
# Requires profile type
if [ -z "$global_arg_profile" ]; then
lib_utils::die_usage "$_usage"
fi
read -ra _read <<<"$_arg_config"
for _arg in "${_read[@]}"; do
if [[ ! "$_arg" =~ ^fetch$|^hledger$|^meta$|^subprofile$ ]]; then
lib_utils::die_usage "$_usage"
fi
done
declare -gr global_arg_config=("${_read[@]}")
fi
# Arg: account
if [ ! -z "$_arg_account" ]; then
# Requires profile type
if [ -z "$global_arg_profile" ]; then
lib_utils::die_usage "$_usage"
fi
read -ra _read <<<"$_arg_account"
# Test if given account is supported
for _arg in "${_read[@]}"; do
_found=false
for _account in "${_accounts[@]}"; do
[[ "$_arg" == "$_account" ]] && _found=true
done
[ $_found == true ] && continue || lib_utils::die_usage "$_usage"
done
declare -gr global_arg_account=("${_read[@]}")
fi
# Arg: confirm
if [ ! -z "$_arg_confirm" ]; then
if [[ ! "$_arg_confirm" =~ (^on$|^yes$|^true$)|(^off$|^no$|^false$) ]]; then
lib_utils::die_usage "$_usage"
fi
if [[ "$_arg_confirm" =~ ^off$|^no$|^false$ ]]; then
declare -gr global_arg_confirm=""
else
declare -gr global_arg_confirm="true"
fi
else
declare -gr global_arg_confirm="true"
fi
# Arg: dev
if [ ! -z "$_arg_dev" ]; then
if [[ ! "$_arg_dev" =~ (^on$|^yes$|^true$)|(^off$|^no$|^false$) ]]; then
lib_utils::die_usage "$_usage"
fi
if [[ "$_arg_dev" =~ ^on$|^yes$|^true$ ]]; then
declare -gr global_arg_dev="true"
else
declare -gr global_arg_dev=""
fi
else
declare -gr global_arg_dev=""
fi
}
#
# Generate new configurations or layout
#
function lib_gen::gen()
{
lib_gen::__parse_args "$@"
lib_utils::print_custom "\n"
lib_utils::print_info "Generating client/container environment"
# TODO: this warning is likely not needed now that lib_env is ensured
# WARNING: client generation MUST be done before container generation
lib_gen::__gen_client

View File

@@ -124,7 +124,7 @@ function lib_docker::docker()
function lib_docker::gen()
{
lib_gen::gen
lib_gen::gen "$@"
lib_utils::catch $?
}