Changeset - 8551913bda80
[Not reviewed]
0 1 0
Branko Majic (branko) - 5 years ago 2020-07-05 15:50:03
branko@majic.rs
Noticket: Implement additional path validations for Factorio Manager:

- Added test for instance directories, new backup directories, backup
directories, and import sources.
- Refactored commands to use the new path validations.
- Updated some comments and formatting.
1 file changed with 156 insertions and 190 deletions:
0 comments (0 inline, 0 general)
games/factorio_manager.sh
Show inline comments
 
@@ -834,28 +834,40 @@ function read_server_settings() {
 
# Arguments:
 
#
 
#   $1 (path_test)
 
#     Test to apply against the path. Supported tests are:
 
#
 
#       game_installations_directory
 
#         Checks if path contains Factorio installations in
 
#         sub-directories.
 
#
 
#       instance_directory_new
 
#         Checks if path is unused and can be used for new instance.
 
#
 
#       instance_directory
 
#         Checks if path contains a valid instance.
 
#
 
#       backup_directory_new
 
#         Checks if path is usable as destination for a new backup.
 
#
 
#       backup_directory
 
#         Checks if path contains a valid backup.
 
#
 
#       instance_import_source
 
#         Checks if path is usable as source for importing an instance.
 
#
 
#   $2 (path)
 
#     Path that should be validated.
 
#
 
#   $3 (exit_code0
 
#   $3 (exit_code)
 
#     Exit code to use when terminating the program.
 
#
 
# Exits:
 
#
 
#   If the path type is unsupported, or if the specified path does not
 
#   conform to requirements for the specified path type.
 
#
 
function validate_path_or_terminate() {
 
    local path_test="$1"
 
    local path="$2"
 
    local exit_code="$3"
 

	
 
@@ -868,24 +880,75 @@ function validate_path_or_terminate() {
 
        fi
 

	
 
    elif [[ $path_test == "instance_directory_new" ]]; then
 
        if [[ -e $path/config.ini ]]; then
 
            error "Instance already exists."
 
            exit "$exit_code"
 
        fi
 

	
 
        if [[ -e $path ]]; then
 
            error "Instance directory already exists, but does not contain a valid Factorio instance: $path."
 
            exit "$exit_code"
 
        fi
 

	
 
    elif [[ $path_test == "instance_directory" ]]; then
 
        if [[ ! -d $path ]]; then
 
            error "Missing instance directory: $path"
 
            error "Perhaps you have misstyped the instance name or forgot to create one first?"
 
            exit "$exit_code"
 
        fi
 

	
 
        if [[ ! -f $path/instance.conf ]]; then
 
            error "Missing instance configuration file: $path/instance.conf"
 
            exit "$exit_code"
 
        fi
 

	
 
        if [[ ! -f $path/config.ini ]]; then
 
            error "Missing game configuration file: $path/config.ini"
 
            exit "$exit_code"
 
        fi
 

	
 
    elif [[ $path_test == "backup_directory_new" ]]; then
 
        if [[ -e $path/config.ini ]]; then
 
            error "Backup already exists under directory: $path"
 
            exit "$exit_code"
 
        elif [[ -e $path ]]; then
 
            error "Backup directory already exists, but does not contain a valid backup: $path"
 
            exit "$exit_code"
 
        fi
 

	
 
    elif [[ $path_test == "backup_directory" ]]; then
 

	
 
        if [[ ! -d $path ]]; then
 
            error "Specified backup not available under: $path"
 
            exit "$ERROR_ARGUMENTS"
 
        fi
 

	
 
        if [[ ! -f $path/instance.conf ]]; then
 
            error "Backup missing instance configuration file: $path/instance.conf"
 
            exit "$exit_code"
 
        fi
 

	
 
        if [[ ! -f $path/config.ini ]]; then
 
            error "Backup missing game configuration file: $path/config.ini"
 
            exit "$exit_code"
 
        fi
 

	
 
    elif [[ $path_test == "instance_import_source" ]]; then
 
        if [[ ! -f $path/bin/x64/factorio ]]; then
 
            error "Could not locate Factorio binary in directory under: $path/bin/x64/factorio"
 
            error "Factorio Manager natively supports instance imports only when all game data (savegames etc) are stored within Factorio installation directory."
 
            exit "$ERROR_ARGUMENTS"
 
        fi
 

	
 
    else
 
        error "Unable to validate path '$path', unsupported test requested: '$path_test'."
 
        exit "$ERROR_GENERAL"
 
    fi
 
}
 

	
 
#
 
# Prompts user to pick version of Factorio.
 
#
 
# Arguments:
 
#
 
#   $1 (game_installations_directory)
 
@@ -1001,24 +1064,25 @@ done
 
i=$OPTIND
 
shift $(($i-1))
 

	
 
# Make sure the manager home directory exists.
 
if [[ ! -e $manager_directory ]]; then
 
    info "Creating Factorio Manager home directory under: $manager_directory"
 
    mkdir -p "$manager_directory"
 
fi
 

	
 
command="$1"
 
shift
 

	
 

	
 
#==============#
 
# set-game-dir #
 
#==============#
 
if [[ $command == set-game-dir ]]; then
 

	
 
    # Read and verify additional positional arguments.
 
    game_installations_directory_target="${1-}"
 
    shift
 

	
 
    if [[ -z $game_installations_directory_target ]]; then
 
        error "Missing argument: GAME_INSTALLATIONS_DIRECTORY"
 
        exit "$ERROR_ARGUMENTS"
 
@@ -1045,79 +1109,90 @@ if [[ $command == set-game-dir ]]; then
 

	
 
    # Update the link
 
    if [[ -L $game_installations_directory ]]; then
 
        rm "$game_installations_directory"
 
    fi
 

	
 
    if ! ln -s "$game_installations_directory_target" "$game_installations_directory"; then
 
        error "Could not create symlink from '$game_installations_directory_target' to '$game_installations_directory'."
 

	
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 

	
 
#==========#
 
# versions #
 
#==========#
 
elif [[ $command == versions ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    echo "Locally available Factorio versions:"
 
    echo
 

	
 
    # Find all sub-directories that are Factorio installations.
 
    for candidate in "$game_installations_directory"/*; do
 
        if [[ -d $candidate && -e $candidate/bin/x64/factorio ]]; then
 
            echo "  - $(basename "$candidate")"
 
        fi
 
    done
 
    echo
 

	
 

	
 
#======#
 
# list #
 
#======#
 
elif [[ $command == list ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    echo "Available instances:"
 
    echo
 

	
 
    # Find all sub-directories that are valid instances.
 
    for candidate in "$manager_directory"/*; do
 
        if [[ -f $candidate/instance.conf ]]; then
 
            source "$candidate/instance.conf"
 
            echo "  - $(basename "$candidate") ($game_version)"
 
        fi
 
    done
 
    echo
 

	
 

	
 
#========#
 
# create #
 
#========#
 
elif [[ $command == create ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Calculate derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 

	
 
    # Verify arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Make sure new instance directory can be used.
 
    validate_path_or_terminate "instance_directory_new" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    select_factorio_version "$game_installations_directory" || exit "$ERROR_GENERAL"
 

	
 
    # Set-up the instance.
 
    mkdir "$instance_directory"
 
    mkdir "$instance_directory/mods"
 
    echo "{}" > "$instance_directory/mods/mod-list.json"
 

	
 
    cat <<EOF > "$instance_config"
 
game_version="$game_version_selected"
 
EOF
 
@@ -1150,55 +1225,55 @@ enable-crash-log-uploading=false
 

	
 
[multiplayer-lobby]
 

	
 
[graphics]
 
EOF
 

	
 
    echo
 
    warning "Factorio Manager has created a minimal empty configuration file for Factorio under $game_config."
 
    warning "Since the generated configuration file is almost empty, Factorio will complain that the file seems corrupt."
 
    warning "Factorio will offer to fix the corrupted configuration file by filling-in the missing information during the first startup."
 
    warning "It should be safe to accept this. This warning will be shown by Factorio only the first time."
 

	
 

	
 
#========#
 
# launch #
 
#========#
 
elif [[ $command == launch ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Set-up derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 
    server_config="$instance_directory/server-settings.json"
 

	
 
    # Verify arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ ! -f $instance_config ]]; then
 
        error "Missing instance configuration file: $instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $game_config ]]; then
 
        error "Missing game configuration file: $game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Update instance write directory prior to launching - this is a
 
    # failsafe in case it got changed by hand through some other means
 
    # (or maybe it was copied over from another instance).
 
    # failsafe in case it got changed by hand or perhaps the value
 
    # comes from backups of a copied instance.
 
    current_write_data=$(grep "^write-data=" "$game_config")
 
    expected_write_data="write-data=${instance_directory}"
 

	
 
    if [[ $current_write_data != $expected_write_data ]]; then
 
        warning "Incorrect path specified for write-data in game configuration file: $game_config"
 
        warning "Current configuration is: $current_write_data"
 
        warning "Configuration will be replaced with: $expected_write_data"
 
        sed -i -e "s#^write-data=.*#$expected_write_data#" "$game_config"
 
    fi
 

	
 
    # Read launcher configuration for the instance.
 
    source "$instance_config"
 
@@ -1218,65 +1293,62 @@ elif [[ $command == launch ]]; then
 
        error "Factorio $game_version installation may have been removed from game installations directory:"
 
        error "   $(readlink -f "$game_installations_directory")"
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 

	
 
    # Launch instance
 
    if [[ -e $server_config ]]; then
 
        "$factorio_bin" --config "$game_config" --start-server "$instance_directory/saves/default.zip"
 
    else
 
        "$factorio_bin" --config "$game_config"
 
    fi
 

	
 

	
 
#========#
 
# backup #
 
#========#
 
elif [[ $command == backup ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    description="${2-}"
 
    shift 2
 

	
 
    # Use timestamp-based names for backups.
 
    timestamp=$(date +%Y-%m-%d_%H:%M:%S)
 

	
 
    # Set-up derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 
    lock_file="$instance_directory/.lock"
 

	
 
    backup_directory="$instance_directory/.bak"
 
    backup_destination="$backup_directory/$timestamp"
 
    backup_description="$backup_destination/.description"
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Verify that we are trying to backup an actual instance.
 
    if [[ ! -f $instance_config ]]; then
 
        error "Missing instance configuration file: $instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $game_config ]]; then
 
        error "Missing game configuration file: $game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Make sure we do not overwrite the backup destination by mistake
 
    # - although highly unlikely unless user spams the backup command.
 
    if [[ -e $backup_destination ]]; then
 
        error "Backup already exists: $backup_destination"
 
    fi
 
    # Validate destination path for backup directory can be used.
 
    validate_path_or_terminate "backup_directory_new" "$backup_destination" "$ERROR_GENERAL"
 

	
 
    (
 

	
 
        # Obtain lock - Factorio uses the same mechanism, so we should
 
        # be able to detect the game is running in this way.
 
        flock --exclusive --nonblock 200
 
        if [[ $? != 0 ]]; then
 
            error "Could not lock instance directory via lock file $lock_file. Is Factorio instance still running?"
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        function remove_lock() {
 
@@ -1293,60 +1365,48 @@ elif [[ $command == backup ]]; then
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        # Store (optional) description.
 
        if [[ -n $description ]]; then
 
            echo "$description" > "$backup_description"
 
        fi
 

	
 
        success "Backup saved to: $backup_destination"
 

	
 
    ) 200>"$lock_file"
 

	
 

	
 
#==============#
 
# list-backups #
 
#==============#
 
elif [[ $command == list-backups ]]; then
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Set-up derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 
    backup_directory="$instance_directory/.bak"
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Verify instance.
 
    if [[ ! -d $instance_directory ]]; then
 
        error "No such instance: $instance"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ ! -f $instance_config ]]; then
 
        error "Missing instance configuration file: $instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $game_config ]]; then
 
        error "Missing game configuration file: $game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Extended regular expression for matching YYYY-MM-DD-hh:mm:ss format.
 
    backup_destination_name_pattern="[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}_[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}"
 

	
 
    # Read current game version.
 
    source "$instance_config"
 
    current_game_version="$game_version"
 
    unset game_version
 

	
 
    # 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 $(colorecho -n green "$instance")."
 
@@ -1368,72 +1428,61 @@ elif [[ $command == list-backups ]]; then
 
                else
 
                    echo "  - $backup_date - version $(colorecho -n green "$game_version")"
 
                fi
 

	
 

	
 
            fi
 
        done
 

	
 
        echo
 

	
 
    fi
 

	
 

	
 
#=========#
 
# restore #
 
#=========#
 
elif [[ $command == restore ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    backup_name="${2-}"
 
    shift 2
 

	
 
    # Set-up derived values.
 
    instance_directory="$manager_directory/$instance"
 
    restore_source="$instance_directory/.bak/$backup_name"
 
    backup_instance_config="$restore_source/instance.conf"
 
    backup_game_config="$restore_source/config.ini"
 
    lock_file="$instance_directory/.lock"
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ -z $backup_name ]]; then
 
        error "Missing argument: BACKUP_NAME"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Verify we are working with legitimate instance and backup.
 
    if [[ ! -d $instance_directory ]]; then
 
        error "No such instance: $instance"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ ! -d $restore_source ]]; then
 
        error "Specified backup not available under: $restore_source"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    if [[ ! -f $backup_instance_config ]]; then
 
        error "Invalid backup, missing instance configuration file: $backup_instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $backup_game_config ]]; then
 
        error "Invalid backup, missing game configuration file: $backup_game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that backup directory contains valid backup.
 
    validate_path_or_terminate "backup_directory" "$restore_source" "$ERROR_ARGUMENTS"
 

	
 
    (
 
        # Obtain lock - Factorio uses the same mechanism, so we should
 
        # be able to detect the game is running in this way.
 
        flock --exclusive --nonblock 200
 
        if [[ $? != 0 ]]; then
 
            error "Could not lock instance directory via lock file $lock_file. Is Factorio instance still running?"
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        function remove_lock() {
 
            rm "$lock_file"
 
@@ -1493,72 +1542,61 @@ elif [[ $command == restore ]]; then
 
            fi
 
        fi
 

	
 
        if ! cp -a "$restore_source"/* "$instance_directory"; then
 
            error "Failed to restore backup from: $restore_source"
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        success "Instance restored from backup."
 

	
 
    ) 200>"$lock_file"
 

	
 

	
 
#===============#
 
# remove-backup #
 
#===============#
 
elif [[ $command == remove-backup ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    backup_name="${2-}"
 
    shift 2
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ -z $backup_name ]]; then
 
        error "Missing argument: BACKUP_NAME"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Set-up derived values.
 
    instance_directory="$manager_directory/$instance"
 
    removal_target="$instance_directory/.bak/$backup_name"
 
    backup_instance_config="$removal_target/instance.conf"
 
    backup_game_config="$removal_target/config.ini"
 
    lock_file="$instance_directory/.lock"
 

	
 
    # Verify we are working with legitimate instance and backup.
 
    if [[ ! -d $instance_directory ]]; then
 
        error "No such instance: $instance"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    if [[ ! -d $removal_target ]]; then
 
        error "Specified backup not available under: $removal_target"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ ! -f $backup_instance_config ]]; then
 
        error "Invalid backup, missing instance configuration file: $backup_instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $backup_game_config ]]; then
 
        error "Invalid backup, missing game configuration file: $backup_game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that backup directory contains valid backup.
 
    validate_path_or_terminate "backup_directory" "$removal_target" "$ERROR_ARGUMENTS"
 

	
 
    # Present user with warning.
 
    echo
 
    if [[ -f "$removal_target/.description" ]]; then
 
        backup_description=$(<"$removal_target/.description")
 
        backup_info="$backup_name ($backup_description)"
 
    else
 
        backup_info="$backup_name"
 
    fi
 

	
 
    warning "You are about to remove an instance backup. All files belonging to specified backup will be removed."
 
    echo
 
@@ -1574,124 +1612,94 @@ elif [[ $command == remove-backup ]]; then
 
    # Request from user to confirm the operation.
 
    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."
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    success "Backup removed."
 

	
 

	
 
#=============#
 
# set-version #
 
#=============#
 
elif [[ $command == set-version ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Make sure user has set directory with game installations - test
 
    # both symlink and target destination.
 
    if [[ ! -L $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 

	
 
    if [[ ! -d $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 

	
 
    # Set-up derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 

	
 
    # Verify we are working with legitimate instance.
 
    if [[ ! -f $instance_config ]]; then
 
        error "Missing instance configuration file: $instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $game_config ]]; then
 
        error "Missing game configuration file: $game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Load instance configuration.
 
    source "$instance_config"
 

	
 
    # Display list of available Factorio versions.
 
    echo "Current version used for instance $(colorecho -n green "$instance") is $(colorecho -n green "$game_version")."
 
    echo
 
    select_factorio_version "$game_installations_directory" "$game_version" "current" || exit "$ERROR_GENERAL"
 
    echo
 

	
 
    # Change instance game version.
 
    if [[ $game_version_selected == $game_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: $(colorecho -n green "$game_version_selected")"
 
    fi
 

	
 

	
 
#======#
 
# info #
 
#======#
 
elif [[ $command == info ]]; then
 
    # Make sure user has set directory with game installations - test
 
    # both symlink and target destination.
 
    if [[ ! -L $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 

	
 
    if [[ ! -d $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Set-up derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 

	
 
    # Verify we are working with legitimate instance.
 
    if [[ ! -f $instance_config ]]; then
 
        error "Missing instance configuration file: $instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $game_config ]]; then
 
        error "Missing game configuration file: $game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Load instance configuration.
 
    source "$instance_config"
 

	
 
    # Basic information.
 
    echo "Instance name: $(colorecho -n green "$instance")"
 

	
 
    if [[ -e "$game_installations_directory/$game_version" ]]; then
 
        echo "Game version: $(colorecho -n green "$game_version")"
 
    else
 
        echo "Game version: $(colorecho -n red "$game_version [not available locally]")"
 
    fi
 
@@ -1699,25 +1707,25 @@ elif [[ $command == info ]]; then
 
    echo "Instance path: $(colorecho -n green "$instance_directory")"
 
    echo
 

	
 
    # Mod information.
 
    shopt -s nullglob
 
    mod_files=($instance_directory/mods/*.zip)
 
    mod_list="$instance_directory/mods/mod-list.json"
 
    shopt -u nullglob
 

	
 
    if [[ ${#mod_files[@]} == 0 ]]; then
 
        echo "Available mods: none"
 

	
 
    # Plain listing.
 
    # Listing using just regular tools.
 
    elif ! hash jqs 2>/dev/null; then
 
        echo "Available mods:"
 
        echo
 

	
 
        # Determine if mod is enabled by default or not when added to
 
        # mods directory (and is not yet listed in the mod list file).
 
        if grep -i -q "^[[:blank:]]*enable-new-mods=false" "$game_config"; then
 
            enable_new_mods="false"
 
        else
 
            enable_new_mods="true"
 
        fi
 

	
 
@@ -1739,25 +1747,25 @@ elif [[ $command == info ]]; then
 
                elif [[ $enable_new_mods == "false" ]]; then
 
                    color="$_text_yellow"
 
                else
 
                    color=""
 
                fi
 

	
 
                # Show colored-information for the mod.
 
                printf "$color  - %-48s %8s $_text_reset\n" "$mod_name" "$mod_version"
 
            fi
 

	
 
        done
 

	
 
    # Fancy listing with detection for enabled mods using jq.
 
    # Listing using the jq utility.
 
    elif hash jq 2>/dev/null; then
 
        echo "Available mods (enabled/${_text_yellow}disabled${_text_reset}):"
 
        echo
 

	
 
        # Determine if mod is enabled by default or not when added to
 
        # mods directory (and is not yet listed in the mod list file).
 
        if grep -i -q "^[[:blank:]]*enable-new-mods=false" "$game_config"; then
 
            enable_new_mods="false"
 
        else
 
            enable_new_mods="true"
 
        fi
 

	
 
@@ -1795,49 +1803,44 @@ elif [[ $command == info ]]; then
 
    fi
 
    echo
 

	
 
    # Call self for displaying list of backups. Better than duplicating code.
 
    "$program" list-backups "$instance" | sed -e "s/^Available backups for instance.*/Available backups:/"
 

	
 

	
 
#========#
 
# remove #
 
#========#
 
elif [[ $command == remove ]]; then
 

	
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Set-up derived values.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    lock_file="$instance_directory/.lock"
 

	
 
    # Verify we are working with legitimate instance and backup.
 
    if [[ ! -d $instance_directory ]]; then
 
        error "No such instance: $instance"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ ! -f $instance_config ]]; then
 
        error "Missing instance configuration file: $instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    (
 
        # Obtain lock - Factorio uses the same mechanism, so we should
 
        # be able to detect the game is running in this way.
 
        flock --exclusive --nonblock 200
 
        if [[ $? != 0 ]]; then
 
            error "Could not lock instance directory via lock file $lock_file. Is Factorio instance still running?"
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        # Removing lock file will most likely fail if we manage to
 
        # remove the instance.
 
@@ -1903,35 +1906,26 @@ elif [[ $command == remove ]]; then
 
        fi
 

	
 
        success "Instance removed."
 

	
 
    ) 200>"$lock_file"
 

	
 

	
 
#======#
 
# copy #
 
#======#
 
elif [[ $command == copy ]]; then
 

	
 
    # Make sure user has set directory with game installations - test
 
    # both symlink and target destination.
 
    if [[ ! -L $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 

	
 
    if [[ ! -d $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    source_instance="${1-}"
 
    destination_instance="${2-}"
 
    shift 2
 

	
 
    # Verify positional arguments.
 
    if [[ -z $source_instance ]]; then
 
        error "Missing argument: SOURCE_INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
@@ -1940,40 +1934,28 @@ elif [[ $command == copy ]]; then
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Calculate derived variables.
 
    source_instance_directory="$manager_directory/$source_instance"
 
    source_instance_config="$source_instance_directory/instance.conf"
 
    source_game_config="$source_instance_directory/config.ini"
 
    source_lock_file="$source_instance_directory/.lock"
 

	
 
    destination_instance_directory="$manager_directory/$destination_instance"
 
    destination_instance_config="$destination_instance_directory/instance.conf"
 

	
 
    # Verify we are working with legitimate source and destination.
 
    if [[ ! -d $source_instance_directory ]]; then
 
        error "No such instance: $source_instance"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if [[ ! -f $source_instance_config ]]; then
 
        error "Missing instance configuration file: $source_instance_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
    if [[ ! -f $source_game_config ]]; then
 
        error "Missing game configuration file: $source_game_config"
 
        exit "$ERROR_GENERAL"
 
    fi
 
    # Validate that source instance directory contains valid instance.
 
    validate_path_or_terminate "instance_directory" "$source_instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Make sure destination instance directory can be used.
 
    validate_path_or_terminate "instance_directory_new" "$destination_instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    (
 
        # Obtain lock - Factorio uses the same mechanism, so we should
 
        # be able to detect the game is running in this way.
 
        flock --exclusive --nonblock 200
 
        if [[ $? != 0 ]]; then
 
            error "Could not lock instance directory via lock file $source_lock_file. Is Factorio instance still running?"
 
            exit "$ERROR_GENERAL"
 
        fi
 

	
 
        function remove_lock() {
 
@@ -2022,40 +2004,32 @@ elif [[ $command == copy ]]; then
 
        # Update write-data directory of destination instance,
 
        # including the backups.
 
        write_data="write-data=${destination_instance_directory}"
 
        find "$destination_instance_directory/" -type f -name config.ini -exec \
 
             sed -i -e "s#^write-data=.*#$write_data#" '{}' \;
 

	
 
        sed -i -e "s/^game_version=.*/game_version=$game_version_selected/" "$destination_instance_config"
 

	
 
        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"
 

	
 

	
 
#========#
 
# import #
 
#========#
 
elif [[ $command == import ]]; then
 

	
 
    # Make sure user has set directory with game installations - test
 
    # both symlink and target destination.
 
    if [[ ! -L $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 

	
 
    if [[ ! -d $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    source_directory="${2-}"
 
    shift 2
 

	
 
    # Verify positional arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
@@ -2063,46 +2037,45 @@ elif [[ $command == import ]]; then
 
        error "Missing argument: SOURCE_DIRECTORY"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Calculate derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 

	
 
    source_config="$source_directory/config/config.ini"
 
    source_lock_file="$source_directory/.lock"
 

	
 
    # Make sure new instance directory can be used.
 
    validate_path_or_terminate "instance_directory_new" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    # Make sure that the import source is valid (should be Factorio
 
    # installation directory).
 
    validate_path_or_terminate "instance_import_source" "$source_directory" "$ERROR_ARGUMENTS"
 

	
 
    # List of entries to import from the source directory.
 
    declare -A import_entries=()
 
    import_entries["achievements-modded.dat"]="contains achivement information for modded plays"
 
    import_entries["achievements.dat"]="contains achievement information for vanilla plays"
 
    import_entries["archive"]="contains desync reports"
 
    import_entries["blueprint-storage.dat"]="contains global (non-savegame specific) blueprints"
 
    import_entries["config/config.ini"]="contains game configuration, including things like shortcuts etc."
 
    import_entries["crop-cache.dat"]="purpose is not known"
 
    import_entries["factorio-current.log"]="contains logs from the currently running game"
 
    import_entries["factorio-previous.log"]="contains logs from the previously running game"
 
    import_entries["mods"]="contains mods and mod settings"
 
    import_entries["player-data.json"]="contains global information about the player, such as username, login token, chat history, etc."
 
    import_entries["saves"]="contains savegames"
 

	
 
    validate_path_or_terminate "instance_directory_new" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    if [[ ! -f $source_directory/bin/x64/factorio ]]; then
 
        error "Could not locate Factorio binary in source directory under: $source_directory/bin/x64/factorio"
 
        error "Factorio Manager natively supports instance imports only when all game data (savegames etc) are stored within Factorio installation directory."
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Display list of available Factorio versions and let user pick one.
 
    echo "Factorio version must  be selected manually for imported instances."
 
    echo
 
    select_factorio_version "$game_installations_directory" || exit "$ERROR_GENERAL"
 

	
 
    (
 

	
 
        # Obtain lock - Factorio uses the same mechanism, so we should
 
        # be able to detect the game is running in this way.
 
        flock --exclusive --nonblock 200
 
        if [[ $? != 0 ]]; then
 
            error "Could not lock instance directory via lock file $source_lock_file. Is Factorio instance still running?"
 
@@ -2163,56 +2136,49 @@ EOF
 
            read -n1
 
        fi
 

	
 
        success "Finished import of instance $(colorecho -n green "$instance")."
 

	
 
    ) 200>"$source_lock_file"
 

	
 

	
 
#===============#
 
# create-server #
 
#===============#
 
elif [[ $command == create-server ]]; then
 
    instance="${1-}"
 

	
 
    # Make sure user has set directory with game installations - test
 
    # both symlink and target destination.
 
    if [[ ! -L $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 
    # Make sure game installations directory has been set.
 
    validate_path_or_terminate "game_installations_directory" "$game_installations_directory" "$ERROR_CONFIGURATION"
 

	
 
    if [[ ! -d $game_installations_directory ]]; then
 
        error "Game installations directory has not been properly set. Please run the set-game-dir command first."
 
        exit "$ERROR_CONFIGURATION"
 
    fi
 
    instance="${1-}"
 

	
 
    # Read positional arguments.
 
    instance="${1-}"
 
    shift
 

	
 
    # Calculate derived variables.
 
    instance_directory="$manager_directory/$instance"
 
    instance_config="$instance_directory/instance.conf"
 
    game_config="$instance_directory/config.ini"
 
    server_config="$instance_directory/server-settings.json"
 
    saves_directory="$instance_directory/saves"
 
    main_save="$saves_directory/default.zip"
 

	
 
    # Verify arguments.
 
    if [[ -z $instance ]]; then
 
        error "Missing argument: INSTANCE"
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    # Make sure new instance directory can be used.
 
    validate_path_or_terminate "instance_directory_new" "$instance_directory" "$ERROR_ARGUMENTS"
 

	
 
    select_factorio_version "$game_installations_directory" || exit "$ERROR_GENERAL"
 

	
 
    # Grab server settings from user.
 
    echo "You will now be prompted to provide settings for the server, with some pre-filled settings."
 
    echo "Do not change settings marked with [EXPERT] unless you know what you are doing."
 
    echo
 
    read_server_settings "$instance"
 

	
 
    # Set-up the instance.
 
    mkdir "$instance_directory"
0 comments (0 inline, 0 general)