fix(linux): unpack the builder's AppImage, not the launcher, under AppImageLauncher #82

Merged
HumanBean merged 1 commit from HumanBean/LongshotLauncher:fix/appimagelauncher-target-appimage into main 2026-11-15 07:09:40 +00:00
Owner

On Linux with AppImageLauncher, installing a builder unpacks the launcher itself into the toolchain folder, so the version shows "Can't be read". It never fixes itself, because toolchain.json records the builder's SHA. rc.4's magic-clearing fix (ff78d8b) isn't enough on its own.

Why it happens: AppImageLauncher starts AppImages through binfmt-bypass, which sets TARGET_APPIMAGE=<launcher's AppImage>. AppImageKit's runtime mounts or extracts TARGET_APPIMAGE when it is set, not itself (appimage_path = getenv("TARGET_APPIMAGE") in runtime.c). The launcher removed APPIMAGE and APPDIR before starting the builder's --appimage-extract, but not TARGET_APPIMAGE, so the builder's runtime quietly extracted the launcher's squashfs. You can reproduce it without the launcher:

python3 -c "f=open('Longshot-v3.0.0-rc.4-x86_64.AppImage','r+b'); f.seek(8); f.write(b'\0\0\0')"
TARGET_APPIMAGE=/path/to/any/AppImage ./Longshot-v3.0.0-rc.4-x86_64.AppImage --appimage-extract
# squashfs-root holds the other AppImage's files; without the variable it is right

What changed

  • Core/Toolchains.cs: the new WithoutOurAppImage removes APPIMAGE, APPDIR and TARGET_APPIMAGE from the environment. ExtractAppImage uses it.
  • Core/SelfUpdate.cs: SelfCheckAsync uses it too. Otherwise, under AppImageLauncher, the staged new launcher's --self-check could run the old launcher and answer with the old tag.
  • Core/Toolchains.cs: an unpacked AppImage that holds usr/bin/LongshotLauncher (the launcher's program, scripts/package.sh) is refused with an error instead of being installed. A Linux version folder that already holds it no longer counts as installed (Read), so broken installs from rc.4 and earlier get installed again the next time they are needed.

Tested (CachyOS, Linux 7.3)

  • python -I tests/test_launcher_core.py: 1049 checks passed. New checks: WithoutOurAppImage removes the three variables and keeps the rest; an extract that yields the launcher is refused and leaves no version behind; a version folder holding the launcher counts as not installed and is installed again.
  • python -I tests/test_release.py: 28 tests, OK.

Not tested: a real install under AppImageLauncher with this build. The reporter's exec trace and the reproduction above show the cause.

🤖 Generated with Claude Code

On Linux with AppImageLauncher, installing a builder unpacks the launcher itself into the toolchain folder, so the version shows "Can't be read". It never fixes itself, because `toolchain.json` records the builder's SHA. rc.4's magic-clearing fix (ff78d8b) isn't enough on its own. **Why it happens:** AppImageLauncher starts AppImages through binfmt-bypass, which sets `TARGET_APPIMAGE=<launcher's AppImage>`. AppImageKit's runtime mounts or extracts `TARGET_APPIMAGE` when it is set, not itself (`appimage_path = getenv("TARGET_APPIMAGE")` in `runtime.c`). The launcher removed `APPIMAGE` and `APPDIR` before starting the builder's `--appimage-extract`, but not `TARGET_APPIMAGE`, so the builder's runtime quietly extracted the launcher's squashfs. You can reproduce it without the launcher: ```sh python3 -c "f=open('Longshot-v3.0.0-rc.4-x86_64.AppImage','r+b'); f.seek(8); f.write(b'\0\0\0')" TARGET_APPIMAGE=/path/to/any/AppImage ./Longshot-v3.0.0-rc.4-x86_64.AppImage --appimage-extract # squashfs-root holds the other AppImage's files; without the variable it is right ``` **What changed** - `Core/Toolchains.cs`: the new `WithoutOurAppImage` removes `APPIMAGE`, `APPDIR` and `TARGET_APPIMAGE` from the environment. `ExtractAppImage` uses it. - `Core/SelfUpdate.cs`: `SelfCheckAsync` uses it too. Otherwise, under AppImageLauncher, the staged new launcher's `--self-check` could run the old launcher and answer with the old tag. - `Core/Toolchains.cs`: an unpacked AppImage that holds `usr/bin/LongshotLauncher` (the launcher's program, `scripts/package.sh`) is refused with an error instead of being installed. A Linux version folder that already holds it no longer counts as installed (`Read`), so broken installs from rc.4 and earlier get installed again the next time they are needed. **Tested** (CachyOS, Linux 7.3) - `python -I tests/test_launcher_core.py`: 1049 checks passed. New checks: `WithoutOurAppImage` removes the three variables and keeps the rest; an extract that yields the launcher is refused and leaves no version behind; a version folder holding the launcher counts as not installed and is installed again. - `python -I tests/test_release.py`: 28 tests, OK. **Not tested:** a real install under AppImageLauncher with this build. The reporter's exec trace and the reproduction above show the cause. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(linux): unpack the builder's AppImage, not the launcher, under AppImageLauncher
All checks were successful
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 12s
41b6e477f0
AppImageLauncher's binfmt-bypass sets TARGET_APPIMAGE to the launcher's own
AppImage, and an AppImage's runtime mounts or unpacks TARGET_APPIMAGE when it is
set. The builder's --appimage-extract unpacked the launcher into the toolchain
folder, which the build then could not read.

- Toolchains.WithoutOurAppImage drops APPIMAGE, APPDIR and TARGET_APPIMAGE; the
  builder's extract and the self-update's --self-check use it.
- An unpacked AppImage holding usr/bin/LongshotLauncher is refused, and a Linux
  version folder that holds it counts as not installed, so it is installed again.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
HumanBean deleted branch fix/appimagelauncher-target-appimage 2026-11-15 07:09:40 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/LongshotLauncher!82
No description provided.