Init
This commit is contained in:
308
install.sh
Executable file
308
install.sh
Executable file
@@ -0,0 +1,308 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SOURCE_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
VERSION="${PTLINUX_VERSION:-0.5.1}"
|
||||
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
||||
then
|
||||
printf 'Invalid launcher version: %s (expected X.Y.Z)\n' "$VERSION" >&2
|
||||
exit 2
|
||||
fi
|
||||
DATA_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}"
|
||||
BIN_HOME="${HOME}/.local/bin"
|
||||
APPLICATION_HOME="${DATA_HOME}/applications"
|
||||
PIXMAP_HOME="${DATA_HOME}/pixmaps"
|
||||
ICON_PATH="${PIXMAP_HOME}/eu.pristontale.PTLinux.png"
|
||||
DEFAULT_INSTALL_DIRECTORY="${HOME}/Games/PristontaleEU"
|
||||
LEGACY_INSTALL_DIRECTORY="${DATA_HOME}/pristontale-eu"
|
||||
INSTALL_DIRECTORY_EXPLICIT=0
|
||||
if [[ -n "${PTLINUX_INSTALL_DIR:-}" ]]
|
||||
then
|
||||
INSTALL_DIRECTORY="$PTLINUX_INSTALL_DIR"
|
||||
INSTALL_DIRECTORY_EXPLICIT=1
|
||||
else
|
||||
INSTALL_DIRECTORY="$DEFAULT_INSTALL_DIRECTORY"
|
||||
fi
|
||||
PRESERVED_LEGACY_INSTALL=0
|
||||
PYTHON_BIN="${PTLINUX_PYTHON:-python3}"
|
||||
DRY_RUN=0
|
||||
RUN_DOCTOR=1
|
||||
INSTALL_DEPENDENCIES=1
|
||||
|
||||
usage()
|
||||
{
|
||||
printf '%s\n' \
|
||||
"Usage: ./install.sh [--install-dir PATH] [--dry-run] [--skip-deps] [--skip-doctor]" \
|
||||
"" \
|
||||
" --install-dir PATH Store the app, managed game, and runtime data at PATH." \
|
||||
" Default: ~/Games/PristontaleEU"
|
||||
}
|
||||
|
||||
while (( $# > 0 ))
|
||||
do
|
||||
case "$1" in
|
||||
--install-dir)
|
||||
if (( $# < 2 ))
|
||||
then
|
||||
printf '%s\n' "--install-dir requires a path." >&2
|
||||
exit 2
|
||||
fi
|
||||
INSTALL_DIRECTORY="$2"
|
||||
INSTALL_DIRECTORY_EXPLICIT=1
|
||||
shift 2
|
||||
;;
|
||||
--install-dir=*)
|
||||
INSTALL_DIRECTORY="${1#*=}"
|
||||
INSTALL_DIRECTORY_EXPLICIT=1
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
--skip-doctor)
|
||||
RUN_DOCTOR=0
|
||||
shift
|
||||
;;
|
||||
--skip-deps)
|
||||
INSTALL_DEPENDENCIES=0
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
printf 'Unknown option: %s\n' "$1" >&2
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( INSTALL_DIRECTORY_EXPLICIT == 0 )) \
|
||||
&& [[ ! -d "${DEFAULT_INSTALL_DIRECTORY}/app/ptlinux" \
|
||||
&& ! -d "${DEFAULT_INSTALL_DIRECTORY}/app/current/ptlinux" ]] \
|
||||
&& [[ -d "${LEGACY_INSTALL_DIRECTORY}/app/ptlinux" \
|
||||
|| -d "${LEGACY_INSTALL_DIRECTORY}/app/current/ptlinux" \
|
||||
|| -f "${LEGACY_INSTALL_DIRECTORY}/launcher-prefix/drive_c/Program Files (x86)/Pristontale EU/Game.exe" ]]
|
||||
then
|
||||
INSTALL_DIRECTORY="$LEGACY_INSTALL_DIRECTORY"
|
||||
PRESERVED_LEGACY_INSTALL=1
|
||||
fi
|
||||
|
||||
if [[ -z "$INSTALL_DIRECTORY" \
|
||||
|| "$INSTALL_DIRECTORY" == *$'\n'* \
|
||||
|| "$INSTALL_DIRECTORY" == *$'\r'* ]]
|
||||
then
|
||||
printf '%s\n' "Install directory is empty or contains invalid characters." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
case "$INSTALL_DIRECTORY" in
|
||||
"~")
|
||||
INSTALL_DIRECTORY="$HOME"
|
||||
;;
|
||||
"~/"*)
|
||||
INSTALL_DIRECTORY="${HOME}/${INSTALL_DIRECTORY:2}"
|
||||
;;
|
||||
"~"*)
|
||||
printf '%s\n' "Use an absolute path instead of another user's ~ directory." >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$INSTALL_DIRECTORY" != /* ]]
|
||||
then
|
||||
INSTALL_DIRECTORY="${PWD}/${INSTALL_DIRECTORY}"
|
||||
fi
|
||||
if command -v realpath >/dev/null 2>&1
|
||||
then
|
||||
INSTALL_DIRECTORY="$(realpath -m -- "$INSTALL_DIRECTORY")"
|
||||
fi
|
||||
if [[ "$INSTALL_DIRECTORY" == "/" ]]
|
||||
then
|
||||
printf '%s\n' "Refusing to use the filesystem root as the install directory." >&2
|
||||
exit 2
|
||||
fi
|
||||
APP_ROOT="${INSTALL_DIRECTORY}/app"
|
||||
RELEASES_ROOT="${APP_ROOT}/releases"
|
||||
RELEASE_ROOT="${RELEASES_ROOT}/${VERSION}"
|
||||
|
||||
if [[ ! -d "${SOURCE_ROOT}/ptlinux" \
|
||||
|| ! -f "${SOURCE_ROOT}/ptdiag/assbin.py" \
|
||||
|| ! -f "${SOURCE_ROOT}/ptdiag/__init__.py" \
|
||||
|| ! -f "${SOURCE_ROOT}/ptlinux/desktop_entry.py" \
|
||||
|| ! -f "${SOURCE_ROOT}/ptlinux/launcher_wrapper.py" \
|
||||
|| ! -f "${SOURCE_ROOT}/ptlinux/self_update.py" \
|
||||
|| ! -f "${SOURCE_ROOT}/ptlinux/launcher-update-public.pem" \
|
||||
|| ! -f "${SOURCE_ROOT}/packaging/eu.pristontale.PTLinux.desktop" \
|
||||
|| ! -f "${SOURCE_ROOT}/packaging/eu.pristontale.PTLinux.png" \
|
||||
|| ! -f "${SOURCE_ROOT}/packaging/pristontale-eu" \
|
||||
|| ! -f "${SOURCE_ROOT}/packaging/install-dependencies.sh" ]]
|
||||
then
|
||||
printf '%s\n' "Installer source is incomplete." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "Installing PristonTale EU Linux launcher for the current user"
|
||||
if (( PRESERVED_LEGACY_INSTALL == 1 ))
|
||||
then
|
||||
printf '%s\n' " Existing installation found; preserving its previous data location."
|
||||
fi
|
||||
printf ' Install data: %s\n' "$INSTALL_DIRECTORY"
|
||||
printf ' Application: %s\n' "$APP_ROOT"
|
||||
printf ' Command: %s\n' "${BIN_HOME}/pristontale-eu"
|
||||
printf ' Desktop: %s\n' "${APPLICATION_HOME}/eu.pristontale.PTLinux.desktop"
|
||||
|
||||
if (( INSTALL_DEPENDENCIES == 1 ))
|
||||
then
|
||||
# shellcheck source=packaging/install-dependencies.sh
|
||||
source "${SOURCE_ROOT}/packaging/install-dependencies.sh"
|
||||
ptlinux_install_host_dependencies "$DRY_RUN"
|
||||
else
|
||||
printf '%s\n' "Skipping host dependency installation."
|
||||
fi
|
||||
|
||||
if (( DRY_RUN == 1 ))
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1
|
||||
then
|
||||
printf 'Python was not found after dependency installation: %s\n' "$PYTHON_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! "$PYTHON_BIN" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)'
|
||||
then
|
||||
printf '%s\n' "Python 3.11 or newer is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install -d -m 0755 "$APP_ROOT" "$RELEASES_ROOT" "$BIN_HOME" "$APPLICATION_HOME" "$PIXMAP_HOME"
|
||||
STAGING_RELEASE="${RELEASES_ROOT}/.${VERSION}.$$.staging"
|
||||
if [[ -e "$STAGING_RELEASE" || -L "$STAGING_RELEASE" ]]
|
||||
then
|
||||
printf 'Launcher staging path already exists: %s\n' "$STAGING_RELEASE" >&2
|
||||
exit 1
|
||||
fi
|
||||
install -d -m 0755 "$STAGING_RELEASE"
|
||||
install -d -m 0755 "${STAGING_RELEASE}/ptlinux" "${STAGING_RELEASE}/ptdiag"
|
||||
install -m 0644 "${SOURCE_ROOT}/ptlinux/"*.py "${STAGING_RELEASE}/ptlinux/"
|
||||
install -m 0644 \
|
||||
"${SOURCE_ROOT}/ptlinux/launcher-update-public.pem" \
|
||||
"${STAGING_RELEASE}/ptlinux/launcher-update-public.pem"
|
||||
install -m 0644 "${SOURCE_ROOT}/ptdiag/__init__.py" "${STAGING_RELEASE}/ptdiag/__init__.py"
|
||||
install -m 0644 "${SOURCE_ROOT}/ptdiag/assbin.py" "${STAGING_RELEASE}/ptdiag/assbin.py"
|
||||
printf '{\n "schema": 1,\n "version": "%s"\n}\n' "$VERSION" > "${STAGING_RELEASE}/release.json"
|
||||
chmod 0644 "${STAGING_RELEASE}/release.json"
|
||||
|
||||
if ! "$PYTHON_BIN" -I -c \
|
||||
'import sys; sys.path.insert(0, sys.argv[1]); import ptlinux, ptlinux.cli, ptlinux.self_update; raise SystemExit(0 if ptlinux.__version__ == sys.argv[2] else 1)' \
|
||||
"$STAGING_RELEASE" "$VERSION"
|
||||
then
|
||||
printf '%s\n' "The staged launcher failed its import/version check." >&2
|
||||
rm -r -- "$STAGING_RELEASE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPLACED_RELEASE=""
|
||||
if [[ -e "$RELEASE_ROOT" || -L "$RELEASE_ROOT" ]]
|
||||
then
|
||||
if [[ ! -d "$RELEASE_ROOT" || -L "$RELEASE_ROOT" ]]
|
||||
then
|
||||
printf 'Existing launcher release is not a directory: %s\n' "$RELEASE_ROOT" >&2
|
||||
rm -r -- "$STAGING_RELEASE"
|
||||
exit 1
|
||||
fi
|
||||
REPLACED_RELEASE="${RELEASES_ROOT}/.${VERSION}.$$.replaced"
|
||||
mv -- "$RELEASE_ROOT" "$REPLACED_RELEASE"
|
||||
fi
|
||||
if ! mv -- "$STAGING_RELEASE" "$RELEASE_ROOT"
|
||||
then
|
||||
if [[ -n "$REPLACED_RELEASE" && -d "$REPLACED_RELEASE" ]]
|
||||
then
|
||||
mv -- "$REPLACED_RELEASE" "$RELEASE_ROOT"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$REPLACED_RELEASE" && -d "$REPLACED_RELEASE" ]]
|
||||
then
|
||||
rm -r -- "$REPLACED_RELEASE"
|
||||
fi
|
||||
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "${APP_ROOT}/current" ]]
|
||||
then
|
||||
CURRENT_TARGET="$(readlink -- "${APP_ROOT}/current")"
|
||||
if [[ ! "$CURRENT_TARGET" =~ ^releases/[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
||||
then
|
||||
printf 'Existing launcher current link is unsafe: %s\n' "$CURRENT_TARGET" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "${APP_ROOT}/${CURRENT_TARGET}" ]]
|
||||
then
|
||||
printf 'Existing launcher current link is broken: %s\n' "$CURRENT_TARGET" >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [[ -e "${APP_ROOT}/current" ]]
|
||||
then
|
||||
printf 'Launcher current path is not a symbolic link: %s\n' "${APP_ROOT}/current" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -L "${APP_ROOT}/previous" ]]
|
||||
then
|
||||
PREVIOUS_TARGET="$(readlink -- "${APP_ROOT}/previous")"
|
||||
if [[ ! "$PREVIOUS_TARGET" =~ ^releases/[0-9]+\.[0-9]+\.[0-9]+$ \
|
||||
|| ! -d "${APP_ROOT}/${PREVIOUS_TARGET}" ]]
|
||||
then
|
||||
printf 'Existing launcher previous link is unsafe or broken: %s\n' "$PREVIOUS_TARGET" >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [[ -e "${APP_ROOT}/previous" ]]
|
||||
then
|
||||
printf 'Launcher previous path is not a symbolic link: %s\n' "${APP_ROOT}/previous" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$CURRENT_TARGET" && "$CURRENT_TARGET" != "releases/${VERSION}" ]]
|
||||
then
|
||||
PREVIOUS_LINK="${APP_ROOT}/.previous.$$.tmp"
|
||||
ln -s -- "$CURRENT_TARGET" "$PREVIOUS_LINK"
|
||||
mv -Tf -- "$PREVIOUS_LINK" "${APP_ROOT}/previous"
|
||||
fi
|
||||
CURRENT_LINK="${APP_ROOT}/.current.$$.tmp"
|
||||
ln -s -- "releases/${VERSION}" "$CURRENT_LINK"
|
||||
mv -Tf -- "$CURRENT_LINK" "${APP_ROOT}/current"
|
||||
|
||||
"$PYTHON_BIN" "${RELEASE_ROOT}/ptlinux/launcher_wrapper.py" \
|
||||
"${SOURCE_ROOT}/packaging/pristontale-eu" \
|
||||
"$APP_ROOT" \
|
||||
"$INSTALL_DIRECTORY" \
|
||||
"${BIN_HOME}/pristontale-eu"
|
||||
install -m 0644 \
|
||||
"${SOURCE_ROOT}/packaging/eu.pristontale.PTLinux.png" \
|
||||
"$ICON_PATH"
|
||||
"$PYTHON_BIN" "${RELEASE_ROOT}/ptlinux/desktop_entry.py" \
|
||||
"${SOURCE_ROOT}/packaging/eu.pristontale.PTLinux.desktop" \
|
||||
"${BIN_HOME}/pristontale-eu" \
|
||||
"$ICON_PATH" \
|
||||
"${APPLICATION_HOME}/eu.pristontale.PTLinux.desktop"
|
||||
|
||||
if command -v desktop-file-validate >/dev/null 2>&1
|
||||
then
|
||||
desktop-file-validate "${APPLICATION_HOME}/eu.pristontale.PTLinux.desktop"
|
||||
fi
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1
|
||||
then
|
||||
update-desktop-database "$APPLICATION_HOME" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
printf '%s\n' "Application installed."
|
||||
if (( RUN_DOCTOR == 1 ))
|
||||
then
|
||||
"${BIN_HOME}/pristontale-eu" doctor || true
|
||||
fi
|
||||
Reference in New Issue
Block a user