From c13beff6b54e7df1ba41a9f346d6974da89e175c Mon Sep 17 00:00:00 2001 From: Sergio Date: Mon, 16 Mar 2026 10:17:30 +0100 Subject: [PATCH] afegit setup-quake --- .gitignore | 4 ++ README.md | 45 ++++++++++++ setup-quake/build.sh | 27 +++++++ setup-quake/config.ini | 3 + setup-quake/requirements.txt | 1 + setup-quake/setup_quake.py | 132 +++++++++++++++++++++++++++++++++++ 6 files changed, 212 insertions(+) create mode 100755 setup-quake/build.sh create mode 100644 setup-quake/config.ini create mode 100644 setup-quake/requirements.txt create mode 100644 setup-quake/setup_quake.py diff --git a/.gitignore b/.gitignore index 637dded..5c206bd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ setup-network/build/ setup-network/dist/ setup-network/*.spec setup-network/.venv/ +setup-quake/build/ +setup-quake/dist/ +setup-quake/*.spec +setup-quake/.venv/ diff --git a/README.md b/README.md index 14cadf6..e5c36c7 100644 --- a/README.md +++ b/README.md @@ -58,3 +58,48 @@ hostname_prefix = retro-alcoi- `/etc/network/interfaces`. Re-running with the same or a different machine number is safe (idempotent). + +### setup-quake + +Installs `ioquake3` from the Debian package manager and downloads/extracts the +Quake 3 data files from a private server to the real user's home directory. + +``` +sudo ./setup-quake +``` + +See [`setup-quake/`](setup-quake/) for source and build instructions. + +#### Quick start + +```bash +cd setup-quake/ +python3 -m venv .venv +.venv/bin/pip install -r requirements.txt +bash build.sh +# Binary is at dist/setup-quake +``` + +Copy `dist/setup-quake` and `dist/config.ini` to a USB stick, then on each +fair PC: + +```bash +sudo ./setup-quake +``` + +#### Configuration + +Edit `config.ini` (alongside the binary) before distributing: + +```ini +[quake] +files_url = https://php.sustancia.synology.me/files/ioquake3-files.zip +install_dir = .q3a +``` + +#### How it works + +1. Installs `ioquake3` via `apt-get`. +2. Downloads the Quake 3 data files zip from the configured URL. +3. Extracts the data files to `~/.q3a` (resolved via `$SUDO_USER` so the real + user's home is used, not root's). diff --git a/setup-quake/build.sh b/setup-quake/build.sh new file mode 100755 index 0000000..11f4a69 --- /dev/null +++ b/setup-quake/build.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Navigate to setup-quake/ regardless of where we're called from +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# Activate virtualenv if present, otherwise require pyinstaller in PATH +if [[ -f .venv/bin/activate ]]; then + source .venv/bin/activate + echo "Activated .venv" +elif ! command -v pyinstaller &>/dev/null; then + echo "Error: pyinstaller not found. Either create a .venv or install pyinstaller." >&2 + echo " python3 -m venv .venv && .venv/bin/pip install -r requirements.txt" >&2 + exit 1 +fi + +echo "Building setup-quake binary..." +pyinstaller --onefile --clean --name setup-quake setup_quake.py + +echo "Copying config.ini to dist/..." +cp config.ini dist/ + +echo "" +echo "Build complete. Output:" +echo " ${SCRIPT_DIR}/dist/setup-quake" +echo " ${SCRIPT_DIR}/dist/config.ini" diff --git a/setup-quake/config.ini b/setup-quake/config.ini new file mode 100644 index 0000000..1536d27 --- /dev/null +++ b/setup-quake/config.ini @@ -0,0 +1,3 @@ +[quake] +files_url = https://php.sustancia.synology.me/files/ioquake3-files.zip +install_dir = .q3a diff --git a/setup-quake/requirements.txt b/setup-quake/requirements.txt new file mode 100644 index 0000000..ef376ca --- /dev/null +++ b/setup-quake/requirements.txt @@ -0,0 +1 @@ +pyinstaller diff --git a/setup-quake/setup_quake.py b/setup-quake/setup_quake.py new file mode 100644 index 0000000..4a7b2dd --- /dev/null +++ b/setup-quake/setup_quake.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +""" +setup-quake: Install ioquake3 and download Quake 3 data files +to the real user's home directory for use at a retro gaming fair. + +Usage: sudo ./setup-quake +""" + +import argparse +import configparser +import os +import pwd +import subprocess +import sys +import urllib.request +import zipfile + + +def get_script_dir(): + """Return the directory containing the script or binary.""" + if getattr(sys, "frozen", False): + return os.path.dirname(sys.executable) + return os.path.dirname(os.path.abspath(__file__)) + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Install ioquake3 and download Quake 3 data files." + ) + parser.parse_args() + + +def check_root(): + if os.geteuid() != 0: + print("Error: this script must be run as root (use sudo).", file=sys.stderr) + sys.exit(1) + + +def load_config(): + config_path = os.path.join(get_script_dir(), "config.ini") + cfg = configparser.ConfigParser() + cfg.read(config_path) + files_url = cfg.get("quake", "files_url", fallback="https://php.sustancia.synology.me/files/ioquake3-files.zip") + install_dir = cfg.get("quake", "install_dir", fallback=".q3a") + return files_url, install_dir + + +def get_real_home(): + """Resolve the actual user's home when running under sudo.""" + sudo_user = os.environ.get("SUDO_USER") + if sudo_user: + home_dir = pwd.getpwnam(sudo_user).pw_dir + return home_dir, sudo_user + home_dir = os.path.expanduser("~") + return home_dir, "root" + + +def install_ioquake3(): + print(" Running: apt-get install -y ioquake3") + subprocess.run(["apt-get", "install", "-y", "ioquake3"], check=True) + + +def download_files(url): + """Download the Quake 3 files zip to /tmp. Returns destination path.""" + dest = "/tmp/ioquake3-files.zip" + print(f" Downloading: {url}") + print(f" Destination: {dest}") + + with urllib.request.urlopen(url) as response: + total = response.headers.get("Content-Length") + total_mb = f"{int(total) / 1024 / 1024:.1f} MB" if total else "unknown size" + print(f" File size: {total_mb}") + + downloaded = 0 + chunk_size = 1024 * 1024 # 1 MB + with open(dest, "wb") as f: + while True: + chunk = response.read(chunk_size) + if not chunk: + break + f.write(chunk) + downloaded += len(chunk) + print(f" Downloaded: {downloaded / 1024 / 1024:.1f} MB", end="\r") + + print() # newline after progress + return dest + + +def extract_files(zip_path, home_dir, install_dir): + target = os.path.join(home_dir, install_dir) + print(f" Extracting to: {target}") + os.makedirs(target, exist_ok=True) + + with zipfile.ZipFile(zip_path) as zf: + zf.extractall(target) + + os.remove(zip_path) + print(f" Cleaned up: {zip_path}") + + +def main(): + parse_args() + check_root() + + files_url, install_dir = load_config() + home_dir, username = get_real_home() + + print("=== setup-quake ===") + print(f" User : {username}") + print(f" Home directory : {home_dir}") + print(f" Install dir : {os.path.join(home_dir, install_dir)}") + print() + + print("[1/3] Installing ioquake3...") + install_ioquake3() + print() + + print("[2/3] Downloading Quake 3 data files...") + zip_path = download_files(files_url) + print() + + print("[3/3] Extracting data files...") + extract_files(zip_path, home_dir, install_dir) + print() + + print("Done. Verify with:") + print(f" dpkg -l ioquake3") + print(f" ls {os.path.join(home_dir, install_dir)}") + + +if __name__ == "__main__": + main()