Empaqueta jlauncher com a .app + .dmg per a macOS

This commit is contained in:
2026-05-30 15:34:29 +02:00
parent c879127401
commit 95a76d0d76
7 changed files with 293 additions and 32 deletions
+55 -2
View File
@@ -9,11 +9,16 @@ Ejecutando desde fuente usamos la raíz del proyecto (la carpeta que contiene ``
from __future__ import annotations
import os
import shutil
import sys
from pathlib import Path
CONFIG_NAME = "games.toml"
# Carpeta de soporte en macOS cuando corremos como .app: ~/Library/Application Support/…
APP_SUPPORT_VENDOR = "jailgames"
APP_SUPPORT_APP = "jlauncher"
def is_compiled() -> bool:
"""True si corremos como binario Nuitka (define ``__compiled__`` en cada módulo)."""
@@ -34,14 +39,62 @@ def base_dir() -> Path:
return Path(__file__).resolve().parent.parent
def macos_app_bundle() -> Path | None:
"""Ruta del .app si corremos como bundle de macOS (``…/jlauncher.app``); si no, None.
En un app bundle el ejecutable vive en ``…/jlauncher.app/Contents/MacOS/jlauncher``,
dentro de un árbol no escribible al instalarse en ``/Applications``. Detectarlo nos
deja redirigir datos y settings a ``~/Library/Application Support``.
"""
if not is_compiled() or sys.platform != "darwin":
return None
exe = Path(sys.executable).resolve()
for parent in exe.parents:
if parent.suffix == ".app":
return parent
return None
def support_dir() -> Path:
"""Carpeta de soporte escribible en macOS (.app); se crea si no existe."""
root = (
Path.home()
/ "Library"
/ "Application Support"
/ APP_SUPPORT_VENDOR
/ APP_SUPPORT_APP
)
root.mkdir(parents=True, exist_ok=True)
return root
def writable_base() -> Path:
"""Base donde escribir datos/settings: Application Support si .app, si no base_dir()."""
if macos_app_bundle() is not None:
return support_dir()
return base_dir()
def config_file() -> Path:
"""Ruta a games.toml (junto al ejecutable / raíz del proyecto)."""
"""Ruta a games.toml.
En .app vive en Application Support (editable y persistente); se siembra la primera vez
desde ``Contents/Resources/games.toml`` del bundle. Si no, junto al ejecutable / raíz.
"""
bundle = macos_app_bundle()
if bundle is not None:
target = writable_base() / CONFIG_NAME
if not target.exists():
seed = bundle / "Contents" / "Resources" / CONFIG_NAME
if seed.exists():
shutil.copy2(seed, target)
return target
return base_dir() / CONFIG_NAME
def data_root(data_dir: str = "jlauncher_data") -> Path:
"""Carpeta raíz de datos; se crea si no existe."""
root = base_dir() / data_dir
root = writable_base() / data_dir
root.mkdir(parents=True, exist_ok=True)
return root
+3 -3
View File
@@ -1,4 +1,4 @@
"""Preferencias persistentes en settings.json, junto al ejecutable."""
"""Preferencias persistentes en settings.json, junto a los datos de la app."""
from __future__ import annotations
@@ -6,7 +6,7 @@ import json
from dataclasses import asdict, dataclass, field
from pathlib import Path
from .paths import base_dir
from .paths import writable_base
SETTINGS_NAME = "settings.json"
@@ -43,7 +43,7 @@ class Settings:
def settings_path() -> Path:
return base_dir() / SETTINGS_NAME
return writable_base() / SETTINGS_NAME
def load_settings() -> Settings: