mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Build the Linux AppImage on a GitHub Actions Linux runner and attach it to each release.
The release is assembled on Windows, and the AppImage needs Linux (the translator's native build and appimagetool), so releases carried no Linux download. .github/workflows/linux-appimage.yml runs when a release is published, or by hand for a tag: it builds the translator, takes the button art from the release's own app zip, runs tools/make_appimage.py, checks that the AppImage starts and uploads it with its SHA-256 to that release. tools/make_appimage.py takes --prompt-art as make_kit.py does and bundles pillow, so an AppImage build can draw the Xbox, PlayStation and keyboard prompts. Pull request #273 by loteran, taken as it is. Added: the workflow installs glslc and spirv-tools, which make_appimage.py needs since the runtime's shaders are compiled at build time. The workflow does nothing until this file is on the repository's default branch on GitHub; from then on every published release starts it, with write access to that release. It was not run here, and make_appimage.py only passes a syntax check on Windows. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
68
.github/workflows/linux-appimage.yml
vendored
Normal file
68
.github/workflows/linux-appimage.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# The Linux AppImage of each release (tools/make_appimage.py), built on a Linux runner and attached to the release
|
||||
# itself: the release is assembled on Windows (tools/make_release.py), and the AppImage needs Linux (the translator's
|
||||
# NativeAOT build for linux-x64, appimagetool). It holds the build kit only, no game files, as the setup does.
|
||||
name: Linux AppImage
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build the AppImage for (it replaces one already attached)'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: write # gh release upload
|
||||
|
||||
concurrency:
|
||||
group: linux-appimage-${{ github.event.release.tag_name || inputs.tag }}
|
||||
|
||||
jobs:
|
||||
appimage:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
TAG: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
- uses: astral-sh/setup-uv@v6
|
||||
- name: Shader compilers
|
||||
# make_appimage.py compiles the runtime's own shaders (tools/build_shaders.py: glslc, spirv-as, spirv-val)
|
||||
run: sudo apt-get update && sudo apt-get install -y glslc spirv-tools
|
||||
- name: Shader translator and VMA
|
||||
run: |
|
||||
uv venv -q --python 3.12 .venv
|
||||
uv pip install -q --python .venv/bin/python pillow
|
||||
.venv/bin/python tools/build_xlate.py
|
||||
.venv/bin/python -c 'import sys; sys.path.insert(0, "tools"); import build_game; print("VMA:", build_game.vma_include())'
|
||||
- name: Button art from the release's app zip
|
||||
run: |
|
||||
# make_release.py uploads the zip with the release; wait for it if the release was published first
|
||||
for i in $(seq 1 20); do
|
||||
gh release download "$TAG" -p 'NX2navi-app-*.zip' -D "$RUNNER_TEMP/app" && break
|
||||
echo "no app zip on $TAG yet ($i)"; sleep 30
|
||||
done
|
||||
unzip -q "$RUNNER_TEMP"/app/NX2navi-app-*.zip 'prompt-art/*' -d "$RUNNER_TEMP/app" || true
|
||||
ls -d "$RUNNER_TEMP/app/prompt-art" 2>/dev/null || echo "::warning::no prompt-art in the app zip: the AppImage's builds keep the Switch prompts"
|
||||
- name: AppImage
|
||||
run: |
|
||||
uv python install -q 3.14
|
||||
py=$(find "$(uv python dir)" -maxdepth 1 -type d -name 'cpython-3.14.*-linux-x86_64-gnu' | sort -V | tail -1)
|
||||
curl -fsSL -o "$RUNNER_TEMP/appimagetool" \
|
||||
https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x "$RUNNER_TEMP/appimagetool"
|
||||
art=(); [ -d "$RUNNER_TEMP/app/prompt-art" ] && art=(--prompt-art "$RUNNER_TEMP/app/prompt-art")
|
||||
APPIMAGE_EXTRACT_AND_RUN=1 .venv/bin/python tools/make_appimage.py --python "$py" \
|
||||
--appimagetool "$RUNNER_TEMP/appimagetool" --out dist "${art[@]}"
|
||||
appimage=$(ls dist/NX2navi-Linux-*-x86_64.AppImage)
|
||||
APPIMAGE_EXTRACT_AND_RUN=1 "$appimage" --help | head -3
|
||||
(cd dist && sha256sum NX2navi-Linux-*-x86_64.AppImage > SHA256SUMS-linux.txt && cat SHA256SUMS-linux.txt)
|
||||
- name: Attach to the release
|
||||
run: gh release upload "$TAG" --clobber dist/NX2navi-Linux-*-x86_64.AppImage dist/SHA256SUMS-linux.txt
|
||||
@@ -5,9 +5,12 @@ player's PC from their own dump with tools/make_game.py, as NX2navi-Setup.exe do
|
||||
|
||||
The AppImage holds no game files: the kit's tools/, recomp/, runtime/ and docs, the shader translator built by
|
||||
tools/build_xlate.py (bin/nx2navi_xlate), the pinned Vulkan Memory Allocator header, and a relocatable CPython 3.14
|
||||
(python-build-standalone, as `uv python install 3.14` puts in ~/.local/share/uv/python) with numpy, lz4, zstandard and
|
||||
fonttools. zbic, the GPL package that unpacks the game's program files, is not bundled: the AppImage installs it with
|
||||
pip into ~/.local/share/nx2navi/pydeps the first time it runs, as the Windows launcher downloads it.
|
||||
(python-build-standalone, as `uv python install 3.14` puts in ~/.local/share/uv/python) with numpy, lz4, zstandard,
|
||||
fonttools and pillow, and with --prompt-art the button art make_game.py's prompts step draws from (as make_kit.py
|
||||
--prompt-art: the pictures tools/prompt_art.py art_files names, into the kit's prompt-art folder; without it that step
|
||||
is skipped and the game keeps the Switch prompts). zbic, the GPL package that unpacks the game's program files, is not
|
||||
bundled: the AppImage installs it with pip into ~/.local/share/nx2navi/pydeps the first time it runs, as the Windows
|
||||
launcher downloads it.
|
||||
|
||||
The compiler and the libraries come from the system (README-BuildKit.md, "Linux"): the AppImage checks for clang,
|
||||
clang++, lld and the headers before it starts, and names the packages for Arch, Fedora and Debian/Ubuntu.
|
||||
@@ -24,7 +27,7 @@ ROOT = Path(__file__).resolve().parent.parent
|
||||
KIT_DIRS = ('recomp', 'runtime')
|
||||
KIT_FILES = ('VERSION', 'LICENSE', 'LICENSE-ADDITIONS', 'THIRD_PARTY_NOTICES.md', 'nx2navi.ini.example')
|
||||
TOOLS_SKIP = ('vendor', 'xlate', '__pycache__') # the translator ships built (bin/); its sources stay out
|
||||
PACKAGES = ('numpy==2.5.4', 'lz4==4.4.5', 'zstandard==0.25.0', 'fonttools==4.68.0')
|
||||
PACKAGES = ('numpy==2.5.4', 'lz4==4.4.5', 'zstandard==0.25.0', 'fonttools==4.68.0', 'pillow==12.3.0')
|
||||
|
||||
APPRUN = r'''#!/bin/bash
|
||||
# NX2navi build kit for Linux: builds Ocarina of Time (Switch 2, game 1.1.1) from the player's own dump.
|
||||
@@ -132,6 +135,9 @@ def main():
|
||||
help='a relocatable CPython 3.14 folder (python-build-standalone, ~/.local/share/uv/python/cpython-3.14*)')
|
||||
ap.add_argument('--appimagetool', type=Path, required=True, help='appimagetool-x86_64.AppImage')
|
||||
ap.add_argument('--out', type=Path, default=ROOT / 'dist', help='where the AppImage goes (default dist/)')
|
||||
ap.add_argument('--prompt-art', type=Path, nargs='+', metavar='FOLDER',
|
||||
help='folders holding XGamepad, P5Gamepad and Keyboard_Mouse (or those folders): the button art, as '
|
||||
'make_kit.py --prompt-art takes it (a release zip\'s prompt-art folder does too)')
|
||||
a = ap.parse_args()
|
||||
|
||||
version = (ROOT / 'VERSION').read_text(encoding='utf-8').strip()
|
||||
@@ -160,6 +166,10 @@ def main():
|
||||
shutil.copy2(xlate / f, kit / 'bin' / f)
|
||||
(kit / 'toolchain' / 'vma').mkdir(parents=True)
|
||||
shutil.copy2(ROOT / 'toolchain' / 'vma' / 'vk_mem_alloc.h', kit / 'toolchain' / 'vma' / 'vk_mem_alloc.h')
|
||||
if a.prompt_art:
|
||||
import prompt_art
|
||||
n, size = prompt_art.copy_art(a.prompt_art, kit / prompt_art.FOLDER)
|
||||
print(f'button art: {n} files, {size / 1e6:.1f} MB')
|
||||
|
||||
py = app / 'usr' / 'python'
|
||||
shutil.copytree(a.python, py, symlinks=True)
|
||||
|
||||
Reference in New Issue
Block a user