From d8222c60fbf80460134ce75f3ead88998deb2aa8 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:31:55 -0700 Subject: [PATCH 01/13] client: src: refactor environment/gen handler - Moves environment handling from `lib_gen` to `lib_env` - Related refactoring --- .../src/docker/lib/internal/lib_docker.bash | 2 +- client/src/docker/lib/internal/lib_env.bash | 321 ++++++++++++++++++ client/src/docker/lib/internal/lib_gen.bash | 315 ++--------------- client/src/docker/lib/lib_docker.bash | 11 +- 4 files changed, 351 insertions(+), 298 deletions(-) create mode 100644 client/src/docker/lib/internal/lib_env.bash diff --git a/client/src/docker/lib/internal/lib_docker.bash b/client/src/docker/lib/internal/lib_docker.bash index d32914f..9a3d3ae 100644 --- a/client/src/docker/lib/internal/lib_docker.bash +++ b/client/src/docker/lib/internal/lib_docker.bash @@ -58,7 +58,7 @@ function lib_docker::__docker() [ -z "$global_platform" ] && lib_utils::die_fatal [ -z "$global_tag" ] && lib_utils::die_fatal - # Inherited from caller (via lib_gen) + # Inherited from caller (via `lib_env`) [ -z "$global_client_version" ] && lib_utils::die_fatal [ -z "$global_repo_dockerfiles" ] && lib_utils::die_fatal diff --git a/client/src/docker/lib/internal/lib_env.bash b/client/src/docker/lib/internal/lib_env.bash new file mode 100644 index 0000000..70120c2 --- /dev/null +++ b/client/src/docker/lib/internal/lib_env.bash @@ -0,0 +1,321 @@ +#!/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 . + +[ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && exit 1 + +# +# "Libraries" +# + +# Utilities (a container library (but container is never exposed to client code)) +source "${DOCKER_FINANCE_CLIENT_REPO}/container/src/finance/lib/internal/lib_utils.bash" || exit 1 + +# +# Implementation +# + +if [ $UID -lt 1000 ]; then + lib_utils::die_fatal "Do not run as root or system user!" +fi + +# IMPORTANT: keep umask for security +umask o-rwx + +if ! docker compose version 1>/dev/null; then + lib_utils::die_fatal "Docker compose plugin not installed" +fi + +if [ -z "$EDITOR" ]; then + editors=("vim" "vi" "emacs" "nano") + for editor in "${editors[@]}"; do + hash "$editor" &>/dev/null && export EDITOR="$editor" && break + done + if [ $? -ne 0 ]; then + lib_utils::die_fatal "Shell EDITOR is not set, export EDITOR in your shell" + fi +fi + +# +# "Constructor" for environment generation +# +# 1. Sets client-side environment with defaults or use existing environment +# 2. If configured, resets to alternative environment configuration after bootstrap +# +# NOTE: some bootstrapped defaults are ignored by environment file (as seen below) +# + +function lib_env::env() +{ + [ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && lib_utils::die_fatal + + # NOTE: global_* *MUST* be reset after sourcing new env file + + # + # Generate `docker-finance` version + # + + global_repo_manifest="${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.yaml" + declare -g global_repo_manifest + + global_client_version="$(grep '^version: ' $global_repo_manifest | sed -e 's/version: "//' -e 's/"//g')" + # shellcheck disable=SC2034 # used during env gen + declare -g global_client_version + + # + # If empty environment: + # + # 1. Poke at possible (default) location of end-user environment file + # a. If found, point to new location and read/reset from there + # + # 2. If file not found, bootstrap with defaults + # + + # Environment (end-user) + global_conf_filename="${USER}@$(uname -n)" + declare -g global_conf_filename + + # Environment (end-user) tag dir (not full path) + [ -z "$global_tag" ] && lib_utils::die_fatal + global_tag_dir="client/$(uname -s)-$(uname -m)/${global_platform}/${global_tag}" + declare -g global_tag_dir + + local _env_dir="/home/${USER}/.config/docker-finance.d/${global_tag_dir}/env" # NOTE: keep aligned with gen.bash + local _env_file="${_env_dir}/${global_conf_filename}" + + # shellcheck source=/dev/null + [ -f "$_env_file" ] && source "$_env_file" + + if [ -z "$DOCKER_FINANCE_CLIENT_CONF" ]; then + # shellcheck source=/dev/null + source "${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.d/client/env/gen.bash" + fi + + [ -z "$DOCKER_FINANCE_CLIENT_CONF" ] \ + && lib_utils::die_fatal "Defaults not generated! (${global_repo_env_file})" + + lib_env::__set_client_globals + + # + # Reset environment with user-provided (user-defined) existing file (if available) + # + + _env_dir="${DOCKER_FINANCE_CLIENT_CONF}/${global_tag_dir}/env" + _env_file="${_env_dir}/${global_conf_filename}" + + if [ -f "$_env_file" ]; then + if [ -s "$_env_file" ]; then + # Re-bootstrap with (new) environment + lib_utils::print_debug "Environment found! Using '${_env_file}'" + lib_env::__read "$_env_file" + lib_env::__set_client_globals + else + lib_utils::print_warning \ + "Client environment '${_env_file}' is empty! Writing defaults" + lib_env::__write "$_env_file" + fi + else + [ -z "$global_command" ] && lib_utils::die_fatal + [ -z "$global_basename" ] && lib_utils::die_fatal + + if [[ -z "$global_command" || "$global_command" != "gen" ]]; then + lib_utils::die_fatal \ + "Client environment not found! Run gen command'" + fi + + lib_utils::print_info \ + "Client environment not found, writing defaults to '${_env_file}'" + lib_env::__write "$_env_file" + fi +} + +# +# Set client globals from environment +# + +function lib_env::__set_client_globals() +{ + lib_utils::print_debug "Setting (or resetting) client globals" + + # + # Repository env + # + + [ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && lib_utils::die_fatal + + # Generate `docker-finance` version + global_repo_manifest="${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.yaml" + declare -g global_repo_manifest + lib_utils::print_debug "global_repo_manifest=${global_repo_manifest}" + + global_client_version="$(grep '^version: ' $global_repo_manifest | sed -e 's/version: "//' -e 's/"//g')" + # shellcheck disable=SC2034 # used during env gen + declare -g global_client_version + lib_utils::print_debug "global_client_version=${global_client_version}" + + # This does not reset when reading env; export again + export DOCKER_FINANCE_VERSION="$global_client_version" + lib_utils::print_debug "DOCKER_FINANCE_VERSION=${DOCKER_FINANCE_VERSION}" + + # Repository-provided (not user-defined) default environment + global_repo_conf_dir="${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.d" + declare -g global_repo_conf_dir + lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" + + # Environment (repo) + declare -g global_repo_env_file="${global_repo_conf_dir}/client/env/gen.bash" + [ ! -f "$global_repo_env_file" ] \ + && lib_utils::die_fatal "Missing environment defaults! ($global_repo_env_file)" + lib_utils::print_debug "global_repo_env_file=${global_repo_env_file}" + + # + # Repository env (Dockerfiles) + # + + # Set image type + [ -z "$global_platform" ] && lib_utils::die_fatal + case "$global_platform" in + archlinux | ubuntu) + global_platform_image="finance" + ;; + dev-tools) + global_platform_image="dev-tools" + ;; + *) + lib_utils::die_fatal "unsupported platform" + ;; + esac + declare -g global_platform_image + lib_utils::print_debug "global_platform_image=${global_platform_image}" + + # Base location of Docker-related files (.in and final out files) + global_repo_dockerfiles="${DOCKER_FINANCE_CLIENT_REPO}/client/Dockerfiles/local/${global_platform_image}" + # shellcheck disable=SC2034 # used in lib_docker + declare -g global_repo_dockerfiles + lib_utils::print_debug "global_repo_dockerfiles=${global_repo_dockerfiles}" + + # Base custom end-user .in Dockerfile (to be appended to final Dockerfile after installation) + declare -g global_repo_custom_dockerfile="${global_repo_conf_dir}/client/Dockerfiles/${global_platform_image}/Dockerfile.${global_platform}.in" + [ ! -f "$global_repo_custom_dockerfile" ] \ + && lib_utils::die_fatal "Missing default custom Dockerfile '${global_repo_custom_dockerfile}'" + lib_utils::print_debug "global_repo_custom_dockerfile=${global_repo_custom_dockerfile}" + + # + # Client-side env + # + + [ -z "$global_tag_dir" ] && lib_utils::die_fatal + + # Environment (end-user) format + [ -z "$DOCKER_FINANCE_USER" ] && lib_utils::die_fatal + global_conf_filename="${DOCKER_FINANCE_USER}@$(uname -n)" + declare -g global_conf_filename + lib_utils::print_debug "global_conf_filename=${global_conf_filename}" + + # Environment file (if available) + local _client_env_dir="${DOCKER_FINANCE_CLIENT_CONF}/${global_tag_dir}/env" + [ ! -d "$_client_env_dir" ] && mkdir -p "$_client_env_dir" + global_env_file="${_client_env_dir}/${global_conf_filename}" + lib_utils::print_debug "global_env_file=${global_env_file}" + + # Custom Dockerfile (if available) + local _client_dockerfile_dir="${DOCKER_FINANCE_CLIENT_CONF}/${global_tag_dir}/Dockerfiles" + [ ! -d "$_client_dockerfile_dir" ] && mkdir -p "$_client_dockerfile_dir" + global_custom_dockerfile="${_client_dockerfile_dir}/${global_conf_filename}" + lib_utils::print_debug "global_custom_dockerfile=${global_custom_dockerfile}" + + # NOTE: + # + # Client env tag format is avoided because: + # + # - We copy over static bash_aliases in Dockerfile, + # and superscript must be referenced by that static path + # + # - The needed dynamicness appears to not be satisfied via docker-compose + + local _client_shell_dir="${DOCKER_FINANCE_CLIENT_CONF}/container/shell" + [ ! -d "$_client_shell_dir" ] && mkdir -p "$_client_shell_dir" + global_shell_file="${_client_shell_dir}/superscript.bash" + lib_utils::print_debug "global_shell_file=${global_shell_file}" + + # Client view of client portion of repository + global_repo_client="${DOCKER_FINANCE_CLIENT_REPO}/client" + [ ! -d "$global_repo_client" ] && lib_utils::die_fatal "Repository '${global_repo_client}' not found!" + lib_utils::print_debug "global_repo_client=${global_repo_client}" + + # Backup-file extension + # TODO: make configurable + global_suffix="$(date +%Y-%m-%d_%H:%M:%S)" + lib_utils::print_debug "global_suffix=${global_suffix}" +} + +# +# Get/Set client-side environment with given file +# + +function lib_env::__read() +{ + local _file="$1" + + # Get environment + local _env=() + while read _line; do + _env+=("$_line") + done < <(printenv | grep -Eo "^DOCKER_FINANCE[^=]+") + + # Reset environment + for _line in "${_env[@]}"; do + lib_utils::print_debug "Unsetting $_line" + unset "$_line" + done + + # Set, if a script that generates env + if [[ "$(head -n1 $_file)" =~ (bin|env|sh|bash) ]]; then + # shellcheck source=/dev/null + source "$global_repo_env_file" + return $? + fi + + # Set, if env file format (docker / bash) + while read _line; do + # Ignore comments + if [[ ! "$_line" =~ ^# ]]; then + # Don't allow manipulating version via file + if [[ "$_line" =~ ^DOCKER_FINANCE_VERSION ]]; then + continue + fi + # Export valid line + export "${_line?}" # SC2163 + lib_utils::print_debug "$_line" + fi + done <"$_file" +} + +# +# Write client-side environment to given file +# + +function lib_env::__write() +{ + lib_utils::print_debug "Writing environment" + + unset DOCKER_FINANCE_VERSION # Must be generated internally + printenv | grep -E "DOCKER_FINANCE" | sort >"$1" +} + +# vim: sw=2 sts=2 si ai et diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index 4502581..ce3afae 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -23,305 +23,21 @@ # "Libraries" # +# Runtime environment handler +source "${DOCKER_FINANCE_CLIENT_REPO}/client/src/docker/lib/internal/lib_env.bash" || exit 1 + +# Utilities (a container library (but container is never exposed to client code)) source "${DOCKER_FINANCE_CLIENT_REPO}/container/src/finance/lib/internal/lib_utils.bash" || exit 1 # # Implementation # -if [ $UID -lt 1000 ]; then - lib_utils::die_fatal "Do not run as root or system user!" -fi - -# IMPORTANT: keep umask for security -umask o-rwx - -if ! docker compose version 1>/dev/null; then - lib_utils::die_fatal "Docker compose plugin not installed" -fi - -if [ -z "$EDITOR" ]; then - editors=("vim" "vi" "emacs" "nano") - for editor in "${editors[@]}"; do - hash "$editor" &>/dev/null && export EDITOR="$editor" && break - done - if [ $? -ne 0 ]; then - lib_utils::die_fatal "Shell EDITOR is not set, export EDITOR in your shell" - fi -fi - # -# "Constructor" for environment generation -# -# 1. Sets client-side environment with defaults or use existing environment -# 2. If configured, resets to alternative environment configuration after bootstrap -# -# NOTE: some bootstrapped defaults are ignored by environment file (as seen below) +# Generate new configurations or layout # function lib_gen::gen() -{ - [ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && lib_utils::die_fatal - - # NOTE: global_* *MUST* be reset after sourcing new env file - - # - # Generate `docker-finance` version - # - - global_repo_manifest="${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.yaml" - declare -g global_repo_manifest - - global_client_version="$(grep '^version: ' $global_repo_manifest | sed -e 's/version: "//' -e 's/"//g')" - # shellcheck disable=SC2034 # used during env gen - declare -g global_client_version - - # - # If empty environment: - # - # 1. Poke at possible (default) location of end-user environment file - # a. If found, point to new location and read/reset from there - # - # 2. If file not found, bootstrap with defaults - # - - # Environment (end-user) - global_conf_filename="${USER}@$(uname -n)" - declare -g global_conf_filename - - # Environment (end-user) tag dir (not full path) - [ -z "$global_tag" ] && lib_utils::die_fatal - global_tag_dir="client/$(uname -s)-$(uname -m)/${global_platform}/${global_tag}" - declare -g global_tag_dir - - local _env_dir="/home/${USER}/.config/docker-finance.d/${global_tag_dir}/env" # NOTE: keep aligned with gen.bash - local _env_file="${_env_dir}/${global_conf_filename}" - - # shellcheck source=/dev/null - [ -f "$_env_file" ] && source "$_env_file" - - if [ -z "$DOCKER_FINANCE_CLIENT_CONF" ]; then - # shellcheck source=/dev/null - source "${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.d/client/env/gen.bash" - fi - - [ -z "$DOCKER_FINANCE_CLIENT_CONF" ] \ - && lib_utils::die_fatal "Defaults not generated! (${global_repo_env_file})" - - lib_gen::__set_client_globals - - # - # Reset environment with user-provided (user-defined) existing file (if available) - # - - _env_dir="${DOCKER_FINANCE_CLIENT_CONF}/${global_tag_dir}/env" - _env_file="${_env_dir}/${global_conf_filename}" - - if [ -f "$_env_file" ]; then - if [ -s "$_env_file" ]; then - # Re-bootstrap with (new) environment - lib_utils::print_debug "Environment found! Using '${_env_file}'" - lib_gen::__read_env "$_env_file" - lib_gen::__set_client_globals - else - lib_utils::print_warning \ - "Client environment '${_env_file}' is empty! Writing defaults" - lib_gen::__write_env "$_env_file" - fi - else - [ -z "$global_command" ] && lib_utils::die_fatal - [ -z "$global_basename" ] && lib_utils::die_fatal - - if [[ -z "$global_command" || "$global_command" != "gen" ]]; then - lib_utils::die_fatal \ - "Client environment not found! Run gen command'" - fi - - lib_utils::print_info \ - "Client environment not found, writing defaults to '${_env_file}'" - lib_gen::__write_env "$_env_file" - fi -} - -# -# Set client globals from environment -# - -function lib_gen::__set_client_globals() -{ - lib_utils::print_debug "Setting (or resetting) client globals" - - # - # Repository env - # - - [ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && lib_utils::die_fatal - - # Generate `docker-finance` version - global_repo_manifest="${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.yaml" - declare -g global_repo_manifest - lib_utils::print_debug "global_repo_manifest=${global_repo_manifest}" - - global_client_version="$(grep '^version: ' $global_repo_manifest | sed -e 's/version: "//' -e 's/"//g')" - # shellcheck disable=SC2034 # used during env gen - declare -g global_client_version - lib_utils::print_debug "global_client_version=${global_client_version}" - - # This does not reset when reading env; export again - export DOCKER_FINANCE_VERSION="$global_client_version" - lib_utils::print_debug "DOCKER_FINANCE_VERSION=${DOCKER_FINANCE_VERSION}" - - # Repository-provided (not user-defined) default environment - global_repo_conf_dir="${DOCKER_FINANCE_CLIENT_REPO}/client/docker-finance.d" - declare -g global_repo_conf_dir - lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" - - # Environment (repo) - declare -g global_repo_env_file="${global_repo_conf_dir}/client/env/gen.bash" - [ ! -f "$global_repo_env_file" ] \ - && lib_utils::die_fatal "Missing environment defaults! ($global_repo_env_file)" - lib_utils::print_debug "global_repo_env_file=${global_repo_env_file}" - - # - # Repository env (Dockerfiles) - # - - # Set image type - [ -z "$global_platform" ] && lib_utils::die_fatal - case "$global_platform" in - archlinux | ubuntu) - global_platform_image="finance" - ;; - dev-tools) - global_platform_image="dev-tools" - ;; - *) - lib_utils::die_fatal "unsupported platform" - ;; - esac - declare -g global_platform_image - lib_utils::print_debug "global_platform_image=${global_platform_image}" - - # Base location of Docker-related files (.in and final out files) - global_repo_dockerfiles="${DOCKER_FINANCE_CLIENT_REPO}/client/Dockerfiles/local/${global_platform_image}" - # shellcheck disable=SC2034 # used in lib_docker - declare -g global_repo_dockerfiles - lib_utils::print_debug "global_repo_dockerfiles=${global_repo_dockerfiles}" - - # Base custom end-user .in Dockerfile (to be appended to final Dockerfile after installation) - declare -g global_repo_custom_dockerfile="${global_repo_conf_dir}/client/Dockerfiles/${global_platform_image}/Dockerfile.${global_platform}.in" - [ ! -f "$global_repo_custom_dockerfile" ] \ - && lib_utils::die_fatal "Missing default custom Dockerfile '${global_repo_custom_dockerfile}'" - lib_utils::print_debug "global_repo_custom_dockerfile=${global_repo_custom_dockerfile}" - - # - # Client-side env - # - - [ -z "$global_tag_dir" ] && lib_utils::die_fatal - - # Environment (end-user) format - [ -z "$DOCKER_FINANCE_USER" ] && lib_utils::die_fatal - global_conf_filename="${DOCKER_FINANCE_USER}@$(uname -n)" - declare -g global_conf_filename - lib_utils::print_debug "global_conf_filename=${global_conf_filename}" - - # Environment file (if available) - local _client_env_dir="${DOCKER_FINANCE_CLIENT_CONF}/${global_tag_dir}/env" - [ ! -d "$_client_env_dir" ] && mkdir -p "$_client_env_dir" - global_env_file="${_client_env_dir}/${global_conf_filename}" - lib_utils::print_debug "global_env_file=${global_env_file}" - - # Custom Dockerfile (if available) - local _client_dockerfile_dir="${DOCKER_FINANCE_CLIENT_CONF}/${global_tag_dir}/Dockerfiles" - [ ! -d "$_client_dockerfile_dir" ] && mkdir -p "$_client_dockerfile_dir" - global_custom_dockerfile="${_client_dockerfile_dir}/${global_conf_filename}" - lib_utils::print_debug "global_custom_dockerfile=${global_custom_dockerfile}" - - # NOTE: - # - # Client env tag format is avoided because: - # - # - We copy over static bash_aliases in Dockerfile, - # and superscript must be referenced by that static path - # - # - The needed dynamicness appears to not be satisfied via docker-compose - - local _client_shell_dir="${DOCKER_FINANCE_CLIENT_CONF}/container/shell" - [ ! -d "$_client_shell_dir" ] && mkdir -p "$_client_shell_dir" - global_shell_file="${_client_shell_dir}/superscript.bash" - lib_utils::print_debug "global_shell_file=${global_shell_file}" - - # Client view of client portion of repository - global_repo_client="${DOCKER_FINANCE_CLIENT_REPO}/client" - [ ! -d "$global_repo_client" ] && lib_utils::die_fatal "Repository '${global_repo_client}' not found!" - lib_utils::print_debug "global_repo_client=${global_repo_client}" - - # Backup-file extension - # TODO: make configurable - global_suffix="$(date +%Y-%m-%d_%H:%M:%S)" - lib_utils::print_debug "global_suffix=${global_suffix}" -} - -# -# Get/Set client-side environment with given file -# - -function lib_gen::__read_env() -{ - local _file="$1" - - # Get environment - local _env=() - while read _line; do - _env+=("$_line") - done < <(printenv | grep -Eo "^DOCKER_FINANCE[^=]+") - - # Reset environment - for _line in "${_env[@]}"; do - lib_utils::print_debug "Unsetting $_line" - unset "$_line" - done - - # Set, if a script that generates env - if [[ "$(head -n1 $_file)" =~ (bin|env|sh|bash) ]]; then - # shellcheck source=/dev/null - source "$global_repo_env_file" - return $? - fi - - # Set, if env file format (docker / bash) - while read _line; do - # Ignore comments - if [[ ! "$_line" =~ ^# ]]; then - # Don't allow manipulating version via file - if [[ "$_line" =~ ^DOCKER_FINANCE_VERSION ]]; then - continue - fi - # Export valid line - export "${_line?}" # SC2163 - lib_utils::print_debug "$_line" - fi - done <"$_file" -} - -# -# Write client-side environment to given file -# - -function lib_gen::__write_env() -{ - lib_utils::print_debug "Writing environment" - - unset DOCKER_FINANCE_VERSION # Must be generated internally - printenv | grep -E "DOCKER_FINANCE" | sort >"$1" -} - -# -# Generate new configurations -# - -function lib_gen::generate() { lib_utils::print_custom "\n" lib_utils::print_info "Generating client/container environment" @@ -330,6 +46,7 @@ function lib_gen::generate() lib_gen::__gen_client if [ $? -eq 0 ]; then + [ -z "$global_platform" ] && lib_utils::die_fatal if [ "$global_platform" != "dev-tools" ]; then lib_gen::__gen_container fi @@ -345,11 +62,18 @@ function lib_gen::generate() function lib_gen::__gen_client() { + [ -z "$global_suffix" ] && lib_utils::die_fatal + [ -z "$EDITOR" ] && lib_utils::die_fatal + lib_utils::print_debug "Generating client" # # Client-side environment file # + # + + [ -z "$global_env_file" ] && lib_utils::die_fatal + [ -z "$global_repo_env_file" ] && lib_utils::die_fatal # Backup existing file if [ -f "$global_env_file" ]; then @@ -365,10 +89,10 @@ function lib_gen::__gen_client() # Get/Set with repository defaults lib_utils::print_debug "Reading $global_repo_env_file" - lib_gen::__read_env "$global_repo_env_file" + lib_env::__read "$global_repo_env_file" lib_utils::print_debug "Writing $global_env_file" - lib_gen::__write_env "$global_env_file" + lib_env::__write "$global_env_file" fi fi @@ -378,13 +102,16 @@ function lib_gen::__gen_client() [[ "$_confirm" == [yY] ]] && $EDITOR "$global_env_file" # Get/Set new (edited) environment variables - lib_gen::__read_env "$global_env_file" - lib_gen::__set_client_globals + lib_env::__read "$global_env_file" + lib_env::__set_client_globals # # Custom (optional) Dockerfile # + [ -z "$global_custom_dockerfile" ] && lib_utils::die_fatal + [ -z "$global_repo_custom_dockerfile" ] && lib_utils::die_fatal + # Backup existing custom Dockerfile if [ -f "$global_custom_dockerfile" ]; then lib_utils::print_custom " \e[32m│\e[0m\n" @@ -601,6 +328,8 @@ function lib_gen::__gen_profile() function lib_gen::__gen_subprofile_shell() { + [ -z "$global_shell_file" ] && lib_utils::die_fatal + local -r _gen_path="$1" local -r _gen_conf_path="$2" diff --git a/client/src/docker/lib/lib_docker.bash b/client/src/docker/lib/lib_docker.bash index 0212788..35c2fe9 100644 --- a/client/src/docker/lib/lib_docker.bash +++ b/client/src/docker/lib/lib_docker.bash @@ -26,7 +26,10 @@ # Docker impl source "${DOCKER_FINANCE_CLIENT_REPO}/client/src/docker/lib/internal/lib_docker.bash" || exit 1 -# Environment generation +# Runtime environment handler +source "${DOCKER_FINANCE_CLIENT_REPO}/client/src/docker/lib/internal/lib_env.bash" || exit 1 + +# Environment layout generator source "${DOCKER_FINANCE_CLIENT_REPO}/client/src/docker/lib/internal/lib_gen.bash" || exit 1 # Plugins support @@ -114,8 +117,8 @@ function lib_docker::docker() declare -gxr global_usage="$global_basename ${global_platform}${global_arg_delim_1}${global_user}:${global_tag} $global_command" lib_utils::print_debug "global_usage=${global_usage}" - # Setup remaining client/container globals - lib_gen::gen || return $? + # Setup remaining environment globals + lib_env::env || return $? # Remaining "constructor" implementation lib_docker::__docker || return $? @@ -129,7 +132,7 @@ function lib_docker::docker() function lib_docker::gen() { - lib_gen::generate + lib_gen::gen lib_utils::catch $? } From c3cf81572bba2ef17273d31f8bac61e98019fb6d Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:33:10 -0700 Subject: [PATCH 02/13] client: src: refactor system checks - UID and dependency checks are done in internal `lib_docker`/`lib_env` - Moves `sed` check to appropriate `lib_env` --- client/src/docker/lib/internal/lib_env.bash | 18 ++++-------------- client/src/docker/lib/lib_docker.bash | 8 -------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/client/src/docker/lib/internal/lib_env.bash b/client/src/docker/lib/internal/lib_env.bash index 70120c2..ef09ad2 100644 --- a/client/src/docker/lib/internal/lib_env.bash +++ b/client/src/docker/lib/internal/lib_env.bash @@ -34,23 +34,13 @@ if [ $UID -lt 1000 ]; then lib_utils::die_fatal "Do not run as root or system user!" fi +# Dependencies +deps=("sed") +lib_utils::deps_check "${deps[@]}" + # IMPORTANT: keep umask for security umask o-rwx -if ! docker compose version 1>/dev/null; then - lib_utils::die_fatal "Docker compose plugin not installed" -fi - -if [ -z "$EDITOR" ]; then - editors=("vim" "vi" "emacs" "nano") - for editor in "${editors[@]}"; do - hash "$editor" &>/dev/null && export EDITOR="$editor" && break - done - if [ $? -ne 0 ]; then - lib_utils::die_fatal "Shell EDITOR is not set, export EDITOR in your shell" - fi -fi - # # "Constructor" for environment generation # diff --git a/client/src/docker/lib/lib_docker.bash b/client/src/docker/lib/lib_docker.bash index 35c2fe9..5b783e1 100644 --- a/client/src/docker/lib/lib_docker.bash +++ b/client/src/docker/lib/lib_docker.bash @@ -47,14 +47,6 @@ source "${DOCKER_FINANCE_CLIENT_REPO}/container/src/finance/lib/internal/lib_uti # Implementation # -if [ $UID -lt 1000 ]; then - lib_utils::die_fatal "Do not run as root or system user!" -fi - -# Dependencies -deps=("sed") -lib_utils::deps_check "${deps[@]}" - # Top-level caller global_basename="$(basename -- $0)" declare -rx global_basename From 9f6ad1911255cb227402262b2e74b6f17288d893 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:33:48 -0700 Subject: [PATCH 03/13] client: src: lib_gen: move hledger conf to subprofile gen Subprofile's hledger conf should be within subprofile generation. --- client/src/docker/lib/internal/lib_gen.bash | 121 +++++++++----------- 1 file changed, 57 insertions(+), 64 deletions(-) diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index ce3afae..eb5934d 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -294,19 +294,6 @@ function lib_gen::__gen_profile() lib_gen::__gen_subprofile_shell "$_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) hledger configuration file? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then - local _gen_path="${_profiles}/${_profile}/${_subprofile}" # client's view - 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_subprofile_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 flow configs and/or accounts? [Y/n] \e[0m" read -p "" _read @@ -383,57 +370,6 @@ function lib_gen::__gen_subprofile_shell_write() "${global_repo_conf_dir}/container/shell/superscript.bash.in" >"$_file" } -# -# Subprofile: generate hledger configuration file -# - -function lib_gen::__gen_subprofile_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_subprofile_hledger_write "$_file" - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" - fi - else - lib_gen::__gen_subprofile_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_subprofile_hledger_write() -{ - local _file="$1" - [ -z "$_file" ] && lib_utils::die_fatal - - [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal - lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" - - [ -z "$global_client_version" ] && lib_utils::die_fatal - lib_utils::print_debug "global_client_version=${global_client_version}" - - sed \ - -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ - "${global_repo_conf_dir}/container/hledger/hledger.conf.in" >"$_file" -} - # # Subprofile: generate flow # @@ -461,6 +397,12 @@ function lib_gen::__gen_subprofile_flow() _confirm="${_read:-y}" [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_flow_meta + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger configuration file? [Y/n] \e[0m" + read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_hledger "$_gen_path" "$_gen_conf_path" + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger-flow accounts? [Y/n] \e[0m" read -p "" _read @@ -615,6 +557,57 @@ function lib_gen::__gen_subprofile_flow_meta_write() "${global_repo_conf_dir}/container/meta/meta.csv.in" >"$_file" } +# +# Subprofile: flow: generate hledger configuration file +# + +function lib_gen::__gen_subprofile_flow_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_subprofile_hledger_write "$_file" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" + fi + else + lib_gen::__gen_subprofile_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_subprofile_flow_hledger_write() +{ + local _file="$1" + [ -z "$_file" ] && lib_utils::die_fatal + + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal + lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" + + [ -z "$global_client_version" ] && lib_utils::die_fatal + lib_utils::print_debug "global_client_version=${global_client_version}" + + sed \ + -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ + "${global_repo_conf_dir}/container/hledger/hledger.conf.in" >"$_file" +} + # # Subprofile: flow: generate accounts # From e8509384d22a125ddffe075885acb4b9a3c217f0 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:34:19 -0700 Subject: [PATCH 04/13] 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 --- client/src/docker/lib/internal/lib_gen.bash | 331 ++++++++++++++++++++ client/src/docker/lib/lib_docker.bash | 2 +- 2 files changed, 332 insertions(+), 1 deletion(-) 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 $? } From f96dae021077a56a49e9e328fbdb986d22485798 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:34:43 -0700 Subject: [PATCH 05/13] client: src: lib_gen: impl overhaul for new args - Rewrite to support new arguments * Related design changes and refactoring * Remove prompt for testing (use `dev=on` instead) - Factor out superscript gen from subscript append - Related print formatting changes - Add more internal checks --- .../container/shell/superscript.bash.in | 1 + client/src/docker/lib/internal/lib_gen.bash | 618 ++++++++++-------- 2 files changed, 359 insertions(+), 260 deletions(-) diff --git a/client/docker-finance.d/container/shell/superscript.bash.in b/client/docker-finance.d/container/shell/superscript.bash.in index 734e3c3..482c8a8 100644 --- a/client/docker-finance.d/container/shell/superscript.bash.in +++ b/client/docker-finance.d/container/shell/superscript.bash.in @@ -41,6 +41,7 @@ alias e='exit' alias grep='grep --color=auto' # All subprofiles' scripts +# TODO: remove this tag as it's no longer needed @DOCKER_FINANCE_SUBPROFILE_SOURCE@ # vim: syn=bash sw=2 sts=2 si ai et diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index afcd128..4f7f4ef 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -372,8 +372,6 @@ function lib_gen::gen() 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 if [ $? -eq 0 ]; then @@ -384,10 +382,13 @@ function lib_gen::gen() fi if [ $? -eq 0 ]; then + lib_utils::print_custom "\n" lib_utils::print_info "Congratulations, environment sucessfully generated!" lib_utils::print_custom "\n" else + lib_utils::print_custom "\n" lib_utils::die_fatal "Environment not fully generated! Try again" + lib_utils::print_custom "\n" fi } @@ -401,79 +402,103 @@ function lib_gen::__gen_client() # # Client-side environment file # - # - [ -z "$global_env_file" ] && lib_utils::die_fatal - [ -z "$global_repo_env_file" ] && lib_utils::die_fatal + if [[ -z "${global_arg_type[*]}" || "${global_arg_type[*]}" =~ env ]]; then - # Backup existing file - if [ -f "$global_env_file" ]; then - lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Client-side environment found, backup then generate new one? [Y/n] \e[0m" + [ -z "$global_env_file" ] && lib_utils::die_fatal + [ -z "$global_repo_env_file" ] && lib_utils::die_fatal - read -p "" _read - local _confirm="${_read:-y}" + # Backup existing file + if [ -f "$global_env_file" ]; then + lib_utils::print_custom " \e[32m│\e[0m\n" + lib_utils::print_custom " \e[32m├─\e[34;1m Client-side environment found, backup then generate new one? [Y/n] \e[0m" - if [[ "$_confirm" == [yY] ]]; then - cp -a "$global_env_file" "${global_env_file}_${global_suffix}" \ - || lib_utils::die_fatal + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-y}" - # Get/Set with repository defaults - lib_utils::print_debug "Reading $global_repo_env_file" - lib_env::__read "$global_repo_env_file" + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then + cp -a "$global_env_file" "${global_env_file}_${global_suffix}" \ + || lib_utils::die_fatal - lib_utils::print_debug "Writing $global_env_file" - lib_env::__write "$global_env_file" + # Get/Set with repository defaults + lib_utils::print_debug "Reading $global_repo_env_file" + lib_env::__read "$global_repo_env_file" + + lib_utils::print_debug "Writing $global_env_file" + lib_env::__write "$global_env_file" + fi fi + + lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) environment now? [Y/n] \e[0m" + + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_env_file" + + # Get/Set new (edited) environment variables + lib_env::__read "$global_env_file" + lib_env::__set_client_globals + fi - lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) environment now? [Y/n] \e[0m" - read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$global_env_file" - - # Get/Set new (edited) environment variables - lib_env::__read "$global_env_file" - lib_env::__set_client_globals - # # Custom (optional) Dockerfile # - [ -z "$global_custom_dockerfile" ] && lib_utils::die_fatal - [ -z "$global_repo_custom_dockerfile" ] && lib_utils::die_fatal + if [[ -z "${global_arg_type[*]}" || "${global_arg_type[*]}" =~ build ]]; then - # Backup existing custom Dockerfile - if [ -f "$global_custom_dockerfile" ]; then - lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Custom (optional) Dockerfile found, backup then generate new one? [Y/n] \e[0m" + [ -z "$global_custom_dockerfile" ] && lib_utils::die_fatal + [ -z "$global_repo_custom_dockerfile" ] && lib_utils::die_fatal - read -p "" _read - local _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then - cp -a "$global_custom_dockerfile" "${global_custom_dockerfile}_${global_suffix}" || lib_utils::die_fatal - cp -fa "$global_repo_custom_dockerfile" "$global_custom_dockerfile" || lib_utils::die_fatal + # Backup existing custom Dockerfile + if [ -f "$global_custom_dockerfile" ]; then + lib_utils::print_custom " \e[32m│\e[0m\n" + lib_utils::print_custom " \e[32m├─\e[34;1m Custom (optional) Dockerfile found, backup then generate new one? [Y/n] \e[0m" + + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-y}" + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then + cp -a "$global_custom_dockerfile" "${global_custom_dockerfile}_${global_suffix}" || lib_utils::die_fatal + cp -fa "$global_repo_custom_dockerfile" "$global_custom_dockerfile" || lib_utils::die_fatal + fi + else + lib_utils::print_custom " \e[32m│\e[0m\n" + lib_utils::print_custom " \e[32m├─\e[34;1m Generating new custom (optional) Dockerfile\e[0m\n" + + lib_utils::print_debug "$global_repo_custom_dockerfile" + lib_utils::print_debug "$global_custom_dockerfile" + + cp -a "$global_repo_custom_dockerfile" "$global_custom_dockerfile" fi - else - lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Generating new custom (optional) Dockerfile\e[0m\n" - lib_utils::print_debug "$global_repo_custom_dockerfile" - lib_utils::print_debug "$global_custom_dockerfile" + lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) custom Dockerfile now? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_custom_dockerfile" || return 0 - cp -a "$global_repo_custom_dockerfile" "$global_custom_dockerfile" fi - - lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) custom Dockerfile now? [Y/n] \e[0m" - read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$global_custom_dockerfile" || return 0 } function lib_gen::__gen_container() { lib_utils::print_debug "Generating container" + # + # Generate joint client/container superscript + # + + if [[ -z "${global_arg_type[*]}" || "${global_arg_type[*]}" =~ superscript ]]; then + + lib_utils::print_custom " \e[32m│\e[0m\n" + lib_utils::print_custom " \e[32m├─\e[34;1m Generate (or update) joint client/container superscript? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then + lib_gen::__gen_superscript + fi + + fi + # # Generate plugins (custom) # @@ -489,23 +514,84 @@ function lib_gen::__gen_container() # Generate flow # - lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Generate (or update) container flow (profiles, etc.)? [Y/n] \e[0m" - read -p "" _read - local _confirm="${_read:-y}" - if [[ "$_confirm" != [yY] ]]; then + if [[ "${global_arg_all[*]}" =~ all|type || "${global_arg_type[*]}" =~ flow ]]; then + lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_normal "" - return 0 - fi + lib_utils::print_custom " \e[32m├─\e[34;1m Generate (or update) container finance flow (layout and profiles)? [Y/n] \e[0m" + # Prompt if type not given + if [[ ! "${global_arg_all[*]}" =~ all|type || -z "${global_arg_type[*]}" ]]; then + if [ -z "$global_arg_confirm" ]; then + lib_utils::print_custom "\n" + else + read -p "" _read + local _confirm="${_read:-y}" + if [[ "$_confirm" != [yY] ]]; then + lib_utils::print_custom " \e[32m│\e[0m\n" + return 0 + fi + fi + fi - [ -z "$DOCKER_FINANCE_CLIENT_FLOW" ] && lib_utils::die_fatal - if [ ! -d "$DOCKER_FINANCE_CLIENT_FLOW" ]; then - mkdir -p "$DOCKER_FINANCE_CLIENT_FLOW" || lib_utils::die_fatal - fi + [ -z "$DOCKER_FINANCE_CLIENT_FLOW" ] && lib_utils::die_fatal + if [ ! -d "$DOCKER_FINANCE_CLIENT_FLOW" ]; then + mkdir -p "$DOCKER_FINANCE_CLIENT_FLOW" || lib_utils::die_fatal + fi - lib_gen::__gen_times - lib_gen::__gen_profile + lib_gen::__gen_times + lib_gen::__gen_profile + + fi +} + +# +# Generate joint client/container superscript +# + +function lib_gen::__gen_superscript() +{ + [ -z "$global_shell_file" ] && lib_utils::die_fatal + + if [ -f "$global_shell_file" ]; then + lib_utils::print_custom " \e[32m│ └─\e[34m Backup existing superscript and generate a new one? [N/y] \e[0m" + + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-n}" + + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then + # Backup + local -r _backup=("cp" "-a" "$global_shell_file" "${global_shell_file}_${global_suffix}") + lib_utils::print_debug "${_backup[@]}" + "${_backup[@]}" || lib_utils::die_fatal + # Write + lib_gen::__gen_superscript_write + fi + local _print_custom=" \e[32m│ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" + else + # Generate new default file + lib_gen::__gen_superscript_write + local _print_custom=" \e[32m│ │ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" + fi + lib_utils::print_custom "$_print_custom" + + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_shell_file" +} + +function lib_gen::__gen_superscript_write() +{ + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal + lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" + + [ -z "$global_client_version" ] && lib_utils::die_fatal + lib_utils::print_debug "global_client_version=${global_client_version}" + + [ -z "$global_shell_file" ] && lib_utils::die_fatal + lib_utils::print_debug "global_shell_file=${global_shell_file}" + + sed \ + -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ + "${global_repo_conf_dir}/container/shell/superscript.bash.in" >"$global_shell_file" } # @@ -518,6 +604,8 @@ function lib_gen::__gen_container() function lib_gen::__gen_plugins() { + [ -z "$DOCKER_FINANCE_CLIENT_PLUGINS" ] && lib_utils::die_fatal + lib_utils::print_debug "Generating custom plugins layout" local -r _client="${DOCKER_FINANCE_CLIENT_PLUGINS}/client" @@ -567,39 +655,56 @@ function lib_gen::__gen_profile() mkdir -p "$_profiles" || lib_utils::die_fatal fi - # - # Profile: development setup - # - - lib_utils::print_custom " \e[32m│ │\e[0m\n" - lib_utils::print_custom " \e[32m│ ├─\e[34;1m Will this profile be used for development and/or demonstration? [N/y] \e[0m" - read -p "" _read - local _is_testing="${_read:-false}" - if [[ "$_read" == [yY] ]]; then - _is_testing=true - fi - lib_utils::print_debug "_is_testing=${_is_testing}" - # # Profile: construct full path to subprofile # + [ -z "$global_user" ] && lib_utils::die_fatal + + # Profile lib_utils::print_custom " \e[32m│ │ │\e[0m\n" lib_utils::print_custom " \e[32m│ │ ├─\e[34m Enter profile name (e.g., family in 'family/alice'): \e[0m" - read -p "" _read + if [ ! -z "$global_arg_profile" ]; then + lib_utils::print_custom "\n" + _read="$global_arg_profile" + else + if [ -z "$global_arg_confirm" ]; then + lib_utils::print_custom "\n" + _read="" + else + read -p "" _read + fi + fi local -r _profile="${_read:-default}" lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Using profile:\e[0m ${_profile}\n" + # Subprofile lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ └─\e[34m Enter subprofile name (e.g., alice in 'family/alice'): \e[0m" - read -p "" _read + lib_utils::print_custom " \e[32m│ │ ├─\e[34m Enter subprofile name (e.g., alice in 'family/alice'): \e[0m" + if [ ! -z "$global_arg_subprofile" ]; then + lib_utils::print_custom "\n" + _read="$global_arg_subprofile" + else + if [ -z "$global_arg_confirm" ]; then + lib_utils::print_custom "\n" + _read="" + else + read -p "" _read + fi + fi local -r _subprofile="${_read:-${global_user}}" - lib_utils::print_custom " \e[32m│ │ └─\e[34m Using subprofile:\e[0m ${_subprofile}\n" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Using subprofile:\e[0m ${_subprofile}\n" + # Check if full profile exists if [ -d "${_profiles}/${_profile}/${_subprofile}" ]; then - lib_utils::print_custom " \e[32m│ │ └─\e[34m Subprofile exists! Continue with backup and generation? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile exists! Continue with backup and generation? [Y/n] \e[0m" - read -p "" _read + if [ -z "$global_arg_confirm" ]; then + lib_utils::print_custom "\n" + _read="" + else + read -p "" _read + fi _confirm="${_read:-y}" if [[ "$_confirm" != [yY] ]]; then lib_utils::print_custom " \e[32m│\e[0m\n" @@ -609,96 +714,16 @@ function lib_gen::__gen_profile() fi # - # Profile: execute profile-specific + # Profile: generate profile-specific # - lib_utils::print_custom " \e[32m│ │\e[0m\n" - lib_utils::print_custom " \e[32m│ ├─\e[34;1m Generate (or update) joint client/container shell script (superscript)? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then - local _gen_path="\${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/${_profile}/${_subprofile}" # \$ for container view - 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}" + local -r _gen_path="${_profiles}/${_profile}/${_subprofile}" + lib_utils::print_debug "_gen_path=${_gen_path}" - lib_gen::__gen_subprofile_shell "$_gen_path" "$_gen_conf_path" - fi + local -r _gen_conf_path="${_gen_path}/docker-finance.d" + lib_utils::print_debug "_gen_conf_path=${_gen_conf_path}" - lib_utils::print_custom " \e[32m│ │\e[0m\n" - lib_utils::print_custom " \e[32m│ ├─\e[34;1m Generate (or update) container flow configs and/or accounts? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then - local _gen_path="${_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_subprofile_flow "$_gen_path" "$_gen_conf_path" - fi -} - -# -# Subprofile: generate client-side container superscript -# TODO: separate superscript gen from subprofile append -# - -function lib_gen::__gen_subprofile_shell() -{ - [ -z "$global_shell_file" ] && lib_utils::die_fatal - - local -r _gen_path="$1" - local -r _gen_conf_path="$2" - - # Subprofile source added to superscript - local -r _source="source \"${_gen_conf_path}/shell/subprofile.bash\"" - - local _file="$global_shell_file" - if [ -f "$_file" ]; then - # Append subprofile source to existing file - lib_utils::print_custom " \e[32m│ │ └─\e[34m Shell superscript found, append new subprofile to existing file? [Y/n] \e[0m" - read -p "" _read - local _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then - grep "$_source" "$_file" >&/dev/null || sed -i "$(wc -l <$_file)i\\$_source\\" "$_file" - fi - # Or generate new file - lib_utils::print_custom " \e[32m│ │ └─\e[34m Backup existing superscript and generate a new one? [N/y] \e[0m" - read -p "" _read - local _confirm="${_read:-n}" - if [[ "$_confirm" == [yY] ]]; then - # Backup - local -r _backup=("cp" "-a" "$_file" "${_file}_${global_suffix}") - lib_utils::print_debug "${_backup[@]}" - "${_backup[@]}" || lib_utils::die_fatal - # Write - lib_gen::__gen_subprofile_shell_write - fi - local _print_custom=" \e[32m│ │ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" - else - # Generate new default file - lib_gen::__gen_subprofile_shell_write - local _print_custom=" \e[32m│ │ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" - fi - lib_utils::print_custom "$_print_custom" - read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" -} - -function lib_gen::__gen_subprofile_shell_write() -{ - [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal - lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" - - [ -z "$global_client_version" ] && lib_utils::die_fatal - lib_utils::print_debug "global_client_version=${global_client_version}" - - sed \ - -e "s:@DOCKER_FINANCE_SUBPROFILE_SOURCE@:${_source}:g" \ - -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ - "${global_repo_conf_dir}/container/shell/superscript.bash.in" >"$_file" + lib_gen::__gen_subprofile_flow } # @@ -707,38 +732,58 @@ function lib_gen::__gen_subprofile_shell_write() function lib_gen::__gen_subprofile_flow() { - local -r _gen_path="$1" - local -r _gen_conf_path="$2" + [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal - lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's shell script? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_flow_shell + if lib_gen::__gen_subprofile_flow_args_config "subprofile"; then + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's shell script? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then + # Subprofile's shell script + lib_gen::__gen_subprofile_flow_shell + # Append subprofile source to superscript + lib_gen::__gen_subprofile_flow_superscript + fi + fi - lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's fetch configuration? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_flow_fetch + if lib_gen::__gen_subprofile_flow_args_config "fetch"; then + # Prompt for default generation + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's fetch configuration file? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_fetch + fi - lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's financial metadata? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_flow_meta + if lib_gen::__gen_subprofile_flow_args_config "meta"; then + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's financial metadata file? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_meta + fi - lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger configuration file? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_hledger "$_gen_path" "$_gen_conf_path" + if lib_gen::__gen_subprofile_flow_args_config "hledger"; then + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger configuration file? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_hledger + fi - lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger-flow accounts? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && lib_gen::__gen_subprofile_flow_accounts + if lib_gen::__gen_subprofile_flow_args_account; then + lib_utils::print_custom " \e[32m│ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger-flow accounts? [Y/n] \e[0m" + if [ ! -z "${global_arg_account[*]}" ]; then + lib_utils::print_custom "\n" + lib_gen::__gen_subprofile_flow_accounts + else + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_accounts + fi + fi lib_utils::print_custom " \e[32m│\e[0m\n" @@ -752,22 +797,41 @@ function lib_gen::__gen_subprofile_flow() lib_utils::print_custom " \e[32m│\e[0m\n" } +function lib_gen::__gen_subprofile_flow_args_config() +{ + [ -z "$1" ] && lib_utils::die_fatal + if [[ -z "${global_arg_type[*]}" || ("${global_arg_type[*]}" =~ flow && -z "$global_arg_profile") || ("${global_arg_type[*]}" =~ flow && ! -z "$global_arg_profile" && -z "${global_arg_account[*]}" && -z "${global_arg_config[*]}") || "${global_arg_config[*]}" =~ $1 ]]; then + return 0 + fi + return 1 +} + +function lib_gen::__gen_subprofile_flow_args_account() +{ + if [[ -z "${global_arg_type[*]}" || ("${global_arg_type[*]}" =~ flow && -z "$global_arg_profile") || ("${global_arg_type[*]}" =~ flow && ! -z "$global_arg_profile" && -z "${global_arg_account[*]}" && -z "${global_arg_config[*]}") || ("${global_arg_type[*]}" =~ flow && ! -z "$global_arg_profile" && ! -z "${global_arg_account[*]}") ]]; then + return 0 + fi + return 1 +} + # # Subprofile: flow: generate subprofile script # function lib_gen::__gen_subprofile_flow_shell() { + [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal + local _dir="${_gen_conf_path}/shell" [ ! -d "$_dir" ] && mkdir -p "$_dir" local _file="${_dir}/subprofile.bash" if [ -f "$_file" ]; then lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile script found, backup then generate new one? [Y/n] \e[0m" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_shell_write @@ -779,14 +843,20 @@ function lib_gen::__gen_subprofile_flow_shell() fi lib_utils::print_custom "$_print_custom" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" } function lib_gen::__gen_subprofile_flow_shell_write() { - [ -z "$DOCKER_FINANCE_CONTAINER_CMD" ] && lib_utils::die_fatal + [[ -z "$DOCKER_FINANCE_CONTAINER_REPO" || -z "$DOCKER_FINANCE_CONTAINER_CMD" ]] && lib_utils::die_fatal + + [[ -z "$_profile" || -z "$_subprofile" || -z "$_file" ]] && lib_utils::die_fatal + + [ -z "$global_client_version" ] && lib_utils::die_fatal + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal + sed \ -e "s:@DOCKER_FINANCE_CONTAINER_CMD@:${DOCKER_FINANCE_CONTAINER_CMD}:g" \ -e "s:@DOCKER_FINANCE_CONTAINER_REPO@:${DOCKER_FINANCE_CONTAINER_REPO}:g" \ @@ -796,23 +866,49 @@ function lib_gen::__gen_subprofile_flow_shell_write() "${global_repo_conf_dir}/container/shell/subprofile.bash.in" >"$_file" } +# +# Subprofile: flow: append subscript to superscript +# + +function lib_gen::__gen_subprofile_flow_superscript() +{ + [[ -z "$_profile" || -z "$_subprofile" ]] && lib_utils::die_fatal + + [ -z "$global_shell_file" ] && lib_utils::die_fatal + [ ! -f "$global_shell_file" ] && lib_utils::die_fatal "Superscript does not exist!" + + # Append subprofile source to superscript + local -r _source="source \"\${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/${_profile}/${_subprofile}/docker-finance.d/shell/subprofile.bash\"" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Appending subprofile to superscript\e[0m\n" + + # If source subprofile does not exist, append + grep "$_source" "$global_shell_file" >&/dev/null \ + || sed -i "$(wc -l <$global_shell_file)i\\$_source\\" "$global_shell_file" + + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Edit superscript now? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + local _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_shell_file" +} + # # Subprofile: flow: generate fetch config # function lib_gen::__gen_subprofile_flow_fetch() { - local _dir="${_gen_conf_path}/fetch" + [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal + + local -r _dir="${_gen_conf_path}/fetch" [ ! -d "$_dir" ] && mkdir -p "$_dir" - local _file="${_dir}/fetch.yaml" + local -r _file="${_dir}/fetch.yaml" if [ -f "$_file" ]; then - lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile's fetch configuration found, backup then generate new one? [Y/n] \e[0m" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_fetch_write @@ -824,20 +920,17 @@ function lib_gen::__gen_subprofile_flow_fetch() fi lib_utils::print_custom "$_print_custom" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" } function lib_gen::__gen_subprofile_flow_fetch_write() { - [ -z "$_profile" ] && lib_utils::die_fatal - [ -z "$_subprofile" ] && lib_utils::die_fatal - - [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal - [ -z "$_file" ] && lib_utils::die_fatal + [[ -z "$_profile" || -z "$_subprofile" || -z "$_file" ]] && lib_utils::die_fatal [ -z "$global_client_version" ] && lib_utils::die_fatal + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal sed \ -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ @@ -852,6 +945,8 @@ function lib_gen::__gen_subprofile_flow_fetch_write() function lib_gen::__gen_subprofile_flow_meta() { + [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal + local _dir="${_gen_conf_path}/meta" [ ! -d "$_dir" ] && mkdir -p "$_dir" @@ -859,10 +954,10 @@ function lib_gen::__gen_subprofile_flow_meta() if [ -f "$_file" ]; then lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile's financial metadata found, backup then generate new one? [Y/n] \e[0m" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_meta_write @@ -874,13 +969,18 @@ function lib_gen::__gen_subprofile_flow_meta() fi lib_utils::print_custom "$_print_custom" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" } function lib_gen::__gen_subprofile_flow_meta_write() { + [ -z "$_file" ] && lib_utils::die_fatal + + [ -z "$global_client_version" ] && lib_utils::die_fatal + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal + # Deletes default comments or else ROOT meta sample won't work out-of-the-box sed \ -e "/\/\/\\!/d" \ @@ -894,8 +994,7 @@ function lib_gen::__gen_subprofile_flow_meta_write() function lib_gen::__gen_subprofile_flow_hledger() { - local -r _gen_path="$1" - local -r _gen_conf_path="$2" + [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal local _dir="${_gen_conf_path}/hledger" [ ! -d "$_dir" ] && mkdir -p "$_dir" @@ -903,37 +1002,36 @@ function lib_gen::__gen_subprofile_flow_hledger() 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 + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - if [[ "$_confirm" == [yY] ]]; then + if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal - lib_gen::__gen_subprofile_hledger_write "$_file" + lib_gen::__gen_subprofile_flow_hledger_write local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" fi else - lib_gen::__gen_subprofile_hledger_write "$_file" + lib_gen::__gen_subprofile_flow_hledger_write 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 + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" } function lib_gen::__gen_subprofile_flow_hledger_write() { - local _file="$1" [ -z "$_file" ] && lib_utils::die_fatal - [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal - lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" - [ -z "$global_client_version" ] && lib_utils::die_fatal lib_utils::print_debug "global_client_version=${global_client_version}" + [ -z "$global_repo_conf_dir" ] && lib_utils::die_fatal + lib_utils::print_debug "global_repo_conf_dir=${global_repo_conf_dir}" + sed \ -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ "${global_repo_conf_dir}/container/hledger/hledger.conf.in" >"$_file" @@ -945,6 +1043,8 @@ function lib_gen::__gen_subprofile_flow_hledger_write() function lib_gen::__gen_subprofile_flow_accounts() { + [[ -z "$_gen_path" || -z "$_gen_conf_path" || -z "$_subprofile" ]] && lib_utils::die_fatal + lib_utils::print_debug "Generating accounts" local _subprofile_path="${_gen_path}/import/${_subprofile}" @@ -952,51 +1052,49 @@ function lib_gen::__gen_subprofile_flow_accounts() if [ -d "$_subprofile_path" ]; then lib_utils::print_custom " \e[32m│ │ │ ├─\e[34m Subprofile import path exists! Continue with account generation (files will be backed up)? [Y/n] \e[0m" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] || return 0 + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] || return 0 else mkdir -p "$_subprofile_path" fi - # docker-finance templates + # All available hledger-flow account paths local _templates_paths - mapfile -t _templates_paths < <(find ${DOCKER_FINANCE_CLIENT_REPO}/container/src/hledger-flow/accounts -name template | sort) + mapfile -t _templates_paths < <(find "${DOCKER_FINANCE_CLIENT_REPO}"/container/src/hledger-flow/accounts -name template | sort) declare -r _templates_paths - lib_utils::print_debug "_templates_paths=${_templates_paths[*]}" - lib_utils::print_custom " \e[32m│ │ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ │ ├─\e[34;1m Generate individual subprofile accounts instead of generating them all at once? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - - # Cycle through all available docker-finance templates and populate subprofile - if [[ $_confirm == [yY] ]]; then - for _template_path in "${_templates_paths[@]}"; do - lib_utils::print_debug "_template_path=${_template_path}" - lib_utils::print_custom " \e[32m│ │ │ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ │ │ ├─\e[34m\e[1m Generate $(echo $_template_path | rev | cut -d/ -f2 | rev) ? [Y/n] \e[0m" - read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] \ - && lib_gen::__gen_subprofile_flow_accounts_populate "$_subprofile_path" "$_template_path" "$_is_testing" + # All available hledger-flow account names + local _accounts + if [ -z "${global_arg_account[*]}" ]; then + for _template in "${_templates_paths[@]}"; do + _accounts+=("$(echo "$_template" | rev | cut -d/ -f2 | rev)") done else - for _template_path in "${_templates_paths[@]}"; do - lib_utils::print_debug "$_subprofile_path $_template_path $_is_testing" - lib_gen::__gen_subprofile_flow_accounts_populate "$_subprofile_path" "$_template_path" "$_is_testing" - done + declare -r _accounts=("${global_arg_account[@]}") fi + + # Cycle through all available docker-finance templates and populate subprofile + for _account in "${_accounts[@]}"; do + for _template_path in "${_templates_paths[@]}"; do + if [[ "$_template_path" =~ \/$_account\/ ]]; then + lib_utils::print_debug "_template_path=${_template_path}" + lib_utils::print_custom " \e[32m│ │ │ │ │\e[0m\n" + lib_utils::print_custom " \e[32m│ │ │ │ ├─\e[34m\e[1m Generate $_account ? [Y/n] \e[0m" + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read + _confirm="${_read:-y}" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] \ + && lib_gen::__gen_subprofile_flow_accounts_populate "$_subprofile_path" "$_template_path" + fi + done + done } function lib_gen::__gen_subprofile_flow_accounts_populate() { - [ -z "$1" ] && lib_utils::die_fatal - [ -z "$2" ] && lib_utils::die_fatal - [ -z "$3" ] && lib_utils::die_fatal + [[ -z "$1" || -z "$2" ]] && lib_utils::die_fatal local _subprofile_path="$1" local _template_path="$2" - local _is_testing="$3" # Continue if hledger-flow account exists local _continue @@ -1009,9 +1107,9 @@ function lib_gen::__gen_subprofile_flow_accounts_populate() # TODO: doesn't check for blockchain explorer shared rules/bash if [ -d "$_account_path" ]; then lib_utils::print_custom " \e[32m│ │ │ │ │ └─\e[34m Account exists! Continue with backup and generation? [Y/n] \e[0m" - read -p "" _read + [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" - [[ "$_confirm" == [yY] ]] || _continue=false + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] || _continue=false fi # Populate with template @@ -1037,7 +1135,7 @@ function lib_gen::__gen_subprofile_flow_accounts_populate() local _mockup="${_in_path}/mockup" lib_utils::print_debug "Getting mockup '${_mockup}'" - if [[ $_is_testing == true ]]; then + if [ ! -z "$global_arg_dev" ]; then lib_utils::print_debug "Copying mockup to '${_in_path}'" cp -a -R --backup --suffix="_${global_suffix}" "${_mockup}"/* "${_in_path}/" || lib_utils::die_fatal fi From c8d99e3f125b66a31d70441f9bb212bc30618bcf Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:35:08 -0700 Subject: [PATCH 06/13] client: docker-finance.d: superscript: remove unused tag Impl now appends, regardless of tag. --- client/docker-finance.d/container/shell/superscript.bash.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/docker-finance.d/container/shell/superscript.bash.in b/client/docker-finance.d/container/shell/superscript.bash.in index 482c8a8..22832ef 100644 --- a/client/docker-finance.d/container/shell/superscript.bash.in +++ b/client/docker-finance.d/container/shell/superscript.bash.in @@ -40,8 +40,6 @@ alias c='clear' # or ctrl+l alias e='exit' alias grep='grep --color=auto' -# All subprofiles' scripts -# TODO: remove this tag as it's no longer needed -@DOCKER_FINANCE_SUBPROFILE_SOURCE@ +# All subprofiles' subscripts are appended below # vim: syn=bash sw=2 sts=2 si ai et From 51bf587ceb63cdebc747b2c41c5bf17b5ceb126f Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:35:25 -0700 Subject: [PATCH 07/13] client/container: rename 'subprofile' script to 'subscript' - Provides clarity, avoids confusion (subprofile.bash -> subscript.bash) - Changes filename in superscript source * End-user must update with client command `edit type=superscript` - Changes filename in flow subprofile's docker-finance.d * Pre-existing subprofiles must manually rename their subscript file --- .../{subprofile.bash.in => subscript.bash.in} | 2 +- client/src/docker/lib/internal/lib_gen.bash | 36 +++++++++---------- container/src/finance/lib/lib_finance.bash | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) rename client/docker-finance.d/container/shell/{subprofile.bash.in => subscript.bash.in} (98%) diff --git a/client/docker-finance.d/container/shell/subprofile.bash.in b/client/docker-finance.d/container/shell/subscript.bash.in similarity index 98% rename from client/docker-finance.d/container/shell/subprofile.bash.in rename to client/docker-finance.d/container/shell/subscript.bash.in index c9a9768..09abc80 100644 --- a/client/docker-finance.d/container/shell/subprofile.bash.in +++ b/client/docker-finance.d/container/shell/subscript.bash.in @@ -20,7 +20,7 @@ # docker-finance @DOCKER_FINANCE_VERSION@ # -# Subprofile script +# Subscript (subprofile script) called by superscript # [ -z "$DOCKER_FINANCE_CONTAINER_CMD" ] && echo "DOCKER_FINANCE_CONTAINER_CMD not set, check installation" >&2 diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index 4f7f4ef..0f2ba68 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -74,7 +74,7 @@ function lib_gen::__parse_args() Configuration type: - config${global_arg_delim_2} + config${global_arg_delim_2} Accounts: @@ -128,13 +128,13 @@ function lib_gen::__parse_args() $ $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 + $ $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}subscript \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 + $ $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}subscript account${global_arg_delim_2}ethereum-based${global_arg_delim_3}metamask \e[32mNotes:\e[0m @@ -307,7 +307,7 @@ function lib_gen::__parse_args() fi read -ra _read <<<"$_arg_config" for _arg in "${_read[@]}"; do - if [[ ! "$_arg" =~ ^fetch$|^hledger$|^meta$|^subprofile$ ]]; then + if [[ ! "$_arg" =~ ^fetch$|^hledger$|^meta$|^subscript$ ]]; then lib_utils::die_usage "$_usage" fi done @@ -734,14 +734,14 @@ function lib_gen::__gen_subprofile_flow() { [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal - if lib_gen::__gen_subprofile_flow_args_config "subprofile"; then + if lib_gen::__gen_subprofile_flow_args_config "subscript"; then lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's shell script? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's subscript file? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then # Subprofile's shell script - lib_gen::__gen_subprofile_flow_shell + lib_gen::__gen_subprofile_flow_subscript # Append subprofile source to superscript lib_gen::__gen_subprofile_flow_superscript fi @@ -815,31 +815,31 @@ function lib_gen::__gen_subprofile_flow_args_account() } # -# Subprofile: flow: generate subprofile script +# Subprofile: flow: generate subprofile subscript # -function lib_gen::__gen_subprofile_flow_shell() +function lib_gen::__gen_subprofile_flow_subscript() { [[ -z "$_gen_path" || -z "$_gen_conf_path" ]] && lib_utils::die_fatal local _dir="${_gen_conf_path}/shell" [ ! -d "$_dir" ] && mkdir -p "$_dir" - local _file="${_dir}/subprofile.bash" + local _file="${_dir}/subscript.bash" if [ -f "$_file" ]; then - lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile script found, backup then generate new one? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile subscript found, backup then generate new one? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal - lib_gen::__gen_subprofile_flow_shell_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile script now? [Y/n] \e[0m" + lib_gen::__gen_subprofile_flow_subscript_write + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile subscript now? [Y/n] \e[0m" fi else - lib_gen::__gen_subprofile_flow_shell_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile script now? [Y/n] \e[0m" + lib_gen::__gen_subprofile_flow_subscript_write + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile subscript now? [Y/n] \e[0m" fi lib_utils::print_custom "$_print_custom" @@ -848,7 +848,7 @@ function lib_gen::__gen_subprofile_flow_shell() [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" } -function lib_gen::__gen_subprofile_flow_shell_write() +function lib_gen::__gen_subprofile_flow_subscript_write() { [[ -z "$DOCKER_FINANCE_CONTAINER_REPO" || -z "$DOCKER_FINANCE_CONTAINER_CMD" ]] && lib_utils::die_fatal @@ -863,7 +863,7 @@ function lib_gen::__gen_subprofile_flow_shell_write() -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ -e "s:@DOCKER_FINANCE_PROFILE@:${_profile}:g" \ -e "s:@DOCKER_FINANCE_SUBPROFILE@:${_subprofile}:g" \ - "${global_repo_conf_dir}/container/shell/subprofile.bash.in" >"$_file" + "${global_repo_conf_dir}/container/shell/subscript.bash.in" >"$_file" } # @@ -878,7 +878,7 @@ function lib_gen::__gen_subprofile_flow_superscript() [ ! -f "$global_shell_file" ] && lib_utils::die_fatal "Superscript does not exist!" # Append subprofile source to superscript - local -r _source="source \"\${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/${_profile}/${_subprofile}/docker-finance.d/shell/subprofile.bash\"" + local -r _source="source \"\${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/${_profile}/${_subprofile}/docker-finance.d/shell/subscript.bash\"" lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Appending subprofile to superscript\e[0m\n" # If source subprofile does not exist, append diff --git a/container/src/finance/lib/lib_finance.bash b/container/src/finance/lib/lib_finance.bash index aa95a68..df3f942 100644 --- a/container/src/finance/lib/lib_finance.bash +++ b/container/src/finance/lib/lib_finance.bash @@ -80,7 +80,7 @@ function lib_finance::finance() 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" + declare -grx global_conf_shell="${global_child_profile_flow}/docker-finance.d/shell/subscript.bash" # Implementation "libraries" (requires previously set globals) source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_edit.bash" || exit 1 From 0ec42d242093fe15f47ca4340582259a45d090d9 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:35:44 -0700 Subject: [PATCH 08/13] client: rename $global_shell_file -> $global_superscript Provides clarity, avoids confusion. --- .../src/docker/lib/internal/lib_docker.bash | 10 ++++---- client/src/docker/lib/internal/lib_env.bash | 4 ++-- client/src/docker/lib/internal/lib_gen.bash | 24 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/client/src/docker/lib/internal/lib_docker.bash b/client/src/docker/lib/internal/lib_docker.bash index 9a3d3ae..15cde64 100644 --- a/client/src/docker/lib/internal/lib_docker.bash +++ b/client/src/docker/lib/internal/lib_docker.bash @@ -561,11 +561,11 @@ function lib_docker::__edit() [ -z "$global_env_file" ] && lib_utils::die_fatal [ ! -f "$global_env_file" ] \ - && lib_utils::die_fatal "Environment file now found" + && lib_utils::die_fatal "Environment file not found" - [ -z "$global_shell_file" ] && lib_utils::die_fatal - [ ! -f "$global_shell_file" ] \ - && lib_utils::die_fatal "Shell (superscript) file now found" + [ -z "$global_superscript" ] && lib_utils::die_fatal + [ ! -f "$global_superscript" ] \ + && lib_utils::die_fatal "Shell (superscript) file not found" # Run all files through one editor instance local _paths=() @@ -581,7 +581,7 @@ function lib_docker::__edit() [[ "$global_platform" == "dev-tools" ]] \ && lib_utils::die_fatal "Invalid platform, use finance image" - _paths+=("$global_shell_file") + _paths+=("$global_superscript") ;; build | dockerfile) [ -z "$global_custom_dockerfile" ] && lib_utils::die_fatal diff --git a/client/src/docker/lib/internal/lib_env.bash b/client/src/docker/lib/internal/lib_env.bash index ef09ad2..e957cf7 100644 --- a/client/src/docker/lib/internal/lib_env.bash +++ b/client/src/docker/lib/internal/lib_env.bash @@ -240,8 +240,8 @@ function lib_env::__set_client_globals() local _client_shell_dir="${DOCKER_FINANCE_CLIENT_CONF}/container/shell" [ ! -d "$_client_shell_dir" ] && mkdir -p "$_client_shell_dir" - global_shell_file="${_client_shell_dir}/superscript.bash" - lib_utils::print_debug "global_shell_file=${global_shell_file}" + global_superscript="${_client_shell_dir}/superscript.bash" + lib_utils::print_debug "global_superscript=${global_superscript}" # Client view of client portion of repository global_repo_client="${DOCKER_FINANCE_CLIENT_REPO}/client" diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index 0f2ba68..e59ffd8 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -549,9 +549,9 @@ function lib_gen::__gen_container() function lib_gen::__gen_superscript() { - [ -z "$global_shell_file" ] && lib_utils::die_fatal + [ -z "$global_superscript" ] && lib_utils::die_fatal - if [ -f "$global_shell_file" ]; then + if [ -f "$global_superscript" ]; then lib_utils::print_custom " \e[32m│ └─\e[34m Backup existing superscript and generate a new one? [N/y] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read @@ -559,7 +559,7 @@ function lib_gen::__gen_superscript() if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then # Backup - local -r _backup=("cp" "-a" "$global_shell_file" "${global_shell_file}_${global_suffix}") + local -r _backup=("cp" "-a" "$global_superscript" "${global_superscript}_${global_suffix}") lib_utils::print_debug "${_backup[@]}" "${_backup[@]}" || lib_utils::die_fatal # Write @@ -575,7 +575,7 @@ function lib_gen::__gen_superscript() [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_shell_file" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_superscript" } function lib_gen::__gen_superscript_write() @@ -586,12 +586,12 @@ function lib_gen::__gen_superscript_write() [ -z "$global_client_version" ] && lib_utils::die_fatal lib_utils::print_debug "global_client_version=${global_client_version}" - [ -z "$global_shell_file" ] && lib_utils::die_fatal - lib_utils::print_debug "global_shell_file=${global_shell_file}" + [ -z "$global_superscript" ] && lib_utils::die_fatal + lib_utils::print_debug "global_superscript=${global_superscript}" sed \ -e "s:@DOCKER_FINANCE_VERSION@:${global_client_version}:g" \ - "${global_repo_conf_dir}/container/shell/superscript.bash.in" >"$global_shell_file" + "${global_repo_conf_dir}/container/shell/superscript.bash.in" >"$global_superscript" } # @@ -874,21 +874,21 @@ function lib_gen::__gen_subprofile_flow_superscript() { [[ -z "$_profile" || -z "$_subprofile" ]] && lib_utils::die_fatal - [ -z "$global_shell_file" ] && lib_utils::die_fatal - [ ! -f "$global_shell_file" ] && lib_utils::die_fatal "Superscript does not exist!" + [ -z "$global_superscript" ] && lib_utils::die_fatal + [ ! -f "$global_superscript" ] && lib_utils::die_fatal "Superscript does not exist!" # Append subprofile source to superscript local -r _source="source \"\${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/${_profile}/${_subprofile}/docker-finance.d/shell/subscript.bash\"" lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Appending subprofile to superscript\e[0m\n" # If source subprofile does not exist, append - grep "$_source" "$global_shell_file" >&/dev/null \ - || sed -i "$(wc -l <$global_shell_file)i\\$_source\\" "$global_shell_file" + grep "$_source" "$global_superscript" >&/dev/null \ + || sed -i "$(wc -l <$global_superscript)i\\$_source\\" "$global_superscript" lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Edit superscript now? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_shell_file" + [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_superscript" } # From 52270ba0b38c1f39fadd528aabb74c255d1124eb Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:36:03 -0700 Subject: [PATCH 09/13] container: rename $global_conf_shell -> $global_conf_subscript Provides clarity, avoids confusion. --- container/plugins/root/example.cc | 2 +- container/src/finance/lib/internal/lib_edit.bash | 6 +++--- container/src/finance/lib/lib_finance.bash | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/container/plugins/root/example.cc b/container/plugins/root/example.cc index a6cfa08..23b0248 100644 --- a/container/plugins/root/example.cc +++ b/container/plugins/root/example.cc @@ -96,7 +96,7 @@ void example2() print_env("global_conf_fetch"); print_env("global_conf_hledger"); print_env("global_conf_meta"); - print_env("global_conf_shell"); + print_env("global_conf_subscript"); // TODO(unassigned): read array from shell? ROOT impl simply calls stdlib getenv() // print_env("global_hledger_cmd"); print_env("global_parent_profile"); diff --git a/container/src/finance/lib/internal/lib_edit.bash b/container/src/finance/lib/internal/lib_edit.bash index 36e02f4..5a3b87a 100644 --- a/container/src/finance/lib/internal/lib_edit.bash +++ b/container/src/finance/lib/internal/lib_edit.bash @@ -324,14 +324,14 @@ function lib_edit::__edit() $EDITOR "${_paths[@]}" || lib_utils::die_fatal ;; shell) - [ -z "$global_conf_shell" ] && lib_utils::die_fatal + [ -z "$global_conf_subscript" ] && lib_utils::die_fatal local _dir - _dir="$(dirname $global_conf_shell)" + _dir="$(dirname $global_conf_subscript)" [ ! -d "$_dir" ] && mkdir -p "$_dir" local _file - _file="$(basename $global_conf_shell)" + _file="$(basename $global_conf_subscript)" local _path _path="${_dir}/${_file}" diff --git a/container/src/finance/lib/lib_finance.bash b/container/src/finance/lib/lib_finance.bash index df3f942..cabbc68 100644 --- a/container/src/finance/lib/lib_finance.bash +++ b/container/src/finance/lib/lib_finance.bash @@ -80,7 +80,7 @@ function lib_finance::finance() 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/subscript.bash" + declare -grx global_conf_subscript="${global_child_profile_flow}/docker-finance.d/shell/subscript.bash" # Implementation "libraries" (requires previously set globals) source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_edit.bash" || exit 1 From 169034cbe2dc1b53c7908e1a39fab3fed490cdc1 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:36:30 -0700 Subject: [PATCH 10/13] client: src: lib_gen: refactor/update editor related - Creates a reusable editor function - Skipping confirmations will also skip opening up the editor * Allows for complete generation without intentional interruption --- client/src/docker/lib/internal/lib_gen.bash | 54 ++++++++++----------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index e59ffd8..2ab642c 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -395,7 +395,6 @@ function lib_gen::gen() function lib_gen::__gen_client() { [ -z "$global_suffix" ] && lib_utils::die_fatal - [ -z "$EDITOR" ] && lib_utils::die_fatal lib_utils::print_debug "Generating client" @@ -430,10 +429,7 @@ function lib_gen::__gen_client() fi lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) environment now? [Y/n] \e[0m" - - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_env_file" + lib_gen::__gen_edit "$global_env_file" # Get/Set new (edited) environment variables lib_env::__read "$global_env_file" @@ -472,10 +468,7 @@ function lib_gen::__gen_client() fi lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) custom Dockerfile now? [Y/n] \e[0m" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_custom_dockerfile" || return 0 - + lib_gen::__gen_edit "$global_custom_dockerfile" fi } @@ -571,11 +564,9 @@ function lib_gen::__gen_superscript() lib_gen::__gen_superscript_write local _print_custom=" \e[32m│ │ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" fi - lib_utils::print_custom "$_print_custom" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_superscript" + lib_utils::print_custom "$_print_custom" + lib_gen::__gen_edit "$global_superscript" } function lib_gen::__gen_superscript_write() @@ -843,9 +834,7 @@ function lib_gen::__gen_subprofile_flow_subscript() fi lib_utils::print_custom "$_print_custom" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" + lib_gen::__gen_edit "$_file" } function lib_gen::__gen_subprofile_flow_subscript_write() @@ -886,9 +875,7 @@ function lib_gen::__gen_subprofile_flow_superscript() || sed -i "$(wc -l <$global_superscript)i\\$_source\\" "$global_superscript" lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Edit superscript now? [Y/n] \e[0m" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - local _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$global_superscript" + lib_gen::__gen_edit "$global_superscript" } # @@ -920,9 +907,7 @@ function lib_gen::__gen_subprofile_flow_fetch() fi lib_utils::print_custom "$_print_custom" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" + lib_gen::__gen_edit "$_file" } function lib_gen::__gen_subprofile_flow_fetch_write() @@ -969,9 +954,7 @@ function lib_gen::__gen_subprofile_flow_meta() fi lib_utils::print_custom "$_print_custom" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" + lib_gen::__gen_edit "$_file" } function lib_gen::__gen_subprofile_flow_meta_write() @@ -1017,9 +1000,7 @@ function lib_gen::__gen_subprofile_flow_hledger() fi lib_utils::print_custom "$_print_custom" - [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read - _confirm="${_read:-y}" - [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && $EDITOR "$_file" + lib_gen::__gen_edit "$_file" } function lib_gen::__gen_subprofile_flow_hledger_write() @@ -1149,4 +1130,21 @@ function lib_gen::__gen_subprofile_flow_accounts_populate() fi } +function lib_gen::__gen_edit() +{ + local _file="$1" + [[ -z "$_file" || ! -f "$_file" ]] && lib_utils::die_fatal + + if [ -z "$global_arg_confirm" ]; then + lib_utils::print_custom "\n" + _read="n" + else + read -p "" _read + fi + local _confirm="${_read:-y}" + + [ -z "$EDITOR" ] && lib_utils::die_fatal + [[ "$_confirm" == [yY] ]] && $EDITOR "$_file" || return 0 +} + # vim: sw=2 sts=2 si ai et From f2102c7b90b68db714a88d24a22cd6f7f72161ce Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:36:42 -0700 Subject: [PATCH 11/13] client: src: lib_gen: reduce prompt language verbosity --- client/src/docker/lib/internal/lib_gen.bash | 50 ++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/client/src/docker/lib/internal/lib_gen.bash b/client/src/docker/lib/internal/lib_gen.bash index 2ab642c..d8ddb29 100644 --- a/client/src/docker/lib/internal/lib_gen.bash +++ b/client/src/docker/lib/internal/lib_gen.bash @@ -410,7 +410,7 @@ function lib_gen::__gen_client() # Backup existing file if [ -f "$global_env_file" ]; then lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Client-side environment found, backup then generate new one? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m├─\e[34;1m Client environment file found, backup then generate new one? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read local _confirm="${_read:-y}" @@ -428,7 +428,7 @@ function lib_gen::__gen_client() fi fi - lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) environment now? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ └─\e[34m Edit file now? [Y/n] \e[0m" lib_gen::__gen_edit "$global_env_file" # Get/Set new (edited) environment variables @@ -467,7 +467,7 @@ function lib_gen::__gen_client() cp -a "$global_repo_custom_dockerfile" "$global_custom_dockerfile" fi - lib_utils::print_custom " \e[32m│ └─\e[34m Edit (new) custom Dockerfile now? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ └─\e[34m Edit file now? [Y/n] \e[0m" lib_gen::__gen_edit "$global_custom_dockerfile" fi } @@ -483,7 +483,7 @@ function lib_gen::__gen_container() if [[ -z "${global_arg_type[*]}" || "${global_arg_type[*]}" =~ superscript ]]; then lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Generate (or update) joint client/container superscript? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m├─\e[34;1m Generate joint client/container superscript? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then @@ -510,7 +510,7 @@ function lib_gen::__gen_container() if [[ "${global_arg_all[*]}" =~ all|type || "${global_arg_type[*]}" =~ flow ]]; then lib_utils::print_custom " \e[32m│\e[0m\n" - lib_utils::print_custom " \e[32m├─\e[34;1m Generate (or update) container finance flow (layout and profiles)? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m├─\e[34;1m Generate container finance flow (layout and profiles)? [Y/n] \e[0m" # Prompt if type not given if [[ ! "${global_arg_all[*]}" =~ all|type || -z "${global_arg_type[*]}" ]]; then if [ -z "$global_arg_confirm" ]; then @@ -545,7 +545,7 @@ function lib_gen::__gen_superscript() [ -z "$global_superscript" ] && lib_utils::die_fatal if [ -f "$global_superscript" ]; then - lib_utils::print_custom " \e[32m│ └─\e[34m Backup existing superscript and generate a new one? [N/y] \e[0m" + lib_utils::print_custom " \e[32m│ └─\e[34m Backup existing file and generate a new one? [N/y] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read local _confirm="${_read:-n}" @@ -558,11 +558,11 @@ function lib_gen::__gen_superscript() # Write lib_gen::__gen_superscript_write fi - local _print_custom=" \e[32m│ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ └─\e[34m Edit file now? [Y/n] \e[0m" else # Generate new default file lib_gen::__gen_superscript_write - local _print_custom=" \e[32m│ │ └─\e[34m Edit (new) superscript now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi lib_utils::print_custom "$_print_custom" @@ -727,7 +727,7 @@ function lib_gen::__gen_subprofile_flow() if lib_gen::__gen_subprofile_flow_args_config "subscript"; then lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's subscript file? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate subprofile's subscript file? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" if [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]]; then @@ -741,7 +741,7 @@ function lib_gen::__gen_subprofile_flow() if lib_gen::__gen_subprofile_flow_args_config "fetch"; then # Prompt for default generation lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's fetch configuration file? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate subprofile's fetch configuration file? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_fetch @@ -749,7 +749,7 @@ function lib_gen::__gen_subprofile_flow() if lib_gen::__gen_subprofile_flow_args_config "meta"; then lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's financial metadata file? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate subprofile's financial metadata file? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_meta @@ -757,7 +757,7 @@ function lib_gen::__gen_subprofile_flow() if lib_gen::__gen_subprofile_flow_args_config "hledger"; then lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger configuration file? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate subprofile's hledger configuration file? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" [[ "$_confirm" == [yY] || -z "$global_arg_confirm" ]] && lib_gen::__gen_subprofile_flow_hledger @@ -765,7 +765,7 @@ function lib_gen::__gen_subprofile_flow() if lib_gen::__gen_subprofile_flow_args_account; then lib_utils::print_custom " \e[32m│ │ │\e[0m\n" - lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate (or update) subprofile's hledger-flow accounts? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ ├─\e[34;1m Generate subprofile's hledger-flow accounts? [Y/n] \e[0m" if [ ! -z "${global_arg_account[*]}" ]; then lib_utils::print_custom "\n" lib_gen::__gen_subprofile_flow_accounts @@ -818,7 +818,7 @@ function lib_gen::__gen_subprofile_flow_subscript() local _file="${_dir}/subscript.bash" if [ -f "$_file" ]; then - lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile subscript found, backup then generate new one? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m File found, backup then generate new one? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" @@ -826,11 +826,11 @@ function lib_gen::__gen_subprofile_flow_subscript() cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_subscript_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile subscript now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi else lib_gen::__gen_subprofile_flow_subscript_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile subscript now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi lib_utils::print_custom "$_print_custom" @@ -891,7 +891,7 @@ function lib_gen::__gen_subprofile_flow_fetch() local -r _file="${_dir}/fetch.yaml" if [ -f "$_file" ]; then - lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile's fetch configuration found, backup then generate new one? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m File found, backup then generate new one? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" @@ -899,11 +899,11 @@ function lib_gen::__gen_subprofile_flow_fetch() cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_fetch_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile's fetch configuration now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi else lib_gen::__gen_subprofile_flow_fetch_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile's fetch configuration now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi lib_utils::print_custom "$_print_custom" @@ -938,7 +938,7 @@ function lib_gen::__gen_subprofile_flow_meta() local _file="${_dir}/meta.csv" if [ -f "$_file" ]; then - lib_utils::print_custom " \e[32m│ │ │ └─\e[34m Subprofile's financial metadata found, backup then generate new one? [Y/n] \e[0m" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m File found, backup then generate new one? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" @@ -946,11 +946,11 @@ function lib_gen::__gen_subprofile_flow_meta() cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_meta_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile's financial metadata now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi else lib_gen::__gen_subprofile_flow_meta_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) subprofile's financial metadata now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi lib_utils::print_custom "$_print_custom" @@ -984,7 +984,7 @@ function lib_gen::__gen_subprofile_flow_hledger() 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" + lib_utils::print_custom " \e[32m│ │ │ └─\e[34m File found, backup then generate new one? [Y/n] \e[0m" [ -z "$global_arg_confirm" ] && lib_utils::print_custom "\n" || read -p "" _read _confirm="${_read:-y}" @@ -992,11 +992,11 @@ function lib_gen::__gen_subprofile_flow_hledger() cp -a "$_file" "${_file}_${global_suffix}" || lib_utils::die_fatal lib_gen::__gen_subprofile_flow_hledger_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi else lib_gen::__gen_subprofile_flow_hledger_write - local _print_custom=" \e[32m│ │ │ └─\e[34m Edit (new) hledger configuration now? [Y/n] \e[0m" + local _print_custom=" \e[32m│ │ │ └─\e[34m Edit file now? [Y/n] \e[0m" fi lib_utils::print_custom "$_print_custom" From e6ccd9607c5c6a67e1e6a7d9d8def8a746c0cdaf Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:36:56 -0700 Subject: [PATCH 12/13] client: completion: add `gen` arguments --- client/src/docker/completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/docker/completion.bash b/client/src/docker/completion.bash index a217574..1ee4cce 100644 --- a/client/src/docker/completion.bash +++ b/client/src/docker/completion.bash @@ -73,7 +73,7 @@ function docker-finance::completion() case "$_prev" in gen) - # TODO: _currently no-op + mapfile -t _reply < <(compgen -W "help all${global_arg_delim_2} type${global_arg_delim_2} profile${global_arg_delim_2} config${global_arg_delim_2} account${global_arg_delim_2} dev${global_arg_delim_2} confirm${global_arg_delim_2}" -- "$_cur") ;; edit) mapfile -t _reply < <(compgen -W "help type${global_arg_delim_2}" -- "$_cur") From a14dfaedde27bc4d677a471e91f3898af60fab83 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sun, 22 Sep 2024 18:37:07 -0700 Subject: [PATCH 13/13] README: update to latest `gen` impl --- README.md | 71 ++++++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 5d0d92c..74bc075 100644 --- a/README.md +++ b/README.md @@ -329,9 +329,10 @@ Supported blockchains (independent of wallet type): The following will generate your Docker-related client/container environment for the default image (see [Environment Generation](#environment-generation) for details): ```bash - dfi archlinux/${USER}:default gen + dfi archlinux/${USER}:default gen all=all ``` - > If you would like to use the `ubuntu` image, replace `archlinux` with `ubuntu` here and for all remaining steps + > To regenerate any step in this process, now or in the future, use `gen help` for available options + > To use the `ubuntu` image instead, replace `archlinux` with `ubuntu` here and for all remaining steps 7. **Build default `docker-finance` image**: ```bash @@ -349,7 +350,7 @@ Supported blockchains (independent of wallet type): 10. (Optional) **Developers: on your client (host), build and setup the `dev-tools` platform**: ```bash - dfi dev-tools/${USER}:default build type=default && dfi dev-tools/${USER}:default gen + dfi dev-tools/${USER}:default build type=default && dfi dev-tools/${USER}:default gen all=all ``` ### Environment Generation @@ -371,7 +372,7 @@ You'll create these files (and more) when running client (host) command `gen`, a When running `gen`, you'll see the following: -> *Client-side environment found, backup then generate new one?* +> *Client environment file found, backup then generate new one? [Y/n]* Generates the client (host) configuration file (see the [Client (Host) Configuration File](#client-host-configuration) for details). @@ -384,22 +385,21 @@ Generates custom Dockerfile. Do as you wish; install your own container packages - To easily edit this configuration file after `gen` is complete, run client (host) command `edit type=build` +> *Generate joint client/container superscript? [Y/n]* + +Select 'y' if this is your first-run for the given platform and tag, or if you need to regenerate the file (see [Superscript](#clientcontainer-superscript) for details). + --- #### Container Generation After the previous client environment is generated, the following will prepare the container environment (everything you'll need while inside `docker-finance`). -> *Generate (or update) container flow (profiles, etc.)?* +> *Generate container finance flow (layout and profiles)? [Y/n]* -Although the container environment is a minimum requirement, here you'll have the option to continue generating or to backup a previous install. +Not limited to `hledger-flow` data, this option leads to generating the layout and files needed for processing *all* `docker-finance` end-user generated data (journals, configurations, etc.). -> *Will this profile be used for development and/or demonstration?* - -If you're a developer or wish to see the mockup test profile, select 'y' here. - -It should be noted that: - - mockup data can be found in the `mockup` directories within this repository +Although the container environment is a minimum requirement, here you'll have the option to continue generation. > *Enter profile name (e.g., family in 'family/alice')* > *Enter subprofile name (e.g., alice in 'family/alice')* @@ -410,42 +410,30 @@ It should be noted that: - all subsequent questions and container generation will relate to this `profile/subprofile` pairing - all output will be sent to the `${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/profile/subprofile` path -> *Generate (or update) joint client/container shell script (superscript)? [Y/n]* - -Select 'y' if this a first-run. If this is not a first-run but you need to regenerate the file, then select 'y' (see [Superscript](#clientcontainer-superscript) for details). - -> *Generate (or update) hledger configuration file?* - -If the container's version of hledger supports it, use this customizable configuration file. - -> *Generate (or update) container flow configs and/or accounts?* - -Not limited to `hledger-flow` data, this option leads to generating the layout and files needed for processing *all* `docker-finance` end-user generated data (journals, configurations, etc.). - -> *Generate (or update) subprofile's shell script?* +> *Generate subprofile's subscript file? [Y/n]* The container's subprofile's shell script is where all subprofile commands and aliases exist. -This file is generated on a per-subprofile basis and all custom code *on a per-subprofile basis* should go here (see [Subprofile](#subprofile) for details). +This file is generated on a per-subprofile basis and all custom code *on a per-subprofile basis* should go here (see [Subscript](#subscript) for details). -> *Generate (or update) subprofile's fetch configuration?* +> *Generate subprofile's fetch configuration file? [Y/n]* The container's fetch configuration is what all remote fetching relies on: prices, exchanges, blockchain explorers; all are configured here (see [Fetch](#fetch-1) for details). -> *Generate (or update) subprofile's financial metadata?* +> *Generate subprofile's financial metadata file? [Y/n]* The container's *per-subprofile* metadata file. This file contains all your custom metadata and can edited with the `edit` and analyzed with the `meta` or `root` command (see [Meta](#meta) for details). -> *Generate (or update) subprofile's hledger-flow accounts?* +> *Generate subprofile's hledger configuration file? [Y/n]* + +This configuration file is specific to `hledger`. See `hledger` documentation for options. + +> *Generate subprofile's hledger-flow accounts? [Y/n]* The container's `hledger-flow` accounts to be installed. These are the accounts described in [What is supported?](#what-is-supported). -> *Generate individual subprofile accounts instead of generating them all at once?* - -If you intend to only use a few accounts, you can do so here. Otherwise, generate all accounts (recommended). - **WARNING**: if you plan to use blockchain-based wallets (coinbase-wallet, pera-wallet, ledger, metamask, etc.), you **MUST** generate their respective chains, as seen during generation (`algorand`, `ethereum-based`, `tezos`, etc). ### Configuration Files @@ -639,7 +627,7 @@ After `gen` is complete, you can edit this file with the client (host) command: The client/container shell script (Superscript) is a bind-mounted (by directory) script that: - is the intermediary between client and container - is unique to each client (host) user (/home/alice, /home/bob, etc.) - - is the glue that ties together **all** container [Subprofile](#subprofile) scripts + - is the glue that ties together **all** container [Subscript](#subscript) - is generated on a per-client basis: all custom code on a **per-client basis** should go here See the in-file comments for further documentation: @@ -654,15 +642,15 @@ After `gen` is complete, you can edit this file with the client (host) command: These configurations are confined solely to the container. -##### *Subprofile* +##### *Subscript* -The Subprofile script is unique to each subprofile for each `profile/subprofile` within the `profiles` parent directory. +The Subprofile's subscript is unique to each subprofile, for each `profile/subprofile` within the `profiles` parent directory. By default, this file will contain user aliases for all container commands. These aliases are mostly useful for small setups or setups with uniquely named subprofiles among all profiles. See the in-file comments for further documentation: - - [subprofile.bash.in](client/docker-finance.d/container/shell/subprofile.bash.in) + - [subscript.bash.in](client/docker-finance.d/container/shell/subscript.bash.in) After `gen` is complete, from within the container, you can edit this file with: `dfi profile/subprofile edit type=shell` (see [Container Command Format](#container-command-format)). @@ -771,7 +759,7 @@ Assuming `` is `testprofile/testuser`: dfi testprofile/testuser fetch help ``` -Or, use a subprofile alias, as described in [Subprofile](#subprofile): +Or, use a subprofile alias, as described in [Subscript](#subscript): ```bash testuser_fetch help @@ -909,8 +897,11 @@ For other dependencies, please see their individual contributing guidelines. You'll greatly benefit from building the [`dev-tools` image](#image-dev-tools), as seen in `docker-finance help`. -Additionally, when developing with the [`docker-finance` image](#image-docker-finance), please test your work with mockups as described in [Environment Generation](#environment-generation) and [Flow Layout](#flow-layout). -> Note: mockup CSVs will *intentionally* have multiple years within in a `1-in/year` directory in order to test for year parsing. +Additionally, when developing with the [`docker-finance` image](#image-docker-finance) create a development profile with the `gen` command argument `dev=on`. From there, you'll have access to mockup CSVs as described in [Flow Layout](#flow-layout). + +> - In addition to `dev=on`, run the `confirm=off` and `profile=` arguments to quickly spin-up a new development profile +> - Developer mockup CSVs can be found in the `mockup` directories within the hledger-flow section of this repository +> - Developer mockup CSVs will *intentionally* have multiple years within in a `1-in/year` directory in order to test for year parsing #### Plugins