Changeset - 8cd955bce0d2
[Not reviewed]
0 1 0
Branko Majic (branko) - 4 years ago 2020-07-05 00:32:20
branko@majic.rs
Noticket: Refactor validation of server settings in Factorio Manager:

- Introduce dedicated validation function.
- Drop some unused variables.
- Validate settings while they are being prepared for the JSON file.
1 file changed with 88 insertions and 35 deletions:
0 comments (0 inline, 0 general) First comment
games/factorio_manager.sh
Show inline comments
 
@@ -382,12 +382,90 @@ function critical_confirmation() {
 
    if [[ $confirm != "YES" ]]; then
 
        error "$abort_text"
 
        exit "$ERROR_GENERAL"
 
    fi
 
}
 

	
 
#
 
# Validates that the specified value conforms to designated setting.
 
#
 
# This is a small helper function used within read_server_settings
 
# function to validate the settings.
 
#
 
# Arguments:
 
#
 
#   $1 (name)
 
#     Name of the setting. Used to show erros to the user.
 
#
 
#   $2 (value)
 
#     Value to validate.
 
#
 
#   $3 (type)
 
#
 
#     Value type. Currently supports the following types:
 
#
 
#       - bool (boolean)
 
#       - int (integer/number)
 
#       - str (string, essentially anything can pass this validation)
 
#       - list (space-separated list of strings, essentially anything
 
#         can pass this validation)
 
#       - VAL_1|...|VAL_N (choice between different values)
 
#
 
#     When using the VAL_1|...|VAL_N variant, validation is slightly
 
#     relaxed for string values to allow both quoted and unquoted
 
#     variants. For example, if type was set to true|false|"admins",
 
#     then both 'admin' and '"admins"' will validate successfully
 
#     against the type.
 
#
 
# Returns:
 
#
 
#   0 if validation has passed, 1 if validation failed, and 2 if
 
#   passed-in type is not supported.
 
#
 
function validate_server_setting_value() {
 
    local name="$1"
 
    local value="$2"
 
    local type="$3"
 

	
 
    declare -a possible_values
 

	
 
    local i
 

	
 
    # Assume failure.
 
    local result=1
 

	
 
    if [[ $type == "bool" ]]; then
 
        [[ $value == true || $value == false ]] && result=0 || colorecho "red" "$name must be a boolean [true|false]."
 

	
 
    elif [[ $type == "int" ]]; then
 
        [[ $value =~ ^[[:digit:]]+$ ]] && result=0 || colorecho "red" "$name must be a number."
 

	
 
    elif [[ $type == "str" ]]; then
 
        result=0
 

	
 
    elif [[ $type == "list" ]]; then
 
        # This is free-form space-delimited list.
 
        result=0
 

	
 
    elif [[ $type =~ ^.+\|.+$ ]]; then
 
        readarray -d "|" -t possible_values < <(echo -n "$type")
 

	
 
        for i in "${possible_values[@]}"; do
 
            # Allow strings without quotes to be specified by the user.
 
            [[ $value == $i || \"$value\" == $i ]] && result=0
 
        done
 

	
 
        [[ $result == 0 ]] || colorecho red "$name must be one of listed values [$type]."
 
    else
 
        error "Unsupported type associated with '$name': $type"
 
        result=2
 
    fi
 

	
 
    return "$result"
 
}
 

	
 
#
 
# Prompts user to provide settings for a server instance.
 
#
 
# Function will go over a number of questions, providing a set of
 
# default values, and allowing the user to edit them in-place. Once
 
# all questions have been answered, user is presented with summary and
 
@@ -429,16 +507,14 @@ function read_server_settings() {
 
    # Local helper variables.
 
    local key="" value="" prompt="" confirmed="" item="" validation_passed possible_values i
 

	
 
    declare -A settings_prompt=()
 
    declare -A settings_description=()
 
    declare -A settings_type=()
 
    declare -A option=()
 

	
 
    declare -a settings_order=()
 
    declare -a possible_options=()
 

	
 
    # Global variables set by the function.
 
    declare -g -A settings_value=()
 

	
 
    # Set-up listings of server settings. Each setting is described
 
    # with name, prompt, description, default value, and
 
@@ -692,62 +768,39 @@ function read_server_settings() {
 
                prompt=$(colorprintf "green" "%02d/%02d ${prompt} " "$current_question" "$total_questions")
 

	
 
                # Show setting description.
 
                colorecho "white" "${settings_description[$key]}" | fold -s
 

	
 
                # Keep prompting user until a valid value is provided.
 
                validation_passed=false
 
                until [[ $validation_passed == true ]]; do
 
                validation_result=""
 
                until [[ $validation_result == 0 ]]; do
 

	
 
                    read -p "$prompt" -e -i "${settings_value[$key]}" value
 

	
 
                    if [[ ${settings_type[$key]} == "bool" ]]; then
 
                        [[ $value == true || $value == false ]] && validation_passed=true || colorecho "red" "Value must be boolean [true|false]."
 

	
 
                    elif [[ ${settings_type[$key]} == "int" ]]; then
 
                        [[ $value =~ ^[[:digit:]]+$ ]] && validation_passed=true || colorecho "red" "Value must be a number."
 

	
 
                    elif [[ ${settings_type[$key]} == "str" ]]; then
 
                        validation_passed=true
 

	
 
                    elif [[ ${settings_type[$key]} == "list" ]]; then
 
                        # This is free-form space-delimited list.
 
                        validation_passed=true
 

	
 
                    elif [[ ${settings_type[$key]} =~ ^.+\|.+$ ]]; then
 
                        readarray -d "|" -t possible_values < <(echo -n "${settings_type[$key]}")
 

	
 
                        for i in "${possible_values[@]}"; do
 
                            [[ $value == $i ]] && validation_passed=true
 

	
 
                            # Convenience for allowing strings without quotes specified by the user.
 
                            [[ \"$value\" == $i ]] && value="\"$value\"" && validation_passed=true
 
                        done
 

	
 
                        [[ $validation_passed == true ]] || colorecho red "Value must be one of selection [${settings_type[$key]}]"
 
                    else
 
                        error "Unsupported type: ${settings_type[$key]}"
 
                        return 1
 
                    fi
 
                    validate_server_setting_value "${settings_prompt[$key]}" "$value" "${settings_type[$key]}"
 
                    validation_result="$?"
 
                    [[ $validation_result == 2 ]] && error "Internal error, type not set correctly for setting: $key." && exit "$ERROR_GENERAL"
 
                done
 

	
 
                settings_value[$key]="$value"
 

	
 
                echo
 
                let current_question++
 
            done
 
        fi
 
    done
 

	
 
    # Prepare values so they can be used within the JSON file.
 
    #
 
    # @TODO: Perform same validation as for user input (since script
 
    # itself could have a typo).
 
    for key in "${settings_order[@]}"; do
 
        debug "Raw value for $key: ${settings_value[$key]}"
 

	
 
        if ! validate_server_setting_value "$key (${settings_prompt[$key]})" "${settings_value[$key]}" "${settings_type[$key]}"; then
 
            error "Failed to validate the settings value. This is most likely an internal bug in $program."
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        if [[ ${settings_type[$key]} == "str" ]]; then
 
            settings_value[$key]="\"${settings_value[$key]}\""
 

	
 
        # Used for selecting between multiple values.
 
        elif [[ ${settings_type[$key]} =~ ^.+\|.+$ ]]; then
 
            readarray -d "|" -t possible_values < <(echo -n "${settings_type[$key]}")
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now