Stop the flatpak build updating runtimes it already has #370
@@ -50,7 +50,10 @@ on:
|
||||
- 'crates/pf-vaadec/**'
|
||||
- 'packaging/flatpak/**'
|
||||
- 'Cargo.lock'
|
||||
# Both halves of this job's correctness, not of the bundle's content: a change to either
|
||||
# can only be proven by a real run, and there is no other trigger that would give it one.
|
||||
- '.gitea/workflows/flatpak.yml'
|
||||
- 'scripts/ci/flatpak-deps-present.sh'
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -270,12 +273,13 @@ jobs:
|
||||
|
||||
- name: Prefetch deps + sources (retried — the network phase, split off the build)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# All of the job's heavy network I/O happens HERE, retried, so a dropped DNS lookup
|
||||
# or TCP dial costs a backoff-retry instead of the whole (long) compile:
|
||||
# 1) --install-deps-only pulls everything the manifest declares from Flathub: the
|
||||
# GNOME 50 runtime/SDK + the rust-stable (//25.08, rustc 1.96) and llvm20 SDK
|
||||
# extensions. (No codec extension: the client links no FFmpeg — see the
|
||||
# manifest header.)
|
||||
# 1) the Flathub deps the manifest declares — the GNOME 50 runtime/SDK + the
|
||||
# rust-stable (//25.08, rustc 1.96) and llvm20 SDK extensions — but ONLY the ones
|
||||
# genuinely MISSING; see the block below. (No codec extension: the client links no
|
||||
# FFmpeg — see the manifest header.)
|
||||
# 2) --download-only fetches every source (all crates in cargo-sources.json) into
|
||||
# the .flatpak-builder state dir. Both are resumable/idempotent, so re-running
|
||||
# after a partial failure is safe and cheap.
|
||||
@@ -288,9 +292,40 @@ jobs:
|
||||
# for the mechanism.
|
||||
# 10 attempts (~9min budget), matching the remote-add bootstrap above — same shared,
|
||||
# load-sensitive runner, same flathub.org resolution path.
|
||||
bash scripts/ci/retry.sh 10 flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
||||
--install-deps-from=flathub --install-deps-only \
|
||||
"$PWD/build-dir" "$MANIFEST"
|
||||
#
|
||||
# WHY THIS IS NOT AN UNCONDITIONAL `--install-deps-only` ANY MORE (2026-08-22):
|
||||
# that flag does not install what is missing, it UPDATES what is present.
|
||||
# builder_manifest_install_dep() branches on `flatpak info --show-commit <ref>` succeeding
|
||||
# and runs `flatpak update` for every dep already installed — with no fallback to a
|
||||
# plain install when that update fails — and ci/flatpak-ci.Dockerfile bakes
|
||||
# the entire runtime set, so on a healthy run it was a pure no-op that nonetheless made
|
||||
# every build depend on Flathub being healthy at that minute. It bit on 2026-08-22:
|
||||
# Updating runtime/org.freedesktop.Sdk.Extension.rust-stable/x86_64/25.08
|
||||
# Error: Failed to update org.freedesktop.Sdk.Extension.rust-stable: While pulling …
|
||||
# .filez: Server returned HTTP 404
|
||||
# dl.flathub.org served a 404 for one object of the then-current rust-stable//25.08
|
||||
# commit, deterministically — all 10 retry.sh attempts died on the SAME object over
|
||||
# ~9 min — and flatpak-builder SEGFAULTED on its own error path (rc=139), so retry.sh
|
||||
# saw a crash rather than a clean "this will never work" either. The build never wanted
|
||||
# that newer commit: the manifest pins a runtime VERSION, not a commit, and the baked
|
||||
# one satisfies it. Updating bought nothing and imported an upstream outage.
|
||||
#
|
||||
# So: assert what the image already has, and reach for Flathub only on a real miss —
|
||||
# the same "guard, don't install on top of a stale image" doctrine as the Tooling step.
|
||||
# The check lives in scripts/ci/flatpak-deps-present.sh (run its --self-test after
|
||||
# touching it): a bug in it that reports "satisfied" when it is not would build against
|
||||
# whatever runtime happened to be lying around, which is worth more than an inline
|
||||
# if-statement. It deliberately fails OPEN — anything it cannot parse takes the slow
|
||||
# install path below.
|
||||
if bash scripts/ci/flatpak-deps-present.sh "$MANIFEST"; then
|
||||
echo "deps satisfied by the baked image — not touching Flathub"
|
||||
flatpak list --user --columns=ref
|
||||
else
|
||||
echo "::warning::$MANIFEST declares deps punktfunk-flatpak-ci does not have — pulling from Flathub (~1.5 GB). Bump GNOME_VERSION/FREEDESKTOP_VERSION in ci/flatpak-ci.Dockerfile so this stays off the hot path."
|
||||
bash scripts/ci/retry.sh 10 flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
||||
--install-deps-from=flathub --install-deps-only \
|
||||
"$PWD/build-dir" "$MANIFEST"
|
||||
fi
|
||||
bash scripts/ci/retry.sh 10 flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
||||
--download-only --disable-updates \
|
||||
"$PWD/build-dir" "$MANIFEST"
|
||||
@@ -298,7 +333,17 @@ jobs:
|
||||
- name: Build the flatpak (offline — deps + sources prefetched above)
|
||||
run: |
|
||||
# Everything is already local (state dir warmed by the prefetch step), so this long
|
||||
# step needs no network; --install-deps-from stays as a no-op safety net.
|
||||
# step needs no network.
|
||||
#
|
||||
# --install-deps-from=flathub USED to sit here, commented as "a no-op safety net". It
|
||||
# was neither. builder-main.c calls builder_manifest_install_deps() whenever that flag
|
||||
# is set — --install-deps-only only decides whether it EXITS afterwards — so this step
|
||||
# re-ran the same `flatpak update` of the runtimes that killed the prefetch step on
|
||||
# 2026-08-22 (Flathub HTTP 404 on a rust-stable//25.08 object; see there). A live pull
|
||||
# of multi-GB runtimes is a strange thing to call a safety net in the step whose whole
|
||||
# design is to be offline, and it could only ever fire if the prefetch step above had
|
||||
# already failed the job. Dropped: the prefetch step is the one place that talks to
|
||||
# Flathub, and it is the one place with retries.
|
||||
#
|
||||
# --disable-updates is LOAD-BEARING, not tidiness: without it this step was never
|
||||
# actually offline. flatpak-builder runs the DOWNLOAD PHASE again as part of every
|
||||
@@ -326,7 +371,6 @@ jobs:
|
||||
flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
||||
--default-branch="$FLATPAK_BRANCH" \
|
||||
--disable-updates \
|
||||
--install-deps-from=flathub \
|
||||
--repo="$PWD/repo" \
|
||||
"$PWD/build-dir" "$MANIFEST"
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# shellcheck shell=bash
|
||||
# Does this box already have every Flathub dep a flatpak manifest declares?
|
||||
# bash scripts/ci/flatpak-deps-present.sh <manifest.yml> -> exit 0 = yes, 1 = no
|
||||
# bash scripts/ci/flatpak-deps-present.sh --self-test -> run the asserts below
|
||||
#
|
||||
# WHY THIS EXISTS: flatpak.yml used to prefetch deps with `flatpak-builder --install-deps-only`,
|
||||
# which does NOT mean "install what is missing". builder_manifest_install_dep() branches on
|
||||
# `flatpak info --show-commit <ref>` succeeding and runs `flatpak update` for every dep that IS
|
||||
# installed (a failed update is fatal there — it never falls back to install) — and
|
||||
# ci/flatpak-ci.Dockerfile bakes the whole runtime set, so on a healthy run that flag did nothing
|
||||
# except make the build depend on Flathub being up at that minute. On 2026-08-22 it took the job
|
||||
# down: dl.flathub.org returned HTTP 404 for one .filez object of the then-current
|
||||
# rust-stable//25.08 commit, identically on all 10 retry.sh attempts (~9 min), and flatpak-builder
|
||||
# segfaulted on its own error path (rc=139) so the retry wrapper could not tell a dead end from a
|
||||
# blip. Nothing about the build wanted that newer commit: the manifest pins a runtime VERSION, not
|
||||
# a commit, and the baked one satisfies it.
|
||||
#
|
||||
# So the workflow asks this first and only reaches for Flathub on a real miss.
|
||||
#
|
||||
# FAILS OPEN, deliberately: an unreadable/unexpected manifest reports "not present" (1), so the
|
||||
# caller does the full install. Silently skipping the install on a manifest we stopped
|
||||
# understanding is how you build against the wrong runtime.
|
||||
set -uo pipefail
|
||||
|
||||
deps_present() {
|
||||
local manifest="$1" runtime rt_ver sdk exts e
|
||||
|
||||
runtime=$(sed -n 's/^runtime: *//p' "$manifest" | head -1)
|
||||
rt_ver=$(sed -n 's/^runtime-version: *//p' "$manifest" | tr -d "\"'" | head -1)
|
||||
sdk=$(sed -n 's/^sdk: *//p' "$manifest" | head -1)
|
||||
exts=$(sed -n '/^sdk-extensions:/,/^[^ #-]/p' "$manifest" | sed -n 's/^ *- *//p')
|
||||
|
||||
[ -n "$runtime" ] && [ -n "$rt_ver" ] && [ -n "$sdk" ] && [ -n "$exts" ] || return 1
|
||||
|
||||
flatpak info --user "$runtime//$rt_ver" >/dev/null 2>&1 || return 1
|
||||
flatpak info --user "$sdk//$rt_ver" >/dev/null 2>&1 || return 1
|
||||
# Extensions are checked for PRESENCE, not version: flatpak-builder resolves their version from
|
||||
# the SDK's own metadata (it prints "Dependency Extension: … 25.08"), never from the manifest.
|
||||
# Any bump that moves them moves runtime-version too, which the two checks above already catch.
|
||||
for e in $exts; do
|
||||
flatpak info --user "$e" >/dev/null 2>&1 || return 1
|
||||
done
|
||||
}
|
||||
|
||||
self_test() {
|
||||
local rc fails=0 full
|
||||
# NOT `local`: the EXIT trap fires after this function has returned.
|
||||
SELFTEST_TMP=$(mktemp -d) || return 1
|
||||
trap 'rm -rf "$SELFTEST_TMP"' EXIT
|
||||
local tmp="$SELFTEST_TMP"
|
||||
|
||||
cat > "$tmp/ok.yml" <<'YML'
|
||||
runtime: org.gnome.Platform
|
||||
runtime-version: '50'
|
||||
sdk: org.gnome.Sdk
|
||||
sdk-extensions:
|
||||
- org.freedesktop.Sdk.Extension.rust-stable
|
||||
- org.freedesktop.Sdk.Extension.llvm20
|
||||
command: punktfunk-client
|
||||
YML
|
||||
# A manifest this script cannot read (the fail-open case).
|
||||
printf 'app-id: io.unom.Punktfunk\n' > "$tmp/unparseable.yml"
|
||||
|
||||
# Stub `flatpak`: $INSTALLED is the newline-separated set of refs it admits to having.
|
||||
mkdir -p "$tmp/bin"
|
||||
cat > "$tmp/bin/flatpak" <<'STUB'
|
||||
#!/usr/bin/env bash
|
||||
# only `flatpak info --user <ref>` is exercised here
|
||||
# args are: info --user <ref>
|
||||
[ "$1" = info ] || exit 0
|
||||
printf '%s\n' "$INSTALLED" | grep -qxF "$3"
|
||||
STUB
|
||||
chmod +x "$tmp/bin/flatpak"
|
||||
PATH="$tmp/bin:$PATH"
|
||||
|
||||
check() { # <expected rc> <label> <installed set> <manifest>
|
||||
INSTALLED="$3" deps_present "$4"; rc=$?
|
||||
if [ "$rc" != "$1" ]; then
|
||||
echo "FAIL: $2 (expected rc=$1, got $rc)" >&2; fails=$((fails + 1))
|
||||
else
|
||||
echo "ok: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
full='org.gnome.Platform//50
|
||||
org.gnome.Sdk//50
|
||||
org.freedesktop.Sdk.Extension.rust-stable
|
||||
org.freedesktop.Sdk.Extension.llvm20'
|
||||
|
||||
check 0 "everything baked -> skip Flathub" "$full" "$tmp/ok.yml"
|
||||
check 1 "cold box -> install" "" "$tmp/ok.yml"
|
||||
check 1 "runtime missing -> install" "${full/org.gnome.Platform\/\/50/x}" "$tmp/ok.yml"
|
||||
check 1 "sdk missing -> install" "${full/org.gnome.Sdk\/\/50/x}" "$tmp/ok.yml"
|
||||
# The regression that started all this: llvm20 fine, rust-stable not.
|
||||
check 1 "one sdk-extension missing -> install" "${full/*.rust-stable/x}" "$tmp/ok.yml"
|
||||
# A runtime installed at ANOTHER version must not pass just because the name matches.
|
||||
check 1 "runtime at the wrong version" 'org.gnome.Platform//51
|
||||
org.gnome.Sdk//51
|
||||
org.freedesktop.Sdk.Extension.rust-stable
|
||||
org.freedesktop.Sdk.Extension.llvm20' "$tmp/ok.yml"
|
||||
check 1 "unreadable manifest -> fail open" "$full" "$tmp/unparseable.yml"
|
||||
|
||||
[ "$fails" = 0 ] || { echo "$fails check(s) failed" >&2; return 1; }
|
||||
echo "all checks passed"
|
||||
}
|
||||
|
||||
case "${1:---help}" in
|
||||
--self-test) self_test ;;
|
||||
--help|-h) sed -n '2,4p' "$0"; exit 2 ;;
|
||||
*) deps_present "$1" ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user