fix: an rc AppImage launch keeps the tools it shipped with #1039

Merged
bibigurl-yum merged 1 commit from fix/linux-rc-startup-manifest into main 2026-11-09 15:15:28 +00:00
bibigurl-yum commented 2026-11-09 07:41:11 +00:00 (Migrated from github.com)

What

An rc (or Actions-tab) AppImage reinstalls the previous stable release's tool tree on every launch, replacing files its own tools had. On v2.0.7-rc.1 that dropped gpu/vk/oot_cheat_items.h out of ~/.local/share/hookshot/builder/versions/v2.0.6/usr/share/hookshot/ every launch, so host/hos_main.c failed to compile (#990) — and any manually added file was wiped on relaunch, which is why the curl workaround in #990 appeared not to work.

Why it happens

begin_update.run() (builder/linux/hookshot_builder.py) fetched releases/latest/download/hookshot-linux.txt and reinstalled whenever manifest.tag != tools_tag(root). An rc build's VERSION (v2.0.7-rc.1) never equals the stable tag (v2.0.6), so every launch reinstalled versions/v2.0.6 from the stable release's parts — including usr/share/hookshot, whose zip lacks the header (its own bundled tree has it).

Fix

linux_update.startup_manifest(root): when the running AppDir ships its own hookshot-linux.txt whose tag is exactly these tools' VERSION, and update_target does not prefer the latest release over it, use that bundled list (the rc's own zips are the truth for its own files) instead of downloading the release's. This is the same "a builder that is not an older release is not made to update" rule as update_target/choose_mode (issue 902), applied to the startup reinstall.

  • A builder older than the latest release still downloads and installs it.
  • A HOOKSHOT_LINUX_LIST override still wins even when tags match.
  • begin_update() when updating a game folder uses it too: a game update on an rc no longer drags the tools back to the release.

Test

python -I -B tests/run_all.py → 106 passed, 0 failed, 14 skipped (game-free skips). Includes a new test_an_rc_build_with_its_own_list_is_not_downgraded_to_the_release covering: rc keeps its own list, a newer release still wins, HOOKSHOT_LINUX_LIST override wins at equal tags, and a builder older than the release still downloads it.

Refs #990

## What An rc (or Actions-tab) AppImage reinstalls the *previous stable release's* tool tree on every launch, replacing files its own tools had. On v2.0.7-rc.1 that dropped `gpu/vk/oot_cheat_items.h` out of `~/.local/share/hookshot/builder/versions/v2.0.6/usr/share/hookshot/` every launch, so `host/hos_main.c` failed to compile (#990) — and any manually added file was wiped on relaunch, which is why the curl workaround in #990 appeared not to work. ## Why it happens `begin_update.run()` (`builder/linux/hookshot_builder.py`) fetched `releases/latest/download/hookshot-linux.txt` and reinstalled whenever `manifest.tag != tools_tag(root)`. An rc build's VERSION (`v2.0.7-rc.1) never equals the stable tag (`v2.0.6), so every launch reinstalled `versions/v2.0.6` from the stable release's parts — including `usr/share/hookshot`, whose zip lacks the header (its own bundled tree has it). ## Fix `linux_update.startup_manifest(root)`: when the running AppDir ships its own `hookshot-linux.txt` whose tag is exactly these tools' VERSION, and `update_target` does not prefer the latest release over it, use that bundled list (the rc's own zips are the truth for its own files) instead of downloading the release's. This is the same "a builder that is not an older release is not made to update" rule as `update_target`/`choose_mode` (issue 902), applied to the startup reinstall. - A builder *older* than the latest release still downloads and installs it. - A `HOOKSHOT_LINUX_LIST` override still wins even when tags match. - `begin_update()` when updating a game folder uses it too: a game update on an rc no longer drags the tools back to the release. ## Test `python -I -B tests/run_all.py` → 106 passed, 0 failed, 14 skipped (game-free skips). Includes a new `test_an_rc_build_with_its_own_list_is_not_downgraded_to_the_release` covering: rc keeps its own list, a newer release still wins, `HOOKSHOT_LINUX_LIST` override wins at equal tags, and a builder older than the release still downloads it. Refs #990
metroid98 (Migrated from github.com) reviewed 2026-11-09 09:04:32 +00:00
metroid98 (Migrated from github.com) left a comment

AI-assisted review (Claude Code) on behalf of metroid98; code read, not run.

