4 Commits

Author SHA1 Message Date
pc-heini 8e3fd053d8 CI: make the tag step idempotent on force rebuilds
Force-rebuilding an already-published version made the final tag push fail
("tag already exists"), turning an otherwise successful run red. Skip
tagging when the tag already exists on the remote.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:33:27 +02:00
pc-heini 583c81ed51 Fix editable-install patch for 26.05 + unblock icon in unprivileged build
The previous patch matched a development-branch variable that does not
exist in release 2605.0, so the warning fired and the editable install was
not patched. In 2605.0 the -e is hardcoded in the pip command
("pip install -e ${package_folder_path}"); strip the -e there instead.

Also, flatpak build-export validates exported app icons in a bwrap sandbox,
which fails in an unprivileged container. Keep the icon inside the app (for
the running window/taskbar) but remove it from build-dir/export so export
skips validation. Host menu icon stays generic; build needs no privileges.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:17:11 +02:00
pc-heini f4d2dddd02 Fix read-only /app failure + add app icon
On first launch O3DE pip-installs its 'o3de' CLI with 'pip install -e'
(editable), which writes an egg-info next to the source under read-only
/app and fails ([Errno 30] Read-only file system), leaving the venv broken
("unable to install O3DE's built-in Python").

- Patch cmake/LYPython.cmake at build time to force a normal (non-editable)
  install, which builds in a temp dir and lands in the writable ~/.o3de venv.
- Drop the build-time get_python "bake": the venv is per-user (keyed to
  $HOME), so it can only be created at runtime; baking under a throwaway
  build HOME did nothing. Speeds up CI; removes cmake/python3 build deps and
  the network build-arg.
