Conversation
…ries Volume layout (breaking — v1 volumes refused on start, see migrate-v1-to-v2.sh): app/configs/ user-facing real *.cfg files (flat); SOT app/logs/ stable symlinks (unchanged) app/runtime/gamefiles/, app/runtime/plutonium/ app/.plutainer-version=2 Each entry script fans out symlinks from app/configs/*.cfg into the engine's expected config dir, so games read configs through symlinks back to the user-facing dir. RCON writeconfig writes back transparently. Env vars unified: PLUTAINER_GAME/CONFIG_FILE/PORT/SERVER_NAME/MOD/AUTO_UPDATE/ HEALTHCHECK/SKIP_SEED/EXTRA_ARGS. Old PLUTO_/IW4X_/ALTER_ prefixes still work via shim_env_vars in game-config.sh, emit [DEPRECATED] warning. PLUTO_SERVER_KEY, PLUTO_MAX_CLIENTS, IW4X_NET_LOG_IP keep original names (single-family vars). Other fixes folded in: - Symlink existence guards via new link_files helper (eliminates dangling symlinks when host gamefiles are missing — same class as the prior t7x '*' bug). - set -euo pipefail in all entry scripts. - wget -N for t7x.exe (skip redownload when unchanged). - HEALTHCHECK start-period: 1m -> 5m for slow first-run downloads. - migrate-v1-to-v2.sh handles the volume restructure (supports --dry-run). - .gitattributes pins shell/python/Dockerfile to LF.
Indirect expansion ${!var} and bare ${VAR} both error out under set -u when
the referenced variable is unset. Add :- default so the strict mode in entry
scripts works when canonical PLUTAINER_* vars (or any old-prefix ones) are
absent.
Workflow now triggers on pushes to main and v2-layout. Tag rules: - :latest only when is_default_branch (= main). - :v2 only when github.ref == refs/heads/v2-layout. These conditions are mutually exclusive, so v2 builds never touch :latest and main builds never touch :v2. Both branches still get a :sha-<short> tag. Doc references updated from :main to :v2.
…, mod fan-out Breaking (only on :v2 — :latest unaffected): * shim_env_vars removed. PLUTO_*/IW4X_*/ALTER_* prefix env vars no longer recognised. PLUTAINER_* is the only accepted form (plus the three unique vars PLUTO_SERVER_KEY, PLUTO_MAX_CLIENTS, IW4X_NET_LOG_IP). New: * PLUTAINER_USE_RAW_CONFIGS=true opts out of the configs/ symlink system; engine path becomes the SOT directly. Default off. * ensure_config_present: auto-lifts CONFIG_FILE from engine path to configs/ if found as a real file there; refuses startup with case-insensitive find-iname hint if absent everywhere. * resolve_mod_config_dir + link_configs variadic: when PLUTAINER_MOD is set, cfg symlinks fan out into BOTH the base engine config dir AND the mod-scoped dir (plutonium fs_game / iw4x mod path). Alterware skipped (Workshop ID, not a path). * link_configs refuses to overwrite a real file at engine path; warns instead. Prevents the silent-replace failure mode. * hold_indefinitely: on startup validation failure, exec sleep infinity so the container stays Up and docker doesn't loop restart it. User fixes the config and runs docker restart. * launch_game: 30s sleep after wine exits before container exits, so restart policies (no min-delay knob in compose) throttle to ~1 restart per 30s on real crashes. * Improved extract_rcon_password: handles single-quoted and unquoted forms; on failure emits a structured WARN telling the user the accepted forms and not to set rcon_password via PLUTAINER_EXTRA_ARGS. Doesn't block startup. Docs updated (README + CLAUDE.md): removed deprecated-prefix table, documented PLUTAINER_USE_RAW_CONFIGS, auto-lift, refuse behavior, restart throttle, and the rcon parser accepted forms.
…r file Original order: seed_configs (cp -n) before ensure_config_present meant a user's real cfg at engine path got bypassed because seed had already filled configs/ with a default basename, satisfying the SOT check. Now auto_lift_user_config runs before seed: if user has a real (non-symlink) cfg at engine path, mv -f it to configs/ unconditionally. Then seed gap-fills (cp -n preserves the user file). Then link_configs fans out. Then ensure_config_present only does the presence-or-refuse check. Three callers updated: alterentry, plutoentry, iw4xentry.
A sidecar that bind-mounts an individual log file (e.g. games_zm.log) before the file exists causes Docker to auto-create an empty root-owned directory at that host path. place_symlink's mv -Tf then fails every poll and litters logs/ with .XXX temp symlinks. Fix both reactively in place_symlink and on startup heal. Try rmdir first (empty dir, plutainer owns parent), fall back to rm -rf; if both fail (non- empty root-owned dir), log a clear error pointing at the sidecar config.
T6/T7 community cfgs commonly write `rcon_password "value"` without the `set` keyword. Engine accepts both forms; parser only accepted the prefixed form, so healthcheck and rcon-cli silently failed on stock t6zm seeds. Make the `set[a]?` prefix optional and adjust the unquoted fallback to pick the right awk column whether or not the prefix is present.
* Add ARM64 image variant with native Wine 11 via Hangover
New Dockerfile.arm64 targets aarch64 (Pi 5+, Ampere, Apple silicon under
Linux). Multi-stage build:
1. rust-builder -> native aarch64 plutonium-updater (upstream ships
no aarch64-linux release).
2. cpp-builder -> native aarch64 iw4x-launcher via build2 0.18.1
compiled from source.
3. runtime -> Debian 13 trixie + Hangover 11.4 (.deb bundle:
Wine 11 + FEX 2603 + box64 as Wine CPU plug-ins).
x86_64 Windows PE binaries (Plutonium/IW4x/T7x server exes) run under
Wine 11 thunked WoW64 with libarm64ecfex.dll as the CPU backend. No
user-space x86 emulator is required because the helper CLIs are native
aarch64.
scripts/ unchanged - the entrypoints call /home/plutainer/.plutainer/
{plutonium-updater,iw4x-launcher} by fixed path, and we drop a native
aarch64 ELF at exactly that path. The amd64 Dockerfile and its
workflow are untouched.
CI: .github/workflows/docker-publish-arm64.yml builds via QEMU on
ubuntu-latest and pushes ghcr.io/<repo>:arm64. Comment in the file
notes the ubuntu-24.04-arm runner swap for a 3-5x speedup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add curl to arm64 cpp-builder stage so build2 installer runs
The build2-install-*.sh script unconditionally `check_cmd curl`s before
fetching the toolchain source tarball; the stage shipped only wget, so
the installer exited 1 on first ARM64 build. Add curl to the apt list
and use it for the script download too for consistency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Switch arm64 CI to native ubuntu-24.04-arm runner
Plutainer is a public repo, so ARM-hosted runners are free. The
Multi-Stage Dockerfile compiles build2 from source and runs full
cargo/build2 builds; QEMU-emulated on ubuntu-latest that runs 60-90 min
and exposes flaky edge cases. Native aarch64 should land at 20-30 min
and removes QEMU as a failure surface.
setup-qemu-action removed (not needed on native arm runner).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Adapt arm64 image to v2-layout: add migrate-v1-to-v2.sh, retag
Two narrow tweaks on top of the v2 scripts:
* Dockerfile.arm64: include migrate-v1-to-v2.sh in the chmod list so the
v2 entrypoint can find it executable (was missing because the original
arm64 commit predated v2).
* CI workflow: trigger on `arm64-v2` and `v2-layout` too, and emit a
clean `:arm64-v2` tag for those branches instead of the v1-style
`arm64-{{branch}}` pattern which would produce `arm64-arm64-v2`.
scripts/ themselves come unchanged from upstream v2-layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…est promotion Pre-promotion to :latest, the v2 image needs to refuse v1 deployments cleanly. Previously the volume check printed its own refusal block but the env-var side was silent — a user pulling :latest (post-promotion) onto their v1 compose would have hit "PLUTAINER_CONFIG_FILE not set" with no hint that the rename was the cause. Changes: - detect_legacy_env_vars: scans PLUTO_*/IW4X_*/ALTER_* names, populates LEGACY_ENVS_FOUND. Returns non-zero if any are set. - check_volume_version: still validates marker / inits fresh / detects v1, but no longer prints the v1 block inline. Sets V1_VOLUME_DETECTED=true on v1 detection and returns. Marker-mismatch errors still print. - print_v1_migration_block: combined refusal block, adapts to what was detected (env, volume, or both). Shows both paths side by side — pin :v1-final or migrate via the bundled tool + env rename. - entrypoint.sh: runs both detectors before deciding to hold, so a single block surfaces every reason for refusal. - MIGRATION.md: full env mapping table, step-by-step migration, rollback. - README.md: top banner rewritten for the post-promotion tag layout. :latest = v2, :v1-final = frozen v1. - docker-publish.yml + docker-publish-arm64.yml: :v2 / :arm64-v2 enable predicates now also fire on main, so the post-merge build publishes both the canonical (:latest / :arm64) and the alias tags.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.