#!/usr/bin/env bash # Compila jlauncher con Nuitka y empaqueta un release. # - Linux: binario onefile + tar.gz. # - macOS: jlauncher.app (con icono) dentro de un .dmg arrastrable a /Applications. # Requisitos del sistema (no los instala el script): ver README (compilador C, git…). set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" cd "$HERE" VERSION="$(sed -n 's/^__version__[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' jlauncher/__init__.py | head -n1)" if [ -z "$VERSION" ]; then echo "[build] no se pudo leer __version__ de jlauncher/__init__.py" >&2 exit 1 fi ARCH="$(uname -m)" OS="$(uname -s | tr '[:upper:]' '[:lower:]')" if [ ! -d .venv ]; then echo "[build] creando venv…" python3 -m venv .venv .venv/bin/pip install --quiet --upgrade pip fi echo "[build] sincronizando dependencias…" .venv/bin/pip install --quiet -r requirements.txt if ! .venv/bin/python -c "import nuitka" 2>/dev/null; then echo "[build] instalando nuitka en el venv…" .venv/bin/pip install --quiet "nuitka[onefile]" fi # zstandard habilita la compresión del onefile (binario mucho más pequeño). if ! .venv/bin/python -c "import zstandard" 2>/dev/null; then echo "[build] instalando zstandard (compresión onefile)…" .venv/bin/pip install --quiet zstandard fi echo "[build] versión: v${VERSION}" echo "[build] limpiando artefactos previos…" rm -rf dist build app.build app.dist app.onefile-build # --------------------------------------------------------------------------- # Construye assets/icon.icns desde assets/icon.png (regenerable con make_icon.py). # --------------------------------------------------------------------------- build_icns() { local png="assets/icon.png" local icns="assets/icon.icns" if [ ! -f "$png" ]; then echo "[build] generando icono provisional (assets/icon.png)…" QT_QPA_PLATFORM=offscreen .venv/bin/python assets/make_icon.py fi echo "[build] construyendo ${icns}…" local iconset="assets/icon.iconset" rm -rf "$iconset"; mkdir -p "$iconset" local s for s in 16 32 128 256 512; do sips -z "$s" "$s" "$png" --out "$iconset/icon_${s}x${s}.png" >/dev/null sips -z $((s*2)) $((s*2)) "$png" --out "$iconset/icon_${s}x${s}@2x.png" >/dev/null done iconutil -c icns "$iconset" -o "$icns" rm -rf "$iconset" } if [ "$OS" = "darwin" ]; then # ------------------------------------------------------------------------- # macOS: app bundle + DMG # ------------------------------------------------------------------------- build_icns echo "[build] compilando jlauncher.app (PySide6; puede tardar varios minutos)…" .venv/bin/python -m nuitka \ --standalone \ --macos-create-app-bundle \ --macos-app-icon=assets/icon.icns \ --macos-app-name=jlauncher \ --macos-app-version="$VERSION" \ --macos-signed-app-name=com.jailgames.jlauncher \ --company-name=jailgames \ --product-name=jlauncher \ --product-version="$VERSION" \ --assume-yes-for-downloads \ --enable-plugin=pyside6 \ --include-package=jlauncher \ --output-dir=dist \ --output-filename=jlauncher \ --remove-output \ app.py # Según la versión, Nuitka nombra el bundle a partir del script de entrada # (app.py -> app.app). Lo normalizamos a jlauncher.app. APP="dist/jlauncher.app" if [ ! -d "$APP" ]; then PRODUCED="$(find dist -maxdepth 1 -name '*.app' | head -n1)" if [ -z "$PRODUCED" ]; then echo "[build] Nuitka no produjo ningún .app en dist/" >&2 exit 1 fi rm -rf "$APP" mv "$PRODUCED" "$APP" fi echo "[build] sembrando games.toml y icon.png en Contents/Resources…" cp games.toml "$APP/Contents/Resources/games.toml" cp assets/icon.png "$APP/Contents/Resources/icon.png" # usado por el diálogo «Quant a» # Bundle ad-hoc (sin Developer ID): quitamos quarantine para abrir sin fricción local. xattr -dr com.apple.quarantine "$APP" 2>/dev/null || true DMG="dist/jlauncher-v${VERSION}-macos-${ARCH}.dmg" echo "[build] empaquetando ${DMG}…" STAGE="$(mktemp -d)" cp -R "$APP" "$STAGE/" ln -s /Applications "$STAGE/Applications" rm -f "$DMG" hdiutil create -volname "jlauncher" -srcfolder "$STAGE" \ -ov -format UDZO "$DMG" >/dev/null rm -rf "$STAGE" echo "[build] hecho:" du -sh "$APP" | sed 's/^/[build] /' ls -lh "$DMG" echo "[build] la app guarda datos en ~/Library/Application Support/jailgames/jlauncher/." echo "[build] distribuir: el .dmg (arrastrar jlauncher.app a Aplicaciones)." echo "[build] sin firma Developer ID: primera apertura con clic derecho → Abrir." else # ------------------------------------------------------------------------- # Linux (y resto): binario onefile + tar.gz # ------------------------------------------------------------------------- RELEASE_NAME="jlauncher-v${VERSION}-${OS}-${ARCH}" echo "[build] compilando (PySide6 onefile; puede tardar varios minutos)…" .venv/bin/python -m nuitka \ --onefile \ --assume-yes-for-downloads \ --enable-plugin=pyside6 \ --include-package=jlauncher \ --output-dir=dist \ --output-filename=jlauncher \ --remove-output \ --lto=yes \ app.py echo "[build] copiando games.toml junto al binario…" cp games.toml dist/games.toml echo "[build] empaquetando release ${RELEASE_NAME}.tar.gz…" tar -czf "dist/${RELEASE_NAME}.tar.gz" -C dist jlauncher games.toml echo "[build] hecho:" ls -lh "dist/jlauncher" "dist/games.toml" "dist/${RELEASE_NAME}.tar.gz" echo "[build] el binario crea jlauncher_data/ y settings.json junto a sí mismo." echo "[build] distribuir: descomprimir el tar.gz (jlauncher + games.toml juntos)." fi