- Add a real launcher icon (org.o3de.O3DE.png).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:02:41 +02:00
pc-heini 759c49bbeb Fix X11 display: share x11 unconditionally (drop fallback-x11)
O3DE's bundled Qt only ships the xcb platform plugin, so it needs X11/
XWayland. Using --socket=fallback-x11 alongside --socket=wayland meant X11
was not shared on Wayland sessions, leaving DISPLAY empty and Qt unable to
connect. Share --socket=x11 unconditionally instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:44:10 +02:00
5 changed files with 59 additions and 44 deletions
+8 -5
View File
@@ -26,11 +26,9 @@ jobs:
- name: Install build dependencies - name: Install build dependencies
run: | run: |
apt-get update apt-get update
# cmake + python3: O3DE's get_python.sh (run on the host, not in the
# sandbox) uses cmake to fetch its Python runtime.
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates curl git jq xz-utils zstd binutils tar \ ca-certificates curl git jq xz-utils zstd binutils tar \
flatpak cmake python3 flatpak
# Done as a plain git clone instead of actions/checkout@v4: the bare # Done as a plain git clone instead of actions/checkout@v4: the bare
# ubuntu image has no Node.js, so JavaScript actions fail with exit 127. # ubuntu image has no Node.js, so JavaScript actions fail with exit 127.
@@ -144,5 +142,10 @@ jobs:
TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }} TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }}
run: | run: |
AUTH_URL="$(echo "${{ github.server_url }}" | sed "s#://#://${{ github.actor }}:${TOKEN}@#")/${{ github.repository }}.git" AUTH_URL="$(echo "${{ github.server_url }}" | sed "s#://#://${{ github.actor }}:${TOKEN}@#")/${{ github.repository }}.git"
git tag "v${{ steps.ver.outputs.version }}" TAG="v${{ steps.ver.outputs.version }}"
git push "$AUTH_URL" "v${{ steps.ver.outputs.version }}" if git ls-remote --tags "$AUTH_URL" "refs/tags/$TAG" | grep -q .; then
echo "Tag $TAG already exists (force rebuild) - leaving it in place."
else
git tag "$TAG"
git push "$AUTH_URL" "$TAG"
fi
+21 -12
View File
@@ -127,18 +127,27 @@ These were confirmed by inspecting the v26.05 package (`opt/O3DE/26.05/…`):
engine compiles project code at runtime. Those live in the SDK. Users therefore engine compiles project code at runtime. Those live in the SDK. Users therefore
pull the SDK runtime (larger than Platform) on install — Flatpak does this pull the SDK runtime (larger than Platform) on install — Flatpak does this
automatically from Flathub. automatically from Flathub.
- **Python is baked in at build time.** O3DE normally downloads its Python runtime - **Python is per-user, not baked in.** On first launch O3DE downloads its Python
into its own install tree on first use, but that tree is read-only inside a runtime and builds a venv under `~/.o3de` (writable), pip-installing its deps
Flatpak. The manifest runs `python/get_python.sh` during the build (with network there. The build does **not** bundle Python — the venv is keyed to the user's
access) so Python is part of the immutable image. **This is the most likely step home path, so it can only be created at runtime.
to need tweaking** — verify it on the first real CI build. - **The editable-install patch.** O3DE installs its own `o3de` CLI with
- **Runtime writes into the install tree may still fail.** Anything O3DE tries to `pip install -e`, which writes an `egg-info` next to the source under read-only
`pip install` or generate *inside* `/opt/O3DE/...` at runtime (e.g. per-gem `/app` and fails. The build patches `cmake/LYPython.cmake` to drop the `-e`, so
Python deps when building certain projects) will hit the read-only `/app`. Base it's a normal install (built in a temp dir, landing in the writable `~/.o3de`
project building should work; exotic gems may not. This is the main open risk. venv). If a future O3DE release changes that pip command, the build prints a
- **No launcher icon yet.** The `.deb` ships only in-editor asset icons, so the warning and Python setup will fail at runtime — that's the line to re-check.
desktop entry uses a generic icon. Drop a real O3DE logo into the repo and - **Other runtime writes into the install tree may still fail.** Anything else
install it in the manifest to fix this. O3DE tries to generate *inside* `/opt/O3DE/...` at runtime (e.g. certain per-gem
Python deps, or the engine-level asset cache) hits the read-only `/app`. Project
data lives in your writable home dir, so normal project work should be fine;
this is the main remaining open risk.
- **Launcher icon.** Shipped as `org.o3de.O3DE.png` (the `.deb` itself has only
in-editor asset icons). It's kept *inside* the app so the running window/taskbar
shows it, but removed from the *exported* set because `flatpak build-export`
validates exported icons in a bwrap sandbox that fails in an unprivileged
container. Consequence: the host menu launcher icon is generic. A privileged
runner would let us export it properly.
- **GPU / drivers:** the renderer needs working GPU access. The manifest grants - **GPU / drivers:** the renderer needs working GPU access. The manifest grants
`--device=dri`/`--device=all`; on some setups you may also want the matching `--device=dri`/`--device=all`; on some setups you may also want the matching
GPU driver extension from Flathub. GPU driver extension from Flathub.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

