mirror of
https://github.com/itzg/docker-minecraft-server
synced 2024-11-10 06:14:14 +00:00
458 lines
10 KiB
Bash
Executable file
458 lines
10 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
function get_from_gh() {
|
|
if [[ "${GH_TOKEN:-}" ]]; then
|
|
# User has provided a Personal Access Token to mitigate rate-limiting issues
|
|
if [[ -z "${oAuthScopes}" ]]; then
|
|
oAuthScopes=$(curl -s -H "Authorization: token $GH_TOKEN" https://api.github.com/users/codertocat -I | grep x-oauth-scopes)
|
|
fi
|
|
if [[ ! "$oAuthScopes" =~ ^x-oauth-scopes:[[:space:]]*$ ]]; then
|
|
# Don't use what you don't have to...
|
|
log "ERROR: GH_TOKEN has permissions it doesn't need. Recreate or update this personal access token and disable ALL scopes."
|
|
exit 1
|
|
else
|
|
curl -fsSL -H "Authorization: token $GH_TOKEN" "${@:2}" "$1"
|
|
fi
|
|
else
|
|
curl -fsSL "${@:2}" "$1"
|
|
fi
|
|
}
|
|
|
|
function join_by() {
|
|
local d=$1
|
|
shift
|
|
echo -n "$1"
|
|
shift
|
|
printf "%s" "${@/#/$d}"
|
|
}
|
|
|
|
function get_major_version() {
|
|
version=$1
|
|
echo "$version" | cut -d. -f 1-2
|
|
}
|
|
|
|
function isURL() {
|
|
local value=$1
|
|
|
|
if [[ ${value:0:8} == "https://" || ${value:0:7} == "http://" || ${value:0:6} == "ftp://" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function isValidFileURL() {
|
|
suffix=${1:?Missing required suffix arg}
|
|
url=${2:?Missing required url arg}
|
|
|
|
[[ "$url" == http*://*.${suffix} || "$url" == http*://*.${suffix}\?* ]]
|
|
}
|
|
|
|
function resolveEffectiveUrl() {
|
|
url="${1:?Missing required url argument}"
|
|
if ! curl -Ls -o /dev/null -w "%{url_effective}" "$url"; then
|
|
log "ERROR failed to resolve effective URL from $url"
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
function getFilenameFromUrl() {
|
|
url="${1:?Missing required url argument}"
|
|
strippedOfQuery="${url%\?*}"
|
|
basename "$strippedOfQuery"
|
|
}
|
|
|
|
function isTrue() {
|
|
case "${1,,}" in
|
|
true | yes | on | 1)
|
|
return 0
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function isFalse() {
|
|
case "${1,,}" in
|
|
false | no | off | 0)
|
|
return 0
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function isDebugging() {
|
|
if isTrue "${DEBUG:-false}"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function handleDebugMode() {
|
|
if isDebugging; then
|
|
set -x
|
|
fi
|
|
}
|
|
|
|
function debug() {
|
|
if isDebugging; then
|
|
log "DEBUG: $*"
|
|
fi
|
|
}
|
|
|
|
function logn() {
|
|
echo -n "[init] $*"
|
|
}
|
|
|
|
function log() {
|
|
local oldState
|
|
# The return status when listing options is zero if all optnames are enabled, non- zero otherwise.
|
|
oldState=$(shopt -po xtrace || true)
|
|
shopt -u -o xtrace
|
|
|
|
if isDebugging || isTrue "${LOG_TIMESTAMP:-false}"; then
|
|
ts=" $(date --rfc-3339=seconds)"
|
|
else
|
|
ts=
|
|
fi
|
|
echo "[init]${ts} $*"
|
|
eval "$oldState"
|
|
}
|
|
|
|
function logAutopause() {
|
|
echo "[Autopause loop] $*"
|
|
}
|
|
|
|
function logAutopauseAction() {
|
|
echo "[$(date -Iseconds)] [Autopause] $*"
|
|
}
|
|
|
|
function logAutostop() {
|
|
echo "[Autostop loop] $*"
|
|
}
|
|
|
|
function logAutostopAction() {
|
|
echo "[$(date -Iseconds)] [Autostop] $*"
|
|
}
|
|
|
|
function logRcon() {
|
|
echo "[Rcon loop] $*"
|
|
}
|
|
|
|
function normalizeMemSize() {
|
|
local scale=1
|
|
case ${1,,} in
|
|
*k)
|
|
scale=1024
|
|
;;
|
|
*m)
|
|
scale=1048576
|
|
;;
|
|
*g)
|
|
scale=1073741824
|
|
;;
|
|
esac
|
|
|
|
val=${1:0:-1}
|
|
echo $((val * scale))
|
|
}
|
|
|
|
function compare_version() {
|
|
local left_version=$1
|
|
local comparison=$2
|
|
local right_version=$3
|
|
|
|
if [[ -z "$left_version" ]]; then
|
|
echo "Left version is required"
|
|
return 1
|
|
fi
|
|
|
|
if [[ -z "$right_version" ]]; then
|
|
echo "Right version is required"
|
|
return 1
|
|
fi
|
|
|
|
# Handle version channels ('a', 'b', or numeric)
|
|
if [[ $left_version == a* || $left_version == b* ]]; then
|
|
left_version=${left_version:1}
|
|
fi
|
|
|
|
if [[ $right_version == a* || $right_version == b* ]]; then
|
|
right_version=${right_version:1}
|
|
fi
|
|
|
|
|
|
local left_version_channel=${left_version:0:1}
|
|
if [[ $left_version_channel =~ [0-9] ]]; then
|
|
left_version_channel='r'
|
|
fi
|
|
|
|
local right_version_channel=${right_version:0:1}
|
|
if [[ $right_version_channel =~ [0-9] ]]; then
|
|
right_version_channel='r'
|
|
fi
|
|
|
|
if [[ $comparison == "lt" && $left_version_channel < $right_version_channel ]]; then
|
|
return 0
|
|
elif [[ $comparison == "lt" && $left_version_channel > $right_version_channel ]]; then
|
|
return 1
|
|
elif [[ $comparison == "gt" && $left_version_channel > $right_version_channel ]]; then
|
|
return 0
|
|
elif [[ $comparison == "gt" && $left_version_channel < $right_version_channel ]]; then
|
|
return 1
|
|
elif [[ $comparison == "le" && $left_version_channel < $right_version_channel ]]; then
|
|
return 0
|
|
elif [[ $comparison == "le" && $left_version_channel == $right_version_channel ]]; then
|
|
return 0
|
|
elif [[ $comparison == "ge" && $left_version_channel > $right_version_channel ]]; then
|
|
return 0
|
|
elif [[ $comparison == "ge" && $left_version_channel == $right_version_channel ]]; then
|
|
return 0
|
|
elif [[ $comparison == "eq" && $left_version_channel == $right_version_channel ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Compare the versions using sort -V
|
|
local result
|
|
|
|
case $comparison in
|
|
"lt")
|
|
if [[ $(echo -e "$left_version\n$right_version" | sort -V | head -n1) == "$left_version" && "$left_version" != "$right_version" ]]; then
|
|
result=0
|
|
else
|
|
result=1
|
|
fi
|
|
;;
|
|
"le")
|
|
if [[ $(echo -e "$left_version\n$right_version" | sort -V | head -n1) == "$left_version" ]]; then
|
|
result=0
|
|
else
|
|
result=1
|
|
fi
|
|
;;
|
|
"eq")
|
|
if [[ "$left_version" == "$right_version" ]]; then
|
|
result=0
|
|
else
|
|
result=1
|
|
fi
|
|
;;
|
|
"ge")
|
|
if [[ $(echo -e "$left_version\n$right_version" | sort -V | tail -n1) == "$left_version" ]]; then
|
|
result=0
|
|
else
|
|
result=1
|
|
fi
|
|
;;
|
|
"gt")
|
|
if [[ $(echo -e "$left_version\n$right_version" | sort -V | tail -n1) == "$left_version" && "$left_version" != "$right_version" ]]; then
|
|
result=0
|
|
else
|
|
result=1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Unsupported comparison operator: $comparison"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
return $result
|
|
}
|
|
|
|
function versionLessThan() {
|
|
local oldState
|
|
# The return status when listing options is zero if all optnames are enabled, non- zero otherwise.
|
|
oldState=$(shopt -po xtrace || true)
|
|
shopt -u -o xtrace
|
|
|
|
# Use if-else since strict mode might be enabled
|
|
if compare_version "${VERSION}" "lt" "${1?}"; then
|
|
eval "$oldState"
|
|
return 0
|
|
else
|
|
eval "$oldState"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
requireVar() {
|
|
if [ ! -v "$1" ]; then
|
|
log "ERROR: $1 is required to be set"
|
|
exit 1
|
|
fi
|
|
if [ -z "${!1}" ]; then
|
|
log "ERROR: $1 is required to be set"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
requireEnum() {
|
|
var=${1?}
|
|
shift
|
|
|
|
for allowed in "$@"; do
|
|
if [[ ${!var} = "$allowed" ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
log "ERROR: $var must be set to one of $*"
|
|
# exit 1
|
|
}
|
|
|
|
function writeEula() {
|
|
if ! echo "# Generated via Docker
|
|
# $(date)
|
|
eula=${EULA,,}
|
|
" >/data/eula.txt; then
|
|
log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}"
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
function removeOldMods {
|
|
if [ -d "$1" ]; then
|
|
log "Removing old mods including='${REMOVE_OLD_MODS_INCLUDE}' excluding='${REMOVE_OLD_MODS_EXCLUDE}' up to depth=${REMOVE_OLD_MODS_DEPTH}"
|
|
args=(
|
|
--delete
|
|
--type file
|
|
--min-depth=1 --max-depth "${REMOVE_OLD_MODS_DEPTH}"
|
|
--name "${REMOVE_OLD_MODS_INCLUDE}"
|
|
--exclude-name "${REMOVE_OLD_MODS_EXCLUDE}"
|
|
)
|
|
if ! isDebugging; then
|
|
args+=(--quiet)
|
|
fi
|
|
mc-image-helper find "${args[@]}" "$1"
|
|
fi
|
|
}
|
|
|
|
function get() {
|
|
mc-image-helper get "$@"
|
|
}
|
|
|
|
function get_silent() {
|
|
local flags=(-s)
|
|
if isTrue "${DEBUG_GET:-false}"; then
|
|
flags+=("--debug")
|
|
fi
|
|
mc-image-helper "${flags[@]}" get "$@"
|
|
}
|
|
|
|
function isFamily() {
|
|
for f in "${@}"; do
|
|
if [[ ${FAMILY^^} == "${f^^}" ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
function isType() {
|
|
for t in "${@}"; do
|
|
# shellcheck disable=SC2153
|
|
if [[ $TYPE == "$t" ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
function extract() {
|
|
src=${1?}
|
|
destDir=${2?}
|
|
|
|
type=$(file -b --mime-type "${src}")
|
|
case "${type}" in
|
|
application/zip)
|
|
unzip -o -q -d "${destDir}" "${src}"
|
|
;;
|
|
application/x-tar|application/gzip|application/x-gzip|application/x-bzip2)
|
|
tar -C "${destDir}" -xf "${src}"
|
|
;;
|
|
application/zstd|application/x-zstd)
|
|
tar -C "${destDir}" --use-compress-program=unzstd -xf "${src}"
|
|
;;
|
|
*)
|
|
log "ERROR: unsupported archive type: $type"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function getDistro() {
|
|
grep -E "^ID=" /etc/os-release | cut -d= -f2 | sed -e 's/"//g'
|
|
}
|
|
|
|
function checkSum() {
|
|
local sum_file=${1?}
|
|
|
|
# Get distro
|
|
distro=$(getDistro)
|
|
|
|
if [ "${distro}" == "debian" ] && sha1sum -c "${sum_file}" --status 2> /dev/null; then
|
|
return 0
|
|
elif [ "${distro}" == "ubuntu" ] && sha1sum -c "${sum_file}" --status 2> /dev/null; then
|
|
return 0
|
|
elif [ "${distro}" == "alpine" ] && sha1sum -c "${sum_file}" -s 2> /dev/null; then
|
|
return 0
|
|
elif [ "${distro}" == "ol" ] && sha1sum -c "${sum_file}" --status 2> /dev/null; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function usesMods() {
|
|
case "$FAMILY" in
|
|
FORGE|FABRIC|HYBRID|SPONGE)
|
|
return 0
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
function usesPlugins() {
|
|
case "$FAMILY" in
|
|
SPIGOT|HYBRID)
|
|
return 0
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
function resolveVersion() {
|
|
givenVersion="$VERSION"
|
|
# shellcheck disable=SC2153
|
|
if ! VERSION=$(mc-image-helper resolve-minecraft-version "$VERSION"); then
|
|
exit 2
|
|
fi
|
|
log "Resolved version given ${givenVersion} into ${VERSION}"
|
|
}
|
|
|
|
function resolveFamily() {
|
|
case "$TYPE" in
|
|
PAPER|SPIGOT|BUKKIT|CANYON|PUFFERFISH|PURPUR)
|
|
FAMILY=SPIGOT
|
|
;;
|
|
FORGE)
|
|
FAMILY=FORGE
|
|
;;
|
|
FABRIC|QUILT)
|
|
FAMILY=FABRIC
|
|
;;
|
|
esac
|
|
export FAMILY
|
|
}
|
|
|
|
function ensureRemoveAllModsOff() {
|
|
reason=${1?}
|
|
|
|
if isTrue "${REMOVE_OLD_MODS:-false}"; then
|
|
log "WARNING using REMOVE_OLD_MODS interferes with $reason -- it is now disabled"
|
|
REMOVE_OLD_MODS=false
|
|
fi
|
|
}
|