The logic of startup_manifest is correct for the cases I traced, and the new test does call it directly with all four outcomes (rc keeps its own list, newer release wins, HOOKSHOT_LINUX_LIST wins, older builder downloads). Two things I could not make fit current main, though:

  1. On current main the changed branch looks unreachable for an rc. begin_update only calls fetch_manifest() when fetched is False, and main computes fetched = self.fetched or bool(folder and self.tools and target == self.tools) with target = self.update_tag or linux_update.update_target(self.latest, self.tools). For an rc/Actions builder newer than releases/latest, update_target returns the tools' own tag, so fetched is True for any game-folder update and the fetch is skipped. The no-folder path is only taken in "update-builder" mode, which choose_mode only picks when update_target != tools, i.e. when the release is newer, and there startup_manifest returns the latest anyway. The tag in the v2.0.7-rc.1 and v2.0.7 trees has the older check (self.update_tag or self.latest or self.tools) == self.tools (hookshot_builder.py line 379), which compares the raw latest (v2.0.6) and so does reinstall on an rc; that is the real bug for rc.1, and main's update_target version already replaces it. So this PR is a harmless extra guard, but I don't think it is what fixes anything on main now. If you have a repro from a main-based Actions build, please say so.

  2. It doesn't explain #990/#1019/#1020/#1021/#1029. All of those report Builder version v2.0.6, which is a final release (tools == latest, so no reinstall ever runs), and the #990 error path is /tmp/.mount_.../usr/share/hookshot/nx2/../host/hos_main.c, the AppImage's own mount, not ~/.local/share/hookshot/builder/versions/.... That matches a1e80a9 (appimage.sh didn't ship gpu/vk/oot_cheat_items.h in v2.0.6), and it also explains why patching versions/v2.0.6 didn't help: the build wasn't running from there. For what it's worth, on a final release the problem doesn't reproduce: a v2.0.5 -> v2.0.7 final update and Linux build finished here (no header error, exit 0). So "Refs #990" is fine but I'd drop "the most-reported break" framing, and the cause line in the description.

Smaller points:

  • startup_manifest calls fetch_manifest() first, so an offline start still raises before the bundled list is considered. Same as before, but with a bundled list in hand it could return it when the fetch fails and tags match.
  • The test never goes through begin_update, so the call-site change in hookshot_builder.py (one line) is not exercised; fine for a one-liner.
  • Merges cleanly per GitHub (MERGEABLE); no CI checks reported.
AI-assisted review (Claude Code) on behalf of metroid98; code read, not run. The logic of `startup_manifest` is correct for the cases I traced, and the new test does call it directly with all four outcomes (rc keeps its own list, newer release wins, `HOOKSHOT_LINUX_LIST` wins, older builder downloads). Two things I could not make fit current main, though: 1. **On current main the changed branch looks unreachable for an rc.** `begin_update` only calls `fetch_manifest()` when `fetched` is False, and main computes `fetched = self.fetched or bool(folder and self.tools and target == self.tools)` with `target = self.update_tag or linux_update.update_target(self.latest, self.tools)`. For an rc/Actions builder newer than `releases/latest`, `update_target` returns the tools' own tag, so `fetched` is True for any game-folder update and the fetch is skipped. The no-folder path is only taken in "update-builder" mode, which `choose_mode` only picks when `update_target != tools`, i.e. when the release is newer, and there `startup_manifest` returns the latest anyway. The tag in the v2.0.7-rc.1 and v2.0.7 trees has the older check `(self.update_tag or self.latest or self.tools) == self.tools` (hookshot_builder.py line 379), which compares the raw latest (v2.0.6) and so does reinstall on an rc; that is the real bug for rc.1, and main's `update_target` version already replaces it. So this PR is a harmless extra guard, but I don't think it is what fixes anything on main now. If you have a repro from a main-based Actions build, please say so. 2. **It doesn't explain #990/#1019/#1020/#1021/#1029.** All of those report Builder version v2.0.6, which is a final release (tools == latest, so no reinstall ever runs), and the #990 error path is `/tmp/.mount_.../usr/share/hookshot/nx2/../host/hos_main.c`, the AppImage's own mount, not `~/.local/share/hookshot/builder/versions/...`. That matches a1e80a9 (appimage.sh didn't ship `gpu/vk/oot_cheat_items.h` in v2.0.6), and it also explains why patching `versions/v2.0.6` didn't help: the build wasn't running from there. For what it's worth, on a final release the problem doesn't reproduce: a v2.0.5 -> v2.0.7 final update and Linux build finished here (no header error, exit 0). So "Refs #990" is fine but I'd drop "the most-reported break" framing, and the cause line in the description. Smaller points: - `startup_manifest` calls `fetch_manifest()` first, so an offline start still raises before the bundled list is considered. Same as before, but with a bundled list in hand it could return it when the fetch fails and tags match. - The test never goes through `begin_update`, so the call-site change in hookshot_builder.py (one line) is not exercised; fine for a one-liner. - Merges cleanly per GitHub (`MERGEABLE`); no CI checks reported.
Commenting is not possible because the repository is archived.
No description provided.