From a1709225884a065d01a00e8a350aa8a828d24ff8 Mon Sep 17 00:00:00 2001 From: Voyager Date: Sun, 16 Aug 2026 08:56:03 -0400 Subject: [PATCH] fix: repair PortMaster package compatibility --- docs/PORTMASTER.md | 44 +++++++++++++---- scripts/build_portmaster.sh | 85 ++++++++++++++++++++++++++------ scripts/portmaster/NETfishing.sh | 5 +- 3 files changed, 108 insertions(+), 26 deletions(-) diff --git a/docs/PORTMASTER.md b/docs/PORTMASTER.md index 19144c0..fceea29 100644 --- a/docs/PORTMASTER.md +++ b/docs/PORTMASTER.md @@ -7,9 +7,20 @@ version-named generic ZIP. The installer-facing archive must be named ```text NETfishing.sh netfishing/ -port.json ``` +`port.json` belongs at `netfishing/port.json` in the distributable archive. +The upstream source-submission layout keeps it beside the launcher and port +directory, but PortMaster's release builder relocates it into the declared +port directory. Do not copy the source-submission layout directly into a +release ZIP. + +HarbourMaster's installer also relocates recognized non-script files found at +an archive root into the detected port directory. That compatibility behavior +masked NETfishing's former root-level `port.json` during auto-install tests. +Directly extracting the same archive into `/ports` did not perform the repair. +Do not rely on installer relocation; build the distributable layout correctly. + Do not derive a release package from an older local `portmaster-stage` directory. The templates in `scripts/portmaster/` are authoritative. @@ -30,9 +41,10 @@ directory. The templates in `scripts/portmaster/` are authoritative. `netfishing/conf/config`, and `netfishing/conf/cache`. - The archive must not contain `conf/`, saves, identities, logs, source files, `.git`, or `.godot` content. -- Release downloads must publish `netfishing.zip`. A renamed versioned ZIP is - not a substitute because HarbourMaster identifies the canonical port by - archive name. +- Release downloads must publish only the canonical `netfishing.zip` for this + platform. Do not also publish a byte-identical versioned PortMaster ZIP; + HarbourMaster identifies the port by its canonical archive name and the + Forgejo release tag already supplies the version. ## Build @@ -53,6 +65,18 @@ builds/v/netfishing.zip `--package-only` is reserved for repackaging an already validated ARM64 export. It does not rebuild game content. +For a packaging-only correction to an already published game release, commit +only PortMaster launcher, packaging-script, or PortMaster documentation changes +after the immutable release tag, then run: + +```bash +bash scripts/build_portmaster.sh --package-only --hotfix +``` + +The hotfix keeps the game executable and PCK tied to the release tag while +recording the newer packaging commit separately in `BUILD-INFO.txt`. Replace +the release's existing `netfishing.zip`; never move the game release tag. + ## Local muOS installation The muOS auto-install directory is: @@ -128,11 +152,13 @@ The device-verified Godot mapping is: `scripts/portmaster/NETfishing.sh` must replace the incompatible SDL2 entry with the Godot entry when that SDL2 GUID is selected. Do not append the two -entries with a newline: WestonPack evaluates launcher arguments through a -shell and treats the second line as a command. Pass the single selected mapping -as `SDL_GAMECONTROLLERCONFIG` in the game command after Weston initializes; -Weston sources PortMaster's control file internally and otherwise restores the -SDL2 value. +entries with a newline. WestonPack reconstructs the wrapped game command +through a shell, so values passed in that command can be split into unintended +commands. Controller names may legally contain spaces, which caused this +failure with the `GO-Super Gamepad` mapping. Export the single selected +`SDL_GAMECONTROLLERCONFIG` value through the outer `env` invocation, before +`westonwrap.sh`, so Weston and the game inherit it without tokenizing the +mapping text. Do not pass a `.gptk` controller mapping to GPTOKEYB. Its exit-only process must retain PortMaster's controller configuration, while the verified Godot diff --git a/scripts/build_portmaster.sh b/scripts/build_portmaster.sh index 5da4b10..908c185 100755 --- a/scripts/build_portmaster.sh +++ b/scripts/build_portmaster.sh @@ -8,12 +8,25 @@ readonly TEMPLATE_ROOT="${SCRIPT_DIR}/portmaster" readonly GODOT_BIN="${GODOT_BIN:-godot}" PACKAGE_ONLY=0 -if [[ "${1:-}" == "--package-only" ]]; then - PACKAGE_ONLY=1 +HOTFIX=0 +while [[ $# -gt 0 ]]; do + case "$1" in + --package-only) + PACKAGE_ONLY=1 + ;; + --hotfix) + HOTFIX=1 + ;; + *) + echo "Usage: $0 [--package-only] [--hotfix]" >&2 + exit 2 + ;; + esac shift -fi -if [[ $# -ne 0 ]]; then - echo "Usage: $0 [--package-only]" >&2 +done +if [[ ${HOTFIX} -eq 1 && ${PACKAGE_ONLY} -ne 1 ]]; then + echo "PortMaster hotfixes must use an existing pinned ARM64 export." >&2 + echo "Run this script with both --package-only and --hotfix." >&2 exit 2 fi @@ -33,11 +46,30 @@ readonly ARM64_PCK="${ARM64_ROOT}/NETfishing.pck" readonly STAGE_ROOT="${RELEASE_ROOT}/portmaster-stage" readonly GAME_ROOT="${STAGE_ROOT}/netfishing" readonly ARCHIVE="${RELEASE_ROOT}/netfishing.zip" -readonly LEGACY_ARCHIVE="${RELEASE_ROOT}/netfishing-${RELEASE_TAG}-portmaster-arm64.zip" +readonly OBSOLETE_VERSIONED_ARCHIVE="${RELEASE_ROOT}/NETfishing-${RELEASE_TAG}-portmaster-arm64.zip" +readonly OBSOLETE_LOWERCASE_ARCHIVE="${RELEASE_ROOT}/netfishing-${RELEASE_TAG}-portmaster-arm64.zip" readonly HEAD_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse HEAD)" readonly TAG_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse "${RELEASE_TAG}^{commit}")" -if [[ "${HEAD_COMMIT}" != "${TAG_COMMIT}" ]]; then +if [[ ${HOTFIX} -eq 1 ]]; then + if ! git -C "${PROJECT_ROOT}" merge-base --is-ancestor \ + "${TAG_COMMIT}" "${HEAD_COMMIT}"; then + echo "${RELEASE_TAG} is not an ancestor of HEAD. Refusing hotfix package." >&2 + exit 1 + fi + + while IFS= read -r changed_path; do + case "${changed_path}" in + docs/PORTMASTER.md|scripts/build_portmaster.sh|scripts/portmaster/*) + ;; + *) + echo "Hotfix contains a non-PortMaster change: ${changed_path}" >&2 + exit 1 + ;; + esac + done < <(git -C "${PROJECT_ROOT}" diff --name-only \ + "${TAG_COMMIT}..${HEAD_COMMIT}") +elif [[ "${HEAD_COMMIT}" != "${TAG_COMMIT}" ]]; then echo "HEAD does not match ${RELEASE_TAG}. Refusing to package mutable source." >&2 exit 1 fi @@ -75,11 +107,14 @@ test -s "${ARM64_PCK}" file "${ARM64_EXECUTABLE}" | grep -q "ARM aarch64" rm -rf -- "${STAGE_ROOT}" -rm -f -- "${ARCHIVE}" "${LEGACY_ARCHIVE}" +rm -f -- \ + "${ARCHIVE}" \ + "${OBSOLETE_VERSIONED_ARCHIVE}" \ + "${OBSOLETE_LOWERCASE_ARCHIVE}" mkdir -p -- "${GAME_ROOT}/licenses" install -m 0755 "${TEMPLATE_ROOT}/NETfishing.sh" "${STAGE_ROOT}/NETfishing.sh" -install -m 0644 "${TEMPLATE_ROOT}/port.json" "${STAGE_ROOT}/port.json" +install -m 0644 "${TEMPLATE_ROOT}/port.json" "${GAME_ROOT}/port.json" install -m 0755 "${ARM64_EXECUTABLE}" "${GAME_ROOT}/NETfishing.aarch64" install -m 0644 "${ARM64_PCK}" "${GAME_ROOT}/NETfishing.pck" install -m 0644 "${TEMPLATE_ROOT}/gameinfo.xml" "${GAME_ROOT}/gameinfo.xml" @@ -107,7 +142,9 @@ cat >"${GAME_ROOT}/BUILD-INFO.txt" <"${GAME_ROOT}/README.md" </dev/null readonly TOP_LEVELS="$( unzip -Z1 "${ARCHIVE}" | cut -d/ -f1 | sort -u )" -readonly EXPECTED_TOP_LEVELS="$(printf '%s\n' NETfishing.sh netfishing port.json)" +readonly EXPECTED_TOP_LEVELS="$(printf '%s\n' NETfishing.sh netfishing)" if [[ "${TOP_LEVELS}" != "${EXPECTED_TOP_LEVELS}" ]]; then echo "Unexpected PortMaster archive roots:" >&2 printf '%s\n' "${TOP_LEVELS}" >&2 exit 1 fi -grep -q '"version": 4' "${STAGE_ROOT}/port.json" -grep -q '"name": "netfishing.zip"' "${STAGE_ROOT}/port.json" -grep -q '"rtr": true' "${STAGE_ROOT}/port.json" +grep -q '"version": 4' "${GAME_ROOT}/port.json" +grep -q '"name": "netfishing.zip"' "${GAME_ROOT}/port.json" +grep -q '"rtr": true' "${GAME_ROOT}/port.json" +if unzip -Z1 "${ARCHIVE}" | grep -qx 'port.json'; then + echo "port.json must be inside netfishing/, not at the archive root." >&2 + exit 1 +fi grep -q '^# PORTMASTER: netfishing.zip, NETfishing.sh$' \ "${STAGE_ROOT}/NETfishing.sh" grep -Fq 'PROFILE_PATH="$CONFDIR/performance_profile"' \ "${STAGE_ROOT}/NETfishing.sh" grep -Fq 'NETFISHING_PERFORMANCE_PROFILE=light' \ "${STAGE_ROOT}/NETfishing.sh" +readonly CONTROLLER_ENV_LINE="$( + grep -nF 'SDL_GAMECONTROLLERCONFIG="$netfishing_controllerconfig"' \ + "${STAGE_ROOT}/NETfishing.sh" | cut -d: -f1 +)" +readonly WESTON_LAUNCH_LINE="$( + grep -nF '"$WESTON_DIR/westonwrap.sh" headless noop kiosk crusty_x11egl' \ + "${STAGE_ROOT}/NETfishing.sh" | cut -d: -f1 +)" +if [[ -z "${CONTROLLER_ENV_LINE}" || -z "${WESTON_LAUNCH_LINE}" || \ + "${CONTROLLER_ENV_LINE}" -ge "${WESTON_LAUNCH_LINE}" ]]; then + echo "SDL_GAMECONTROLLERCONFIG must be exported before westonwrap.sh." >&2 + exit 1 +fi grep -Fq '$GPTOKEYB "NETfishing.aarch64" &' \ "${STAGE_ROOT}/NETfishing.sh" grep -Fq 'pm_platform_helper "$GAME_EXECUTABLE"' \ diff --git a/scripts/portmaster/NETfishing.sh b/scripts/portmaster/NETfishing.sh index 527f15f..43cd7e4 100755 --- a/scripts/portmaster/NETfishing.sh +++ b/scripts/portmaster/NETfishing.sh @@ -123,12 +123,13 @@ esac $GPTOKEYB "NETfishing.aarch64" & pm_platform_helper "$GAME_EXECUTABLE" -$ESUDO env CRUSTY_RESOLUTION="${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \ +$ESUDO env \ + CRUSTY_RESOLUTION="${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \ + SDL_GAMECONTROLLERCONFIG="$netfishing_controllerconfig" \ "$WESTON_DIR/westonwrap.sh" headless noop kiosk crusty_x11egl \ XDG_DATA_HOME="$CONFDIR/data" \ XDG_CONFIG_HOME="$CONFDIR/config" \ XDG_CACHE_HOME="$CONFDIR/cache" \ - SDL_GAMECONTROLLERCONFIG="$netfishing_controllerconfig" \ GODOT_SILENCE_ROOT_WARNING=1 \ "${NETFISHING_GAME_ENVIRONMENT[@]}" \ "$GAME_EXECUTABLE" \