+11 -18
View File
@@ -16,8 +16,7 @@ command: o3de-wrapper.sh
finish-args: finish-args:
- --share=ipc - --share=ipc
- --share=network # Project Manager fetches gems/templates; engine downloads assets - --share=network # Project Manager fetches gems/templates; engine downloads assets
- --socket=x11 - --socket=x11 # O3DE's bundled Qt only ships the xcb plugin, so X11/XWayland is required
- --socket=fallback-x11
- --socket=wayland - --socket=wayland
- --socket=pulseaudio - --socket=pulseaudio
- --device=dri # GPU access for the renderer - --device=dri # GPU access for the renderer
@@ -29,11 +28,6 @@ finish-args:
modules: modules:
- name: o3de - name: o3de
buildsystem: simple buildsystem: simple
# The Python bootstrap step (below) downloads O3DE's Python runtime into the
# install tree, so this module needs network access during the build.
build-options:
build-args:
- --share=network
build-commands: build-commands:
# The .deb is an `ar` archive containing data.tar.{gz,xz,zst}. # The .deb is an `ar` archive containing data.tar.{gz,xz,zst}.
- ar x o3de.deb - ar x o3de.deb
@@ -43,25 +37,22 @@ modules:
# is kept for robustness in case a future release adds desktop glue there.) # is kept for robustness in case a future release adds desktop glue there.)
- 'if [ -d data/opt ]; then mkdir -p "${FLATPAK_DEST}/opt"; cp -a data/opt/. "${FLATPAK_DEST}/opt/"; fi' - 'if [ -d data/opt ]; then mkdir -p "${FLATPAK_DEST}/opt"; cp -a data/opt/. "${FLATPAK_DEST}/opt/"; fi'
- 'if [ -d data/usr ]; then cp -a data/usr/. "${FLATPAK_DEST}/"; fi' - 'if [ -d data/usr ]; then cp -a data/usr/. "${FLATPAK_DEST}/"; fi'
# O3DE fetches its own Python runtime on first use, writing into its install # On first launch O3DE pip-installs its 'o3de' CLI editable ('pip install
# tree. That tree is read-only at runtime in a Flatpak, so bake Python in now # -e'), which writes an egg-info into read-only /app and fails. Force a
# while ${FLATPAK_DEST} is still writable. # normal install (built in a temp dir, lands in the writable ~/.o3de venv).
- | - |
set -e set -e
ENGINE_DIR=$(find "${FLATPAK_DEST}/opt/O3DE" -mindepth 1 -maxdepth 1 -type d | head -n1) LYPYTHON=$(find "${FLATPAK_DEST}/opt/O3DE" -path '*/cmake/LYPython.cmake' | head -n1)
echo "Engine dir: ${ENGINE_DIR}" if [ -n "$LYPYTHON" ] && grep -qF -- '-m pip install -e ' "$LYPYTHON"; then
if [ -x "${ENGINE_DIR}/python/get_python.sh" ]; then sed -i 's/-m pip install -e /-m pip install /g' "$LYPYTHON"
( cd "${ENGINE_DIR}" && HOME="${PWD}" ./python/get_python.sh )
else else
echo "::warning:: get_python.sh not found; Python may fail at runtime" echo "::warning:: 'pip install -e' not found in LYPython.cmake"
fi fi
# Launcher + AppStream + desktop entry under the Flatpak app-id. # Launcher + AppStream + desktop entry under the Flatpak app-id.
- install -Dm755 o3de-wrapper.sh "${FLATPAK_DEST}/bin/o3de-wrapper.sh" - install -Dm755 o3de-wrapper.sh "${FLATPAK_DEST}/bin/o3de-wrapper.sh"
- install -Dm644 org.o3de.O3DE.desktop "${FLATPAK_DEST}/share/applications/org.o3de.O3DE.desktop" - install -Dm644 org.o3de.O3DE.desktop "${FLATPAK_DEST}/share/applications/org.o3de.O3DE.desktop"
- install -Dm644 org.o3de.O3DE.metainfo.xml "${FLATPAK_DEST}/share/metainfo/org.o3de.O3DE.metainfo.xml" - install -Dm644 org.o3de.O3DE.metainfo.xml "${FLATPAK_DEST}/share/metainfo/org.o3de.O3DE.metainfo.xml"
# NOTE: the .deb ships no clean application icon (only in-editor asset icons), - install -Dm644 org.o3de.O3DE.png "${FLATPAK_DEST}/share/icons/hicolor/256x256/apps/org.o3de.O3DE.png"
# so none is installed; the desktop entry falls back to a generic icon. Drop a
# real logo into the repo and install it here to fix the launcher icon.
sources: sources:
- type: file - type: file
path: o3de.deb path: o3de.deb
@@ -71,3 +62,5 @@ modules:
path: org.o3de.O3DE.desktop path: org.o3de.O3DE.desktop
- type: file - type: file
path: org.o3de.O3DE.metainfo.xml path: org.o3de.O3DE.metainfo.xml
- type: file
path: org.o3de.O3DE.png
+19 -9
View File
@@ -29,21 +29,26 @@ tar -C data -xf data.tar.*
mkdir -p "$DEST/opt" mkdir -p "$DEST/opt"
cp -a data/opt/. "$DEST/opt/" cp -a data/opt/. "$DEST/opt/"
echo ">> baking O3DE's Python runtime into the image" echo ">> patching the editable pip install (read-only /app workaround)"
# O3DE fetches Python into its install tree on first use, but that tree is # On first launch O3DE sets up a per-user Python venv in ~/.o3de and pip-installs
# read-only at runtime in a Flatpak, so populate it now while it is writable. # its 'o3de' CLI with 'pip install -e' (editable). Editable mode writes an
ENGINE_DIR=$(find "$DEST/opt/O3DE" -mindepth 1 -maxdepth 1 -type d | head -n1) # egg-info next to the source under /app, which is read-only in a Flatpak, so it
echo " engine dir: $ENGINE_DIR" # fails. Force a normal (non-editable) install instead: pip builds in a temp dir
if [ -x "$ENGINE_DIR/python/get_python.sh" ]; then # and installs into the writable ~/.o3de venv. (Nothing Python-related needs to
( cd "$ENGINE_DIR" && HOME="$PWD" ./python/get_python.sh ) # be baked into the image; it all lives per-user under ~/.o3de.)
LYPYTHON=$(find "$DEST/opt/O3DE" -path '*/cmake/LYPython.cmake' | head -n1)
if [ -n "$LYPYTHON" ] && grep -qF -- '-m pip install -e ' "$LYPYTHON"; then
sed -i 's/-m pip install -e /-m pip install /g' "$LYPYTHON"
echo " patched: $LYPYTHON"
else else
echo " WARNING: get_python.sh not found; Python may fail at runtime" >&2 echo " WARNING: 'pip install -e' not found in LYPython.cmake; O3DE layout may have changed" >&2
fi fi
echo ">> installing launcher + metadata" echo ">> installing launcher + metadata"
install -Dm755 o3de-wrapper.sh "$DEST/bin/o3de-wrapper.sh" install -Dm755 o3de-wrapper.sh "$DEST/bin/o3de-wrapper.sh"
install -Dm644 org.o3de.O3DE.desktop "$DEST/share/applications/$APP_ID.desktop" install -Dm644 org.o3de.O3DE.desktop "$DEST/share/applications/$APP_ID.desktop"
install -Dm644 org.o3de.O3DE.metainfo.xml "$DEST/share/metainfo/$APP_ID.metainfo.xml" install -Dm644 org.o3de.O3DE.metainfo.xml "$DEST/share/metainfo/$APP_ID.metainfo.xml"
install -Dm644 org.o3de.O3DE.png "$DEST/share/icons/hicolor/256x256/apps/$APP_ID.png"
echo ">> build-finish (command + sandbox permissions)" echo ">> build-finish (command + sandbox permissions)"
flatpak build-finish build-dir \ flatpak build-finish build-dir \
@@ -51,7 +56,6 @@ flatpak build-finish build-dir \
--share=ipc \ --share=ipc \
--share=network \ --share=network \
--socket=x11 \ --socket=x11 \
--socket=fallback-x11 \
--socket=wayland \ --socket=wayland \
--socket=pulseaudio \ --socket=pulseaudio \
--device=dri \ --device=dri \
@@ -61,6 +65,12 @@ flatpak build-finish build-dir \
--env=QT_QPA_PLATFORM=xcb --env=QT_QPA_PLATFORM=xcb
echo ">> export to OSTree repo" echo ">> export to OSTree repo"
# flatpak build-export validates exported app icons in a bwrap sandbox, which
# fails in an unprivileged container ("is not a valid icon: bwrap ..."). The
# icon stays inside the app (so the running window/taskbar shows it); we just
# drop it from the *exported* set so export skips validation. Trade-off: the
# host menu launcher icon is generic. (A privileged runner would avoid this.)
rm -rf build-dir/export/share/icons
flatpak build-export repo build-dir "$BRANCH" flatpak build-export repo build-dir "$BRANCH"
flatpak build-update-repo repo --title="O3DE (unofficial Flatpak)" --prune --prune-depth=1 flatpak build-update-repo repo --title="O3DE (unofficial Flatpak)" --prune --prune-depth=1