Browse Source
* feat(etl): add downloader and update support for ET: Legacy
Refactors ET: Legacy to use a dedicated update module instead of hardcoded installation files. The new update_etl.sh module leverages the GitHub API to check for, download, and apply the latest builds from GameServerManagers/etlserver-build.
* feat(etl): add update_etl module to core modules
Registers the update_etl.sh module within the core modules to enable the fetching and execution of ET: Legacy updates.
* feat(etl): add update commands to core_getopt
Ensures that the update and check-update commands are available for ET: Legacy by including the etl shortname in the getopt command registration logic.
* feat(etl): improve local build detection
Updates the game log directory to the "legacy" folder and enhances local build detection by parsing etconsole.log for version information, falling back to build.txt if necessary.
* feat(etl): update glibc requirement and log path detection
Updates the minimum glibc requirement to 2.17 and switches the local build detection to use the gamelogdir variable instead of a hardcoded path.
* feat(etl): improve MD5 hash extraction
Updates the MD5 hash parsing to use a specific regex for 32-character hexadecimal strings, providing a more robust extraction from the release body than relying on the last field of the line.
* feat(xnt): add SHA512 hash extraction for remote builds
Updates the Xonotic update module to fetch the SHA512 hash from the remote download server, allowing for build verification and identification.
* fix(xnt): derive sha512 URL from remotebuildfilename not remotebuildtag
Tag format is xonotic-v0.8.6 but the sha512 file is named xonotic-0.8.6.sha512
(without the v). Using remotebuildtag directly produced a 404. Deriving from
remotebuildfilename (which already has the v stripped by tr -d v) gives the
correct URL.
* fix(core_dl): fix zip extraction with extractsrc across devices and non-empty dirs
Using mv to move extracted directories fails in two cases:
- Cross-device moves (e.g. tmp and serverfiles on different Docker volumes)
- Target directory already exists and is non-empty (update scenario)
Replace find+mv with cp -a which handles both cases by copying recursively
and merging into the destination. Also replace the hardcoded 'Xonotic'
temp_extractdir with ${extractsrc} to be generic.
* fix(core_dl): remove duplicate ellipsis in hash verification message
pull/4899/head
committed by
GitHub
9 changed files with 191 additions and 14 deletions
@ -0,0 +1,173 @@ |
|||||
|
#!/bin/bash |
||||
|
# LinuxGSM update_etl.sh module |
||||
|
# Author: Daniel Gibbs |
||||
|
# Contributors: https://linuxgsm.com/contrib |
||||
|
# Website: https://linuxgsm.com |
||||
|
# Description: Handles updating of ET: Legacy servers. |
||||
|
|
||||
|
moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" |
||||
|
|
||||
|
fn_update_dl() { |
||||
|
# Download and extract files to serverfiles. |
||||
|
fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "${remotebuildhash}" |
||||
|
fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" |
||||
|
echo "${remotebuild}" > "${serverfiles}/build.txt" |
||||
|
fn_clear_tmp |
||||
|
} |
||||
|
|
||||
|
fn_update_localbuild() { |
||||
|
# Gets local build info. |
||||
|
fn_print_dots "Checking local build: ${remotelocation}" |
||||
|
# Try to get build version from etconsole.log. |
||||
|
if [ -f "${gamelogdir}/etconsole.log" ]; then |
||||
|
localbuild=$(grep "Initializing legacy game" "${gamelogdir}/etconsole.log" | sed -n 's/.*\^2\(v[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' | tail -1) |
||||
|
fi |
||||
|
# Fall back to build.txt if log parse failed or log does not exist. |
||||
|
if [ -z "${localbuild}" ]; then |
||||
|
localbuild=$(head -n 1 "${serverfiles}/build.txt" 2> /dev/null) |
||||
|
fi |
||||
|
if [ -z "${localbuild}" ]; then |
||||
|
fn_print_error "Checking local build: ${remotelocation}: missing local build info" |
||||
|
fn_script_log_error "Missing local build info" |
||||
|
fn_script_log_error "Set localbuild to 0" |
||||
|
localbuild="0" |
||||
|
else |
||||
|
fn_print_ok "Checking local build: ${remotelocation}" |
||||
|
fn_script_log_pass "Checking local build" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
fn_update_remotebuild() { |
||||
|
# Gets remote build info. |
||||
|
apiurl="https://api.github.com/repos/GameServerManagers/etlserver-build/releases/latest" |
||||
|
remotebuildresponse=$(curl -s "${apiurl}") |
||||
|
remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.browser_download_url | contains("i386-et-260b")) | .name') |
||||
|
remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.browser_download_url | contains("i386-et-260b")) | .browser_download_url') |
||||
|
remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name') |
||||
|
remotebuildhash=$(echo "${remotebuildresponse}" | jq -r '.body' | grep 'MD5' | grep -oE '[a-f0-9]{32}') |
||||
|
|
||||
|
if [ "${firstcommandname}" != "INSTALL" ]; then |
||||
|
fn_print_dots "Checking remote build: ${remotelocation}" |
||||
|
# Checks if remotebuild variable has been set. |
||||
|
if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then |
||||
|
fn_print_fail "Checking remote build: ${remotelocation}" |
||||
|
fn_script_log_fail "Checking remote build" |
||||
|
core_exit.sh |
||||
|
else |
||||
|
fn_print_ok "Checking remote build: ${remotelocation}" |
||||
|
fn_script_log_pass "Checking remote build" |
||||
|
fi |
||||
|
else |
||||
|
# Checks if remotebuild variable has been set. |
||||
|
if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then |
||||
|
fn_print_failure "Unable to get remote build" |
||||
|
fn_script_log_fail "Unable to get remote build" |
||||
|
core_exit.sh |
||||
|
fi |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
fn_update_compare() { |
||||
|
fn_print_dots "Checking for update: ${remotelocation}" |
||||
|
# Update has been found or force update. |
||||
|
if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then |
||||
|
# Create update lockfile. |
||||
|
date '+%s' > "${lockdir:?}/update.lock" |
||||
|
fn_print_ok_nl "Checking for update: ${remotelocation}" |
||||
|
fn_print "\n" |
||||
|
fn_print_nl "${bold}${underline}Update${default} available" |
||||
|
fn_print_nl "* Local build: ${red}${localbuild}${default}" |
||||
|
fn_print_nl "* Remote build: ${green}${remotebuild}${default}" |
||||
|
if [ -n "${branch}" ]; then |
||||
|
fn_print_nl "* Branch: ${branch}" |
||||
|
fi |
||||
|
if [ -f "${rootdir}/.dev-debug" ]; then |
||||
|
fn_print_nl "Remote build info" |
||||
|
fn_print_nl "* apiurl: ${apiurl}" |
||||
|
fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" |
||||
|
fn_print_nl "* remotebuildurl: ${remotebuildurl}" |
||||
|
fn_print_nl "* remotebuild: ${remotebuild}" |
||||
|
fi |
||||
|
fn_print "\n" |
||||
|
fn_script_log_info "Update available" |
||||
|
fn_script_log_info "Local build: ${localbuild}" |
||||
|
fn_script_log_info "Remote build: ${remotebuild}" |
||||
|
if [ -n "${branch}" ]; then |
||||
|
fn_script_log_info "Branch: ${branch}" |
||||
|
fi |
||||
|
fn_script_log_info "${localbuild} > ${remotebuild}" |
||||
|
|
||||
|
if [ "${commandname}" == "UPDATE" ]; then |
||||
|
date +%s > "${lockdir:?}/last-updated.lock" |
||||
|
unset updateonstart |
||||
|
check_status.sh |
||||
|
# If server stopped. |
||||
|
if [ "${status}" == "0" ]; then |
||||
|
fn_update_dl |
||||
|
if [ "${localbuild}" == "0" ]; then |
||||
|
exitbypass=1 |
||||
|
command_start.sh |
||||
|
fn_firstcommand_reset |
||||
|
exitbypass=1 |
||||
|
fn_sleep_time_5 |
||||
|
command_stop.sh |
||||
|
fn_firstcommand_reset |
||||
|
fi |
||||
|
# If server started. |
||||
|
else |
||||
|
fn_print_restart_warning |
||||
|
exitbypass=1 |
||||
|
command_stop.sh |
||||
|
fn_firstcommand_reset |
||||
|
exitbypass=1 |
||||
|
fn_update_dl |
||||
|
exitbypass=1 |
||||
|
command_start.sh |
||||
|
fn_firstcommand_reset |
||||
|
fi |
||||
|
unset exitbypass |
||||
|
alert="update" |
||||
|
elif [ "${commandname}" == "CHECK-UPDATE" ]; then |
||||
|
alert="check-update" |
||||
|
fi |
||||
|
alert.sh |
||||
|
else |
||||
|
fn_print_ok_nl "Checking for update: ${remotelocation}" |
||||
|
fn_print "\n" |
||||
|
fn_print_nl "${bold}${underline}No update${default} available" |
||||
|
fn_print_nl "* Local build: ${green}${localbuild}${default}" |
||||
|
fn_print_nl "* Remote build: ${green}${remotebuild}${default}" |
||||
|
if [ -n "${branch}" ]; then |
||||
|
fn_print_nl "* Branch: ${branch}" |
||||
|
fi |
||||
|
fn_print "\n" |
||||
|
fn_script_log_info "No update available" |
||||
|
fn_script_log_info "Local build: ${localbuild}" |
||||
|
fn_script_log_info "Remote build: ${remotebuild}" |
||||
|
if [ -n "${branch}" ]; then |
||||
|
fn_script_log_info "Branch: ${branch}" |
||||
|
fi |
||||
|
if [ -f "${rootdir}/.dev-debug" ]; then |
||||
|
fn_print_nl "Remote build info" |
||||
|
fn_print_nl "* apiurl: ${apiurl}" |
||||
|
fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" |
||||
|
fn_print_nl "* remotebuildurl: ${remotebuildurl}" |
||||
|
fn_print_nl "* remotebuild: ${remotebuild}" |
||||
|
fi |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# The location where the builds are checked and downloaded. |
||||
|
remotelocation="github.com" |
||||
|
|
||||
|
if [ "${firstcommandname}" == "INSTALL" ]; then |
||||
|
fn_update_remotebuild |
||||
|
fn_update_dl |
||||
|
else |
||||
|
fn_print_dots "Checking for update" |
||||
|
fn_print_dots "Checking for update: ${remotelocation}" |
||||
|
fn_script_log_info "Checking for update: ${remotelocation}" |
||||
|
fn_update_localbuild |
||||
|
fn_update_remotebuild |
||||
|
fn_update_compare |
||||
|
fi |
||||
Loading…
Reference in new issue