From 21e9dad9ce8c730360e01069d530a19a20dd903c Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 28 Nov 2024 15:42:22 +0200 Subject: [PATCH] Updated mods updater script to correctly process mod dependencies --- docker/files/update-mods.sh | 133 +++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/docker/files/update-mods.sh b/docker/files/update-mods.sh index 1587a841..e9ac6e1b 100755 --- a/docker/files/update-mods.sh +++ b/docker/files/update-mods.sh @@ -23,6 +23,128 @@ print_failure() echo "$1" } +# Checks game version vs version in mod. +# Returns 0 if major version differs or mod minor version is less than game version, 1 if ok +check_game_version() { + local game_version="$1" + local mod_version="$2" + + local game_major mod_major game_minor mod_minor + game_major=$(echo "$game_version" | cut -d '.' -f1) + game_minor=$(echo "$game_version" | cut -d '.' -f2) + mod_major=$(echo "$mod_version" | cut -d '.' -f1) + mod_minor=$(echo "$mod_version" | cut -d '.' -f2) + + if [[ "$game_major" -ne "$mod_major" ]]; then + echo 0 + return + fi + + if [[ "$mod_minor" -ge "$game_minor" ]]; then + echo 1 + else + echo 0 + fi +} + +# Checks dependency string with provided version. +# Only checks for operator based string, ignoring everything else +# Returns 1 if check is ok, 0 if not +check_dependency_version() +{ + local dependency="$1" + local mod_version="$2" + + if [[ "$dependency" =~ ^(\?|!|~|\(~\)) ]]; then + echo 1 + fi + + local condition + condition=$(echo "$dependency" | grep -oE '(>=|<=|>|<|=) [0-9]+(\.[0-9]+)*') + + if [[ -z "$condition" ]]; then + echo 1 + fi + + local operator required_version + operator=$(echo "$condition" | awk '{print $1}') + required_version=$(echo "$condition" | awk '{print $2}') + + case "$operator" in + ">=") + if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | head -n1)" == "$required_version" ]]; then + echo 1 + else + echo 0 + fi + ;; + ">") + if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | head -n1)" == "$required_version" && "$required_version" != "$FACTORIO_VERSION" ]]; then + echo 1 + else + echo 0 + fi + ;; + "<=") + if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | tail -n1)" == "$required_version" ]]; then + echo 1 + else + echo 0 + fi + ;; + "<") + if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | tail -n1)" == "$required_version" && "$required_version" != "$FACTORIO_VERSION" ]]; then + echo 1 + else + echo 0 + fi + ;; + "=") + if [[ "$mod_version" == "$required_version" ]]; then + echo 1 + else + echo 0 + fi + ;; + *) + echo 0 + ;; + esac +} + +get_mod_info() +{ + local mod_info_json="$1" + + while IFS= read -r mod_release_info; do + local mod_version mod_factorio_version + mod_version=$(echo "$mod_release_info" | jq -r ".version") + mod_factorio_version=$(echo "$mod_release_info" | jq -r ".info_json.factorio_version") + + if [[ $(check_game_version "$mod_factorio_version" "$FACTORIO_VERSION") == 0 ]]; then + echo " Skipping mod version $mod_version because of factorio version mismatch" >&2 + continue + fi + + # If we found 'dependencies' element, we also check versions there + if [[ $(echo "$mod_release_info" | jq -e '.info_json | has("dependencies") and (.dependencies | length > 0)') == true ]]; then + while IFS= read -r dependency; do + + # We only check for 'base' dependency + if [[ "$dependency" == base* ]] && [[ $(check_dependency_version "$dependency" "$FACTORIO_VERSION") == 0 ]]; then + echo " Skipping mod version $mod_version, unsatisfied base dependency: $dependency" >&2 + continue 2 + fi + + done < <(echo "$mod_release_info" | jq -r '.info_json.dependencies[]') + fi + + echo "$mod_release_info" | jq -j ".file_name, \";\", .download_url, \";\", .sha1" + break + + done < <(echo "$mod_info_json" | jq -c ".releases|sort_by(.released_at)|reverse|.[]") +} + update_mod() { MOD_NAME="$1" @@ -30,7 +152,7 @@ update_mod() print_step "Checking for update of mod $MOD_NAME for factorio $FACTORIO_VERSION ..." - MOD_INFO_URL="$MOD_BASE_URL/api/mods/$MOD_NAME_ENCODED" + MOD_INFO_URL="$MOD_BASE_URL/api/mods/$MOD_NAME_ENCODED/full" MOD_INFO_JSON=$(curl --silent "$MOD_INFO_URL") if ! echo "$MOD_INFO_JSON" | jq -e .name >/dev/null; then @@ -38,7 +160,12 @@ update_mod() return 0 fi - MOD_INFO=$(echo "$MOD_INFO_JSON" | jq -j --arg version "$FACTORIO_VERSION" ".releases|reverse|map(select(.info_json.factorio_version as \$mod_version | \$version | startswith(\$mod_version)))[0]|.file_name, \";\", .download_url, \";\", .sha1") + MOD_INFO=$(get_mod_info "$MOD_INFO_JSON") + + if [[ "$MOD_INFO" == "" ]]; then + print_failure " Not compatible with version" + return 0 + fi MOD_FILENAME=$(echo "$MOD_INFO" | cut -f1 -d";") MOD_URL=$(echo "$MOD_INFO" | cut -f2 -d";") @@ -90,7 +217,7 @@ update_mod() if [[ -f $MOD_DIR/mod-list.json ]]; then jq -r ".mods|map(select(.enabled))|.[].name" "$MOD_DIR/mod-list.json" | while read -r mod; do if [[ $mod != base ]]; then - update_mod "$mod" + update_mod "$mod" || true fi done fi