diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index eb5934d..afcd128 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -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}] [type${global_arg_delim_3}]> [<[profile${global_arg_delim_2}]> [config${global_arg_delim_2}] [account${global_arg_delim_2}]] [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} + + Note: 'type' is currently the same as 'all' + + Category type: + + type${global_arg_delim_2} + + Flow (only): + + Full profile (w/ subprofile): + + profile${global_arg_delim_2} + + Configuration type: + + config${global_arg_delim_2} + + 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 diff --git a/client/src/docker/lib/lib_docker.bash b/client/src/docker/lib/lib_docker.bash index 5b783e1..5b7a05f 100644 --- a/client/src/docker/lib/lib_docker.bash +++ b/client/src/docker/lib/lib_docker.bash @@ -124,7 +124,7 @@ function lib_docker::docker() function lib_docker::gen() { - lib_gen::gen + lib_gen::gen "$@" lib_utils::catch $? }