#!/usr/bin/env bash # Build SyncGames-x86_64.AppImage (thin GUI + agent). # Usage: from SyncGames/agent/, ./packaging/build-appimage.sh set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" VERSION="$(python3 -c "from syncgames import __version__; print(__version__)" 2>/dev/null || echo "0.1.0")" # Prefer package version when installed in venv if [[ -d "${ROOT}/.venv" ]]; then # shellcheck source=/dev/null source "${ROOT}/.venv/bin/activate" VERSION="$(python3 -c "from syncgames import __version__; print(__version__)")" fi OUT_NAME="SyncGames-${VERSION}-x86_64.AppImage" APPDIR="${ROOT}/build/appimage/AppDir" BUILD_BIN="${ROOT}/build/appimage" APPIMAGETOOL_URL="${APPIMAGETOOL_URL:-https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage}" APPIMAGETOOL="${APPIMAGETOOL:-${BUILD_BIN}/appimagetool-x86_64.AppImage}" echo "==> Version: ${VERSION}" echo "==> Output: ${OUT_NAME}" if [[ ! -d "${ROOT}/.venv" ]]; then echo "==> Creating .venv" python3 -m venv "${ROOT}/.venv" fi # shellcheck source=/dev/null source "${ROOT}/.venv/bin/activate" python3 -m pip install -q -U pip python3 -m pip install -q -e ".[build]" echo "==> PyInstaller" rm -rf "${ROOT}/build/pyinstaller" "${ROOT}/dist/SyncGames" || true pyinstaller "${ROOT}/packaging/pyinstaller.spec" if [[ ! -x "${ROOT}/dist/SyncGames/SyncGames" ]]; then echo "PyInstaller did not produce dist/SyncGames/SyncGames" >&2 exit 1 fi echo "==> Assemble AppDir" rm -rf "$APPDIR" mkdir -p "$APPDIR/usr/bin" \ "$APPDIR/usr/lib" \ "$APPDIR/usr/share/applications" \ "$APPDIR/usr/share/icons/hicolor/256x256/apps" \ "$APPDIR/usr/share/icons/hicolor/128x128/apps" \ "$APPDIR/usr/share/metainfo" cp -a "${ROOT}/dist/SyncGames" "$APPDIR/usr/lib/syncgames" ln -sf "../lib/syncgames/SyncGames" "$APPDIR/usr/bin/SyncGames" python3 - <<'PY' from PIL import Image from pathlib import Path base = Path("build/appimage/AppDir/usr/share/icons/hicolor") color = (24, 72, 64, 255) # deep teal — save/sync feel, not purple AI default for size in (256, 128): p = base / f"{size}x{size}" / "apps" / "syncgames.png" p.parent.mkdir(parents=True, exist_ok=True) Image.new("RGBA", (size, size), color).save(p) PY cp "$ROOT/packaging/appimage/syncgames.desktop" "$APPDIR/usr/share/applications/" cp "$APPDIR/usr/share/applications/syncgames.desktop" "$APPDIR/" cat > "$APPDIR/usr/share/metainfo/io.github.syncgames.appdata.xml" < io.github.syncgames SyncGames Session-gated game save sync setup and management CC0-1.0 MIT

Configure MinIO SSOT connection, manage game save paths, and run start/end session sync with lease and version guardrails.

syncgames.desktop
EOF cat > "$APPDIR/AppRun" <<'SH' #!/bin/bash HERE="$(dirname "$(readlink -f "$0")")" export PATH="${HERE}/usr/bin:${PATH}" LIBDIR="${HERE}/usr/lib/syncgames" export LD_LIBRARY_PATH="${LIBDIR}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" if [[ -d "${LIBDIR}/PySide6" ]]; then export QT_PLUGIN_PATH="${LIBDIR}/PySide6/Qt/plugins${QT_PLUGIN_PATH:+:$QT_PLUGIN_PATH}" fi exec "${HERE}/usr/bin/SyncGames" "$@" SH chmod +x "$APPDIR/AppRun" ln -sf "usr/share/icons/hicolor/256x256/apps/syncgames.png" "$APPDIR/.DirIcon" || true # appimagetool expects Icon= name at AppDir root cp "$APPDIR/usr/share/icons/hicolor/256x256/apps/syncgames.png" "$APPDIR/syncgames.png" echo "==> appimagetool" mkdir -p "$BUILD_BIN" if [[ ! -x "$APPIMAGETOOL" ]]; then curl -fsSL -o "$APPIMAGETOOL" "$APPIMAGETOOL_URL" chmod +x "$APPIMAGETOOL" fi rm -f "${ROOT}/dist/${OUT_NAME}" || true mkdir -p "${ROOT}/dist" ARCH=x86_64 "$APPIMAGETOOL" "$APPDIR" "${ROOT}/dist/${OUT_NAME}" echo "==> Built ${ROOT}/dist/${OUT_NAME}"