diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 8442a8942b..4236fa6955 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -44,7 +44,7 @@ jobs: - { os: ubuntu-latest, arch: x64, family: linux, tasks: "packageReleaseDeb packageReleaseRpm" } - { os: ubuntu-latest, arch: x64, family: linux-portable, tasks: "createReleaseAppImage createReleaseDistributable" } runs-on: ${{ matrix.os }} - timeout-minutes: 45 + timeout-minutes: 60 # linux-portable leg also downloads the freedesktop runtime + builds the Flatpak bundle defaults: run: shell: bash @@ -101,6 +101,25 @@ jobs: fi chmod +x desktopApp/packaging/appimage/appimagetool-x86_64.AppImage + # Flatpak tooling + the freedesktop runtime/sdk the manifest pins + # (runtime-version is greped from the manifest so this never drifts). + # Retried: the runtime download from Flathub is ~1 GB and flatpak + # install resumes cleanly on re-run. + - name: Install Flatpak tooling + runtimes (linux-portable only) + if: matrix.family == 'linux-portable' + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + max_attempts: 3 + timeout_minutes: 15 + command: | + set -euo pipefail + sudo apt-get update && sudo apt-get install -y flatpak flatpak-builder + flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo + FDO_VER=$(grep -E "^runtime-version:" desktopApp/packaging/flatpak/com.vitorpamplona.amethyst.Desktop.yml | cut -d"'" -f2) + flatpak install --user --noninteractive flathub \ + "org.freedesktop.Platform//${FDO_VER}" \ + "org.freedesktop.Sdk//${FDO_VER}" + # macOS only: import the Developer ID Application cert into a throwaway # keychain so jpackage's codesign pass can find it. Soft — if the # MAC_CERTIFICATE_P12 secret isn't set (forks, or before Apple creds are @@ -161,6 +180,36 @@ jobs: ( cd "$APP" && tar czf "../../../../portable/amethyst-desktop-${VER}-linux-x64.tar.gz" Amethyst/ ) fi + # Flatpak bundle: wraps the same createReleaseDistributable tree the + # AppImage uses. The manifest (desktopApp/packaging/flatpak/) copies the + # prebuilt jpackage tree into /app — no Gradle runs inside the sandbox. + # build-bundle emits a single-file .flatpak whose baked-in runtime-repo + # lets the user's flatpak fetch the freedesktop runtime from Flathub on + # install. --disable-rofiles-fuse: GH runners lack a usable rofiles-fuse. + - name: Build Flatpak bundle (linux-portable only) + if: matrix.family == 'linux-portable' + run: | + set -euo pipefail + VER="${{ steps.ver.outputs.version }}" + PKG="desktopApp/packaging/flatpak" + APP_ID="com.vitorpamplona.amethyst.Desktop" + OUT="desktopApp/build/flatpak" + # Inject the AppStream entry for this build (the checked-in + # metainfo deliberately carries none — CI is the source of truth). + sed -i "s||\n |" \ + "${PKG}/${APP_ID}.metainfo.xml" + mkdir -p "$OUT" + flatpak-builder --user --force-clean --disable-rofiles-fuse \ + --state-dir="${OUT}/.flatpak-builder" \ + --repo="${OUT}/repo" \ + "${OUT}/build-dir" \ + "${PKG}/${APP_ID}.yml" + flatpak build-bundle "${OUT}/repo" \ + "${OUT}/Amethyst-${VER}-x86_64.flatpak" \ + "$APP_ID" \ + --runtime-repo=https://dl.flathub.org/repo/flathub.flatpakrepo + ls -la "$OUT" + - name: Collect + rename assets run: | set -euo pipefail diff --git a/.gitignore b/.gitignore index 45f5f1d139..2616f94e70 100644 --- a/.gitignore +++ b/.gitignore @@ -180,6 +180,11 @@ desktopApp/src/jvmMain/appResources/*/ffmpeg/* desktopApp/packaging/appimage/appimagetool-x86_64.AppImage desktopApp/packaging/appimage/squashfs-root/ +# flatpak-builder state/cache from local builds (CI uses --state-dir under desktopApp/build/) +.flatpak-builder/ +desktopApp/packaging/flatpak/build-dir/ +desktopApp/packaging/flatpak/repo/ + # Git worktrees .worktrees/ .claude/worktrees/ diff --git a/BUILDING.md b/BUILDING.md index 54b6021e97..e719e3aad2 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -37,7 +37,9 @@ Platform-specific: - **macOS**: Xcode Command Line Tools (`xcode-select --install`) - **Windows**: WiX Toolset 3.x on PATH (for MSI). `winget install WiXToolset.WiXToolset` - **Linux (all)**: nothing extra for `.deb`; `rpm` + `fakeroot` for `.rpm`; - `appimagetool` + `desktop-file-utils` for AppImage + `appimagetool` + `desktop-file-utils` for AppImage; `flatpak` + + `flatpak-builder` for the Flatpak bundle (see + [`desktopApp/packaging/flatpak/README.md`](desktopApp/packaging/flatpak/README.md)) Install Linux RPM tooling: @@ -109,6 +111,7 @@ are **not** required to build Amethyst from the committed sources. | Linux `.deb` | `./gradlew :desktopApp:packageReleaseDeb` | `desktopApp/build/compose/binaries/main-release/deb/amethyst_*.deb` | | Linux `.rpm` | `./gradlew :desktopApp:packageReleaseRpm` | `desktopApp/build/compose/binaries/main-release/rpm/amethyst-*.rpm` | | Linux AppImage | `./gradlew :desktopApp:createReleaseAppImage` | `desktopApp/build/appimage/Amethyst-*-x86_64.AppImage` | +| Linux Flatpak | `flatpak-builder` over `createReleaseDistributable` output — see [`desktopApp/packaging/flatpak/README.md`](desktopApp/packaging/flatpak/README.md) | `desktopApp/build/flatpak/Amethyst-*-x86_64.flatpak` (CI) | | Windows `.zip` portable | See below (inline `7z`) | — | | Linux `.tar.gz` portable | See below (inline `tar`) | — | @@ -148,7 +151,7 @@ Where: | `` | Tag stripped of leading `vX.YY.ZZ` | | `` | `macos`, `windows`, `linux` | | `` | `x64`, `arm64` | -| `` | `dmg`, `msi`, `zip`, `deb`, `rpm`, `AppImage`, `tar.gz` | +| `` | `dmg`, `msi`, `zip`, `deb`, `rpm`, `AppImage`, `flatpak`, `tar.gz` | Single source of truth: [`scripts/asset-name.sh`](scripts/asset-name.sh). Package manager manifests (Homebrew cask, Winget) depend on this exact scheme — @@ -160,6 +163,7 @@ Examples: - `amethyst-desktop-1.12.1-macos-arm64.dmg` - `amethyst-desktop-1.12.1-windows-x64.msi` - `amethyst-desktop-1.12.1-linux-x64.AppImage` +- `amethyst-desktop-1.12.1-linux-x64.flatpak` --- @@ -625,12 +629,18 @@ State is shared across install channels (DMG, Homebrew, MSI, Winget, .deb, expose downgrade migration risks — **prefer a single install channel per machine**. +**Exception: Flatpak.** The sandbox redirects XDG dirs into +`~/.var/app/com.vitorpamplona.amethyst.Desktop/`, so a Flatpak install keeps +its own separate state and does not see (or risk downgrading) state written +by any other channel. + | OS | App location | State directories | |---|---|---| | macOS | `/Applications/Amethyst.app` | `~/Library/Application Support/Amethyst`
`~/Library/Preferences/com.vitorpamplona.amethyst.desktop.plist`
`~/Library/Caches/Amethyst` | | Windows | `%LOCALAPPDATA%\Amethyst` or `C:\Program Files\Amethyst` | `%APPDATA%\Amethyst`
`%LOCALAPPDATA%\Amethyst` | | Linux (deb/rpm) | `/opt/amethyst` | `~/.config/amethyst`
`~/.local/share/amethyst`
`~/.cache/amethyst` | | Linux (AppImage/tar.gz) | user-chosen | Same as above | +| Linux (Flatpak) | `/var/lib/flatpak` or `~/.local/share/flatpak` | `~/.var/app/com.vitorpamplona.amethyst.Desktop/` | Uninstall: @@ -639,6 +649,8 @@ Uninstall: - .deb: `sudo apt remove amethyst` - .rpm: `sudo dnf remove amethyst` - AppImage / tar.gz: delete the file / extracted directory +- Flatpak: `flatpak uninstall com.vitorpamplona.amethyst.Desktop` (add + `--delete-data` to also remove `~/.var/app/…`) - macOS `.dmg`: drag from `/Applications` to Trash, then delete state dirs manually --- diff --git a/desktopApp/packaging/flatpak/README.md b/desktopApp/packaging/flatpak/README.md index 12bf3f3c7a..c732506f48 100644 --- a/desktopApp/packaging/flatpak/README.md +++ b/desktopApp/packaging/flatpak/README.md @@ -1,44 +1,65 @@ -# Flathub packaging for Amethyst Desktop +# Flatpak packaging for Amethyst Desktop -This directory contains the Flatpak manifest and associated metadata for -publishing Amethyst Desktop on Flathub. +This directory contains the Flatpak manifest and associated metadata. It is +used two ways: + +1. **Release CI** (`.github/workflows/create-release.yml`, `linux-portable` + leg) builds a single-file bundle from it on every tag and attaches it to + the GitHub Release as `amethyst-desktop--linux-x64.flatpak`. +2. **Flathub submission** (future) — the same manifest is the starting + point, but Flathub requires building from downloadable sources instead of + the local `type: dir` tree, so it will need a source rewrite at + submission time. ## Files -- `com.vitorpamplona.amethyst.Desktop.yml` — Flatpak manifest -- `com.vitorpamplona.amethyst.Desktop.metainfo.xml` — AppStream metadata - (categories, license, screenshots — needs screenshots added before - submission) +- `com.vitorpamplona.amethyst.Desktop.yml` — Flatpak manifest. It packages + the **prebuilt** jpackage tree from + `./gradlew :desktopApp:createReleaseDistributable` (which bundles its own + trimmed JRE — that's why there is no openjdk module/sdk-extension). +- `com.vitorpamplona.amethyst.Desktop.metainfo.xml` — AppStream metadata. + Release CI injects the `` entry for the version being built + (the checked-in file deliberately carries none); screenshots still need + to be added before any Flathub submission. - `com.vitorpamplona.amethyst.Desktop.desktop` — XDG desktop entry -- `icons/256/com.vitorpamplona.amethyst.Desktop.png` — TODO: copy a 256x256 - PNG icon from `desktopApp/src/jvmMain/resources/icon.png` before - submission - -## Build prerequisites - -- `./gradlew :desktopApp:createReleaseDistributable` — produces - `desktopApp/build/compose/binaries/main-release/app/Amethyst/` -- `flatpak install org.freedesktop.Platform//24.08 org.freedesktop.Sdk//24.08 org.freedesktop.Sdk.Extension.openjdk21//24.08` +- `icons/512/com.vitorpamplona.amethyst.Desktop.png` — 512x512 icon (copy of + `desktopApp/src/jvmMain/resources/icon.png`) ## Local build ```bash +# 1. Build the app tree the manifest packages +./gradlew :desktopApp:createReleaseDistributable + +# 2. Tooling + Flathub remote (one-time) +sudo apt-get install -y flatpak flatpak-builder # or distro equivalent +flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo + +# 3. Build + install locally cd desktopApp/packaging/flatpak -flatpak-builder --user --install --force-clean build-dir com.vitorpamplona.amethyst.Desktop.yml +flatpak-builder --user --install --install-deps-from=flathub --force-clean \ + build-dir com.vitorpamplona.amethyst.Desktop.yml flatpak run com.vitorpamplona.amethyst.Desktop ``` -## Submission to Flathub +To produce the distributable single-file bundle instead (what CI ships): -Follow https://docs.flathub.org/docs/for-app-authors/submission +```bash +flatpak-builder --user --install-deps-from=flathub --force-clean \ + --repo=repo build-dir com.vitorpamplona.amethyst.Desktop.yml +flatpak build-bundle repo amethyst.flatpak com.vitorpamplona.amethyst.Desktop \ + --runtime-repo=https://dl.flathub.org/repo/flathub.flatpakrepo +``` -1. Fork `flathub/flathub` on GitHub. -2. Branch from `new-pr` (NOT `master`). -3. Copy this manifest + AppStream + desktop into a new directory matching - the app id. -4. Open a PR titled "Add com.vitorpamplona.amethyst.Desktop". -5. After merge, a per-app repo is created with write access for ongoing - updates. +Installing the bundle: `flatpak install --user ./amethyst.flatpak`. The +`--runtime-repo` baked in above lets flatpak fetch the freedesktop runtime +from Flathub automatically on the user's machine. + +## Sandbox notes + +- `--socket=x11` (not wayland/fallback-x11): Compose Desktop renders through + AWT/skiko, which is X11-only on Linux and runs under XWayland on Wayland + sessions. ## Codec coverage @@ -47,6 +68,19 @@ Follow https://docs.flathub.org/docs/for-app-authors/submission - HLS, H.264, AAC, MP3, Opus: covered by the GStreamer plugin set in `org.freedesktop.Platform 24.08` itself. +## Submission to Flathub + +Follow https://docs.flathub.org/docs/for-app-authors/submission + +1. Fork `flathub/flathub` on GitHub. +2. Branch from `new-pr` (NOT `master`). +3. Copy this manifest + AppStream + desktop into a new directory matching + the app id, and rework the `type: dir` source into a + buildable-from-source or downloadable-artifact form per Flathub policy. +4. Open a PR titled "Add com.vitorpamplona.amethyst.Desktop". +5. After merge, a per-app repo is created with write access for ongoing + updates. + ## License metadata The manifest declares the binary as diff --git a/desktopApp/packaging/flatpak/com.vitorpamplona.amethyst.Desktop.yml b/desktopApp/packaging/flatpak/com.vitorpamplona.amethyst.Desktop.yml index 8ed6f86207..79f44e226b 100644 --- a/desktopApp/packaging/flatpak/com.vitorpamplona.amethyst.Desktop.yml +++ b/desktopApp/packaging/flatpak/com.vitorpamplona.amethyst.Desktop.yml @@ -8,8 +8,6 @@ app-id: com.vitorpamplona.amethyst.Desktop runtime: org.freedesktop.Platform runtime-version: '24.08' sdk: org.freedesktop.Sdk -sdk-extensions: - - org.freedesktop.Sdk.Extension.openjdk21 command: amethyst-desktop add-extensions: @@ -26,8 +24,11 @@ cleanup-commands: finish-args: - --share=network - --share=ipc - - --socket=fallback-x11 - - --socket=wayland + # Compose Desktop renders through AWT/skiko, which is X11-only on Linux + # (runs under XWayland on Wayland sessions). fallback-x11 + wayland would + # leave the app without a usable display socket on Wayland sessions, so + # grant x11 unconditionally. + - --socket=x11 - --socket=pulseaudio - --device=dri - --filesystem=xdg-download @@ -37,12 +38,10 @@ finish-args: # GStreamer plugin/cache paths (org.freedesktop.Platform exposes them by default). - --env=GST_PLUGIN_SYSTEM_PATH=/usr/lib/x86_64-linux-gnu/gstreamer-1.0 +# No openjdk module / sdk-extension: the jpackage tree copied below already +# bundles its own trimmed JRE under Amethyst/lib/runtime/, so installing a +# second JRE at /app/jre would only bloat the bundle. modules: - - name: openjdk - buildsystem: simple - build-commands: - - /usr/lib/sdk/openjdk21/install.sh - - name: amethyst-desktop buildsystem: simple build-commands: @@ -53,7 +52,7 @@ modules: - install -Dm755 amethyst-desktop.sh /app/bin/amethyst-desktop - install -Dm644 com.vitorpamplona.amethyst.Desktop.metainfo.xml -t /app/share/metainfo/ - install -Dm644 com.vitorpamplona.amethyst.Desktop.desktop -t /app/share/applications/ - - install -Dm644 icons/256/com.vitorpamplona.amethyst.Desktop.png -t /app/share/icons/hicolor/256x256/apps/ + - install -Dm644 icons/512/com.vitorpamplona.amethyst.Desktop.png -t /app/share/icons/hicolor/512x512/apps/ sources: # Built artifact from `./gradlew :desktopApp:createReleaseDistributable`. # Path matches Compose Multiplatform 1.11's output layout. @@ -73,5 +72,6 @@ modules: - type: file path: com.vitorpamplona.amethyst.Desktop.desktop - - type: file - path: icons/256/com.vitorpamplona.amethyst.Desktop.png + - type: dir + path: icons + dest: icons diff --git a/desktopApp/packaging/flatpak/icons/512/com.vitorpamplona.amethyst.Desktop.png b/desktopApp/packaging/flatpak/icons/512/com.vitorpamplona.amethyst.Desktop.png new file mode 100644 index 0000000000..ffe89a16f0 Binary files /dev/null and b/desktopApp/packaging/flatpak/icons/512/com.vitorpamplona.amethyst.Desktop.png differ diff --git a/scripts/asset-name.sh b/scripts/asset-name.sh index 6e82288085..908e51d565 100755 --- a/scripts/asset-name.sh +++ b/scripts/asset-name.sh @@ -8,7 +8,7 @@ # = tag stripped of leading 'v' (e.g. "1.08.0") # = macos | windows | linux # = x64 | arm64 -# = dmg | msi | zip | deb | rpm | AppImage | tar.gz +# = dmg | msi | zip | deb | rpm | AppImage | flatpak | tar.gz # # Consumed by: .github/workflows/create-release.yml, .github/workflows/bump-*.yml, # BUILDING.md, local release runbooks. @@ -26,6 +26,7 @@ # amethyst-desktop-1.08.0-linux-x64.deb # amethyst-desktop-1.08.0-linux-x64.rpm # amethyst-desktop-1.08.0-linux-x64.AppImage +# amethyst-desktop-1.08.0-linux-x64.flatpak # amethyst-desktop-1.08.0-linux-x64.tar.gz # amy-1.08.0-macos-arm64.tar.gz # amy-1.08.0-macos-x64.tar.gz @@ -74,6 +75,7 @@ collect_assets() { desktopApp/build/compose/binaries/main-release/deb/*.deb \ desktopApp/build/compose/binaries/main-release/rpm/*.rpm \ desktopApp/build/appimage/*.AppImage \ + desktopApp/build/flatpak/*.flatpak \ desktopApp/build/portable/*.tar.gz \ desktopApp/build/portable/*.zip \ ; do