#!/usr/bin/env bash # Build the O3DE Flatpak WITHOUT flatpak-builder. # # flatpak-builder runs every build command inside a bubblewrap sandbox, which # needs user namespaces / a privileged container - awkward in CI. We don't need # it: our "build" is just unpacking a .deb and running get_python.sh, both plain # shell. flatpak build-init/build-finish/build-export only touch files and the # OSTree repo (no bwrap), so this works in an unprivileged container. # # Expects ./o3de.deb to already be present. Produces ./repo (an OSTree repo). set -euo pipefail cd "$(dirname "$0")/.." APP_ID=org.o3de.O3DE RUNTIME=org.freedesktop.Sdk RUNTIME_VER=24.08 BRANCH=stable rm -rf build-dir data repo echo ">> build-init" flatpak build-init build-dir "$APP_ID" "$RUNTIME" "$RUNTIME" "$RUNTIME_VER" DEST=build-dir/files echo ">> extracting .deb payload" mkdir -p data ar x o3de.deb tar -C data -xf data.tar.* mkdir -p "$DEST/opt" cp -a data/opt/. "$DEST/opt/" echo ">> pre-building the o3de sdist (read-only /app workaround)" # On first launch O3DE builds a per-user Python venv in ~/.o3de and installs its # 'o3de' CLI from /scripts/o3de. By default python/get_python.sh does an # *editable* install ('pip install -e'), which writes an egg-info next to the # source under read-only /app and fails. get_python.sh has a built-in escape hatch # for immutable installs (the Snap path): if a prebuilt sdist exists at # scripts/o3de/dist/o3de-1.0.0.tar.gz it installs THAT (non-editable) instead. So # we build that tarball here, while the tree is still writable. At runtime the # tarball is copied into the writable ~/.o3de venv - nothing is written to /app. O3DE_PKG=$(find "$DEST/opt/O3DE" -maxdepth 3 -type d -path '*/scripts/o3de' | head -n1) if [ -n "$O3DE_PKG" ] && [ -f "$O3DE_PKG/setup.py" ]; then ( cd "$O3DE_PKG" && python3 setup.py sdist ) if [ -f "$O3DE_PKG/dist/o3de-1.0.0.tar.gz" ]; then echo " built: $O3DE_PKG/dist/o3de-1.0.0.tar.gz" else echo " ERROR: sdist did not produce o3de-1.0.0.tar.gz" >&2 exit 1 fi else echo " ERROR: scripts/o3de/setup.py not found; O3DE layout may have changed" >&2 exit 1 fi # Belt-and-suspenders for the project-build path: LYPython.cmake also installs the # o3de package (editable) during a CMake configure when you build a project. Patch # every copy to a non-editable install so that write doesn't hit read-only /app. find "$DEST/opt/O3DE" -path '*/cmake/LYPython.cmake' | while read -r LYPYTHON; do if grep -qF -- '-m pip install -e ' "$LYPYTHON"; then sed -i 's/-m pip install -e /-m pip install /g' "$LYPYTHON" echo " patched: $LYPYTHON" fi done echo ">> installing launcher + metadata" 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.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)" flatpak build-finish build-dir \ --command=o3de-wrapper.sh \ --share=ipc \ --share=network \ --socket=x11 \ --socket=wayland \ --socket=pulseaudio \ --device=dri \ --device=all \ --filesystem=home \ --talk-name=org.freedesktop.Notifications \ --env=QT_QPA_PLATFORM=xcb 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-update-repo repo --title="O3DE (unofficial Flatpak)" --prune --prune-depth=1 echo ">> done: ./repo"