magicciv/scripts/godot-docker.sh
Natalie 7678f4668f feat(@projects): add docker container wrapper for godot
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-25 14:06:52 -07:00

85 lines
2.6 KiB
Bash
Executable file

#!/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 "$@"