#!/usr/bin/env bash # godot-docker.sh — run Godot Linux headless inside a freeze-proof Docker container. # # Why: `godot --headless --import` and similar commands kernel-panicked plum # twice and freeze apricot when run cold. Containers on macOS run inside a # Linux VM with its own kernel, fully isolated from macOS — no chance of # tripping the GPU/video kexts that caused the panics. Cgroup limits below # also keep the VM from starving itself. # # See: ~/.claude/plans/godot-container-runner.md # # Usage: # scripts/godot-docker.sh [args...] # passed straight to godot # scripts/godot-docker.sh --version # smoke test # scripts/godot-docker.sh --headless --import # warm the import cache # scripts/godot-docker.sh --headless --script res://addons/gut/gut_cmdln.gd -gexit -gtest=res://engine/tests/unit/test_city_buildable_helper.gd set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" DOCKERFILE="$REPO_ROOT/tools/docker/Dockerfile.godot" IMAGE="mc-godot:4.6.2" VOLUME="mc-godot-cache" WORKDIR_IN_CONTAINER="/work/src/game" # Cgroup hard caps so the container can't starve the host VM. # Defaults sized for Docker Desktop with ≥7 GiB allocated. CPUS="${MC_GODOT_CPUS:-4}" MEMORY="${MC_GODOT_MEMORY:-6g}" PIDS_LIMIT="${MC_GODOT_PIDS:-256}" ensure_image() { if docker image inspect "$IMAGE" >/dev/null 2>&1; then return 0 fi echo "[godot-docker] image $IMAGE not found — building..." >&2 docker build \ --tag "$IMAGE" \ --file "$DOCKERFILE" \ "$REPO_ROOT/tools/docker" } ensure_volume() { if docker volume inspect "$VOLUME" >/dev/null 2>&1; then return 0 fi echo "[godot-docker] creating named volume $VOLUME for warm import cache" >&2 docker volume create "$VOLUME" >/dev/null } ensure_docker_running() { if ! docker info >/dev/null 2>&1; then echo "ERROR: Docker daemon not reachable. Start Docker Desktop first." >&2 exit 2 fi } main() { ensure_docker_running ensure_image ensure_volume # Force a TTY only when stdout is a terminal; CI invocations stay non-interactive. local tty_flag="" if [[ -t 1 ]]; then tty_flag="-t" fi docker run \ --rm \ -i $tty_flag \ --cpus "$CPUS" \ --memory "$MEMORY" \ --memory-swap "$MEMORY" \ --pids-limit "$PIDS_LIMIT" \ --volume "$REPO_ROOT:/work" \ --volume "$VOLUME:/work/src/game/.godot" \ --workdir "$WORKDIR_IN_CONTAINER" \ "$IMAGE" \ "$@" } main "$@"