From e28d8f0b02a5b921428275ff635df912412c0bcf 2020-07-04 23:40:18
From: Branko Majic <branko@majic.rs>
Date: 2020-07-04 23:40:18
Subject: [PATCH] Noticket: Drop warning_prompt and bold_* functions:

- Introduce new function that handles promting for dangerous
  operations and aborts if user does not confirm operation.
- Replace use of bold_* functions with colorecho function.
- Refactor colorecho and colorprintf to share associative array with
  colors, and also support bold variants.
- Write documentation for the colorecho and colorprintf functions.

---

diff --git a/games/factorio_manager.sh b/games/factorio_manager.sh
index ae51ef7d4beb84cc160b577e53b9457b79110547..ac5156c4e9cadae074d43b7c941f085a50294c3a 100755
--- a/games/factorio_manager.sh
+++ b/games/factorio_manager.sh
@@ -228,6 +228,27 @@ else
     _bg_white=""
 fi
 
+# Make the colors available via an associative array as well.
+declare -A _text_colors=()
+
+_text_colors[black]="${_text_black}"
+_text_colors[blue]="${_text_blue}"
+_text_colors[cyan]="${_text_cyan}"
+_text_colors[green]="${_text_green}"
+_text_colors[purple]="${_text_purple}"
+_text_colors[red]="${_text_red}"
+_text_colors[white]="${_text_white}"
+_text_colors[yellow]="${_text_yellow}"
+
+_text_colors[boldblack]="${_text_bold}${_text_black}"
+_text_colors[boldblue]="${_text_bold}${_text_blue}"
+_text_colors[boldcyan]="${_text_bold}${_text_cyan}"
+_text_colors[boldgreen]="${_text_bold}${_text_green}"
+_text_colors[boldpurple]="${_text_bold}${_text_purple}"
+_text_colors[boldred]="${_text_bold}${_text_red}"
+_text_colors[boldwhite]="${_text_bold}${_text_white}"
+_text_colors[boldyellow]="${_text_bold}${_text_yellow}"
+
 # Set-up functions for printing coloured messages.
 function debug() {
     if [[ $debug != 0 ]]; then
@@ -251,6 +272,38 @@ function error() {
     echo "${_text_bold}${_text_red}[ERROR]${_text_reset}" "$@" >&2
 }
 
+#
+# Prints text in requested color to standard output. Behaves as thin
+# wrapper around the echo built-in.
+#
+# Two invocation variants with different arguments are
+# supported. First argument is the one that will determine what the
+# desired invocation is.
+#
+# Arguments (variant 1):
+#
+#   $1 (echo_options)
+#     Additional options to pass-in to echo. Must be a single argument
+#     with leading dash followed by echo's own options. E.g. "-ne".
+#
+#   $2 (color)
+#     Text color to use. Supported values: black, blue, cyan, green,
+#     purple, red, white, yellow.
+#
+#   $3 (text)
+#     Text to output.
+#
+#
+# Arguments (variant 2):
+#
+#   $1 (color)
+#     Text color to use. Supported values: black, blue, cyan, green,
+#     purple, red, white, yellow, boldblack, boldblue, boldcyan,
+#     boldgreen, boldpurple, boldred, boldwhite, boldyellow.
+#
+#   $2 (text)
+#     Text to output.
+#
 function colorecho() {
     local options="" color text
     local reset="$_text_reset"
@@ -263,24 +316,30 @@ function colorecho() {
     color="$1"
     text="$2"
 
-    declare -A colors=()
-
-    colors[black]="${_text_black}"
-    colors[red]="${_text_red}"
-    colors[green]="${_text_green}"
-    colors[yellow]="${_text_yellow}"
-    colors[blue]="${_text_blue}"
-    colors[purple]="${_text_purple}"
-    colors[cyan]="${_text_cyan}"
-    colors[white]="${_text_white}"
-
     if [[ -n $options ]]; then
-        echo "$options" "${colors[$color]}$text${reset}"
+        echo "$options" "${_text_colors[$color]}$text${reset}"
     else
-        echo "${colors[$color]}$text${reset}"
+        echo "${_text_colors[$color]}$text${reset}"
     fi
 }
 
+#
+# Prints text in requested color to standard output using printf
+# format string and arguments.. Behaves as thin wrapper around the
+# printf built-in.
+#
+# Arguments:
+#
+#   $1 (color)
+#     Text color to use. Supported values: black, blue, cyan, green,
+#     purple, red, white, yellow.
+#
+#   $2 (format_string)
+#     printf-compatible format string.
+#
+#   $3 .. $n
+#      Replacement values for the the format string.
+#
 function colorprintf() {
     local reset="$_text_reset"
 
@@ -288,34 +347,42 @@ function colorprintf() {
     local format="$2"
     shift 2
 
-    declare -A colors=()
-
-    colors[black]="${_text_black}"
-    colors[red]="${_text_red}"
-    colors[green]="${_text_green}"
-    colors[yellow]="${_text_yellow}"
-    colors[blue]="${_text_blue}"
-    colors[purple]="${_text_purple}"
-    colors[cyan]="${_text_cyan}"
-    colors[white]="${_text_white}"
-
-    printf "${colors[$color]}${format}${reset}" "$@"
+    printf "${_text_colors[$color]}${format}${reset}" "$@"
 }
 
-function warning_prompt() {
-    echo -n "${_text_bold}${_text_yellow}[WARN] ${_text_reset}" "$@"
-}
-
-function bold_green() {
-    echo -n "${_text_bold}${_text_green}$@${_text_reset}"
-}
+#
+# Presents user with a warning, asks user for confirmation to
+# continue, and terminates the script is confirmation is not provided
+# with designated exit code.
+#
+# This function can be used to request confirmation for dangerous
+# actions/operations (such as removal of large number of files etc).
+#
+# The user must type-in YES (with capital casing) to proceed.
+#
+# Arguments:
+#
+#   $1 (prompt_text)
+#     Text to prompt the user with.
+#
+#   $2 (abort_text)
+#     Text to show to user in case the operation was aborted by user.
+#
+#   $3 (exit_code)
+#     Exit code when terminating the proram.
+#
+function critical_confirmation() {
+    local prompt_text="$1"
+    local abort_text="$2"
+    local exit_code="$3"
 
-function bold_red() {
-    echo -n "${_text_bold}${_text_red}$@${_text_reset}"
-}
+    echo -n "${_text_bold}${_text_yellow}[WARN] ${_text_reset}" "${prompt_text} Type YES to confirm (default is no): "
+    read confirm
 
-function bold_blue() {
-    echo -n "${_text_bold}${_text_blue}$@${_text_reset}"
+    if [[ $confirm != "YES" ]]; then
+        error "$abort_text"
+        exit "$ERROR_GENERAL"
+    fi
 }
 
 #
@@ -1136,9 +1203,9 @@ elif [[ $command == list-backups ]]; then
 
     # Detect and show available backups to the user.
     if [[ ! -d $backup_directory ]] || ! ls "$backup_directory" | grep -q -E "^$backup_destination_name_pattern\$"; then
-        echo "No backups are available for instance $(bold_green $instance)."
+        echo "No backups are available for instance $(colorecho -n green "$instance")."
     else
-        echo "Available backups for instance $(bold_green $instance) (current version $(bold_green "$current_game_version"))."
+        echo "Available backups for instance $(colorecho -n green "$instance") (current version $(colorecho -n green "$current_game_version"))."
         echo
 
         for backup_destination in "$backup_directory"/*; do
@@ -1151,9 +1218,9 @@ elif [[ $command == list-backups ]]; then
 
                 if [[ -f "$backup_destination/.description" ]]; then
                     backup_description=$(<"$backup_destination/.description")
-                    echo "  - $backup_date - version $(bold_green "$game_version") ($backup_description)"
+                    echo "  - $backup_date - version $(colorecho -n green "$game_version") ($backup_description)"
                 else
-                    echo "  - $backup_date - version $(bold_green "$game_version")"
+                    echo "  - $backup_date - version $(colorecho -n green "$game_version")"
                 fi
 
 
@@ -1252,7 +1319,7 @@ elif [[ $command == restore ]]; then
         else
             backup_info="$backup_name"
         fi
-        echo "Restore instance $(bold_green "$instance") from backup: $(bold_green "$backup_info")"
+        echo "Restore instance $(colorecho -n green "$instance") from backup: $(colorecho -n green "$backup_info")"
         echo
 
         # Show user what files will be removed.
@@ -1269,13 +1336,9 @@ elif [[ $command == restore ]]; then
         fi
 
         # Request from user to confirm the operation.
-        warning_prompt "Are you sure you want to proceed? Type YES to confirm (default is no): "
-        read confirm
-
-        if [[ $confirm != "YES" ]]; then
-            error "Aborted restore process, no changes have been made to instance files."
-            exit "$ERROR_GENERAL"
-        fi
+        critical_confirmation "Are you sure you want to proceed?" \
+                              "Aborted restore process, no changes have been made to instance files." \
+                              "$ERROR_GENERAL"
 
         if [[ ${#entries_to_remove[@]} != 0 ]]; then
             if ! rm -rf "${entries_to_remove[@]}"; then
@@ -1353,9 +1416,9 @@ elif [[ $command == remove-backup ]]; then
 
     warning "You are about to remove an instance backup. All files belonging to specified backup will be removed."
     echo
-    echo "Instance: $(bold_green "$instance")"
+    echo "Instance: $(colorecho -n green "$instance")"
     echo
-    echo "Backup: $(bold_green "$backup_info")"
+    echo "Backup: $(colorecho -n green "$backup_info")"
     echo
     echo "Files and directories that will be removed:"
     echo
@@ -1363,13 +1426,9 @@ elif [[ $command == remove-backup ]]; then
     echo
 
     # Request from user to confirm the operation.
-    warning_prompt "Are you sure you want to proceed? Type YES to confirm (default is no): "
-    read confirm
-
-    if [[ $confirm != "YES" ]]; then
-        error "Aborted backup removal, no changes have been made to backup files."
-        exit "$ERROR_GENERAL"
-    fi
+    critical_confirmation "Are you sure you want to proceed?" \
+                          "Aborted backup removal, no changes have been made to backup files." \
+                          "$ERROR_GENERAL"
 
     if ! rm -rf "$removal_target"; then
         error "Failed to remove existing instance files."
@@ -1432,7 +1491,7 @@ elif [[ $command == set-version ]]; then
         if [[ -f $candidate/bin/x64/factorio ]]; then
             candidate_version=$(basename "$candidate")
             if [[ $candidate_version == $game_version ]]; then
-                echo "  - $candidate_version $(bold_green "[current]")"
+                echo "  - $candidate_version $(colorecho -n green "[current]")"
             else
                 echo "  - $candidate_version"
             fi
@@ -1442,7 +1501,7 @@ elif [[ $command == set-version ]]; then
     echo
 
     # Display current version.
-    echo "Current version used for instance $(bold_green "$instance") is $(bold_green "$game_version")."
+    echo "Current version used for instance $(colorecho -n green "$instance") is $(colorecho -n green "$game_version")."
     echo
     read -p "Please specify what version you would like to use (enter to keep current): " game_version_selected
 
@@ -1461,7 +1520,7 @@ elif [[ $command == set-version ]]; then
         info "Current version has been kept."
     else
         sed -i -e "s/^game_version=.*/game_version=$game_version_selected/" "$instance_config"
-        success "Version changed to: $(bold_green "$game_version_selected")"
+        success "Version changed to: $(colorecho -n green "$game_version_selected")"
     fi
 
 #======#
@@ -1510,15 +1569,15 @@ elif [[ $command == info ]]; then
     source "$instance_config"
 
     # Basic information.
-    echo "Instance name: $(bold_green "$instance")"
+    echo "Instance name: $(colorecho -n green "$instance")"
 
     if [[ -e "$game_installations_directory/$game_version" ]]; then
-        echo "Game version: $(bold_green "$game_version")"
+        echo "Game version: $(colorecho -n green "$game_version")"
     else
-        echo "Game version: $(bold_red "$game_version [not available locally]")"
+        echo "Game version: $(colorecho -n red "$game_version [not available locally]")"
     fi
 
-    echo "Instance path: $(bold_green "$instance_directory")"
+    echo "Instance path: $(colorecho -n green "$instance_directory")"
     echo
 
     # Mod information.
@@ -1703,18 +1762,14 @@ elif [[ $command == remove ]]; then
 
         # Display instance information.
         source "$instance_config"
-        echo "Instance name:    $(bold_green "$instance")"
-        echo "Instance version: $(bold_green "$game_version")"
+        echo "Instance name:    $(colorecho -n green "$instance")"
+        echo "Instance version: $(colorecho -n green "$game_version")"
         echo
 
         # Request from user to confirm the operation.
-        warning_prompt "Are you sure you want to proceed? Type YES to confirm (default is no): "
-        read confirm
-
-        if [[ $confirm != "YES" ]]; then
-            error "Aborted instance removal, no changes have been made to instance files."
-            exit "$ERROR_GENERAL"
-        fi
+        critical_confirmation "Are you sure you want to proceed?" \
+                              "Aborted instance removal, no changes have been made to instance files." \
+                              "$ERROR_GENERAL"
 
         if [[ ${#entries_to_remove[@]} != 0 ]]; then
             if ! rm -rf "${entries_to_remove[@]}"; then
@@ -1825,7 +1880,7 @@ elif [[ $command == copy ]]; then
             if [[ -f $candidate/bin/x64/factorio ]]; then
                 candidate_version=$(basename "$candidate")
                 if [[ $candidate_version == $game_version ]]; then
-                    echo "  - $candidate_version $(bold_green "[current]")"
+                    echo "  - $candidate_version $(colorecho -n green "[current]")"
                 else
                     echo "  - $candidate_version"
                 fi
@@ -1834,7 +1889,7 @@ elif [[ $command == copy ]]; then
         echo
 
         # Display current version.
-        echo "Current version used for instance $(bold_green "$source_instance") is $(bold_green "$game_version")."
+        echo "Current version used for instance $(colorecho -n green "$source_instance") is $(colorecho -n green "$game_version")."
         echo
         read -p "Please specify what version you would like to use for new instance (press enter to keep the current version): " game_version_selected
 
@@ -1882,7 +1937,7 @@ elif [[ $command == copy ]]; then
 
         sed -i -e "s/^game_version=.*/game_version=$game_version_selected/" "$destination_instance_config"
 
-        success "Created new instance $(bold_green "$destination_instance") using version $(bold_green "$game_version_selected") as copy of instance $(bold_green "$source_instance")."
+        success "Created new instance $(colorecho -n green "$destination_instance") using version $(colorecho -n green "$game_version_selected") as copy of instance $(colorecho -n green "$source_instance")."
 
     ) 200>"$source_lock_file"
 
@@ -2005,7 +2060,7 @@ elif [[ $command == import ]]; then
         for source_entry in "${import_entries_keys[@]}"; do
             source_entry_path="$source_directory/$source_entry"
             if [[ -e $source_entry_path ]]; then
-                info "Importing $(bold_blue "$source_entry")..."
+                info "Importing $(colorecho -n blue "$source_entry")..."
 
                 if ! cp -a "$source_entry_path" "$instance_directory/"; then
                     error "Could not import $source_entry from $source_entry_path (see above for errors)."
@@ -2033,14 +2088,14 @@ EOF
             warning "For some of the entries this is perfectly normal, but you should verify that no critical files have been missed by mistake before switching to using this instance."
             echo
             for missing_import_entry in "${missing_import_entries[@]}"; do
-                echo "$(bold_blue "$missing_import_entry"), ${import_entries[$missing_import_entry]}"
+                echo "$(colorecho blue "$missing_import_entry"), ${import_entries[$missing_import_entry]}"
                 echo
             done
             warning "Press any key to continue."
             read -n1
         fi
 
-        success "Finished import of instance $(bold_green "$instance")."
+        success "Finished import of instance $(colorecho -n green "$instance")."
 
     ) 200>"$source_lock_file"
 
@@ -2228,7 +2283,7 @@ EOF
         exit "$ERROR_GENERAL"
     fi
 
-    success "Created new server instance $(bold_green "$instance")"
+    success "Created new server instance $(colorecho -n green "$instance")"
 else
     error "Invalid command: $command"