forked from unom/punktfunk
The Nitro console bundle is a pure function of web/ and sdk/, and it was being built
six times on every push: ci.yml, deb, both RPM legs (f43 + f44), arch, and the docker
app image, at roughly 2.5 min each. windows-host.yml has cached it on exactly this
shape for a while — this extends the same arrangement to the Linux packaging legs,
sharing one key family so whichever job builds it first warms the others.
The bun version is part of the key. Each builder image runs the bun.sh installer at
image-build time, so rust-ci, fedora-rpm and arch-ci can drift apart; keying on it
means they share while they agree and simply stop sharing when they do not, rather
than one image's bun silently producing the bundle another image ships.
Each packaging path needed a different hand-off:
* deb — build-web-deb.sh already builds only if web/.output is missing, so the
restore alone is enough; the workflow's build+smoke step is now gated on
the miss.
* arch — makepkg builds with PF_SRCDIR pointing at the workspace, so a restored
bundle is already where it needs to be. PKGBUILD gains the same
build-if-missing guard the deb script has.
* rpm — neither direction works by default. build-rpm.sh packages a `git archive`
tarball and web/.output is gitignored, so a bundle in the workspace is
invisible to rpmbuild; and the spec's own build lands in rpmbuild's
%{_topdir}, which build-rpm.sh mktemps and removes on EXIT, so a console
built there is gone before the cache's post step and the cache would never
populate — every run a miss that quietly rebuilt. So the workflow builds it,
and hands it over by absolute path through a new optional `pf_prebuilt_web`
macro. Undefined (plain rpmbuild, COPR) takes the original build path.
Every path asserts the bundle exists and carries the Bun.serve marker, on cache hits
too. A cache is one more place a wrong artifact can come from, and the packaging
scripts' build-if-missing behaviour — correct for a local build — would otherwise turn
a broken restore into either a silent rebuild or, with the build step skipped, a
package with no console in it. That is not hypothetical: windows-host.yml shipped
0.22.1 and 0.22.2 with no console because an unset path variable was handled by a
single Write-Host, which is why its equivalent step throws.
99 lines
5.7 KiB
Bash
Executable File
99 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build the punktfunk-host RPM from the committed tree, for the Gitea RPM registry (Bazzite).
|
|
#
|
|
# Counterpart to ../debian/build-deb.sh. The library Requires (libavcodec.so.NN, …) are
|
|
# auto-generated by rpmbuild from the binary it links — so build this in the Fedora 43 image
|
|
# (ci/fedora-rpm.Dockerfile) to match Bazzite's sonames. libcuda is excluded in the spec.
|
|
#
|
|
# Usage: PF_VERSION=0.0.1 [PF_RELEASE=0.ci42.gdeadbee] bash packaging/rpm/build-rpm.sh
|
|
# Output: dist/punktfunk-<version>-<release>.<arch>.rpm (+ the -debuginfo/-debugsource subpkgs)
|
|
set -euo pipefail
|
|
|
|
PF_VERSION="${PF_VERSION:-0.5.0}" # canary base; keep one minor ahead of the latest stable release
|
|
PF_RELEASE="${PF_RELEASE:-1}"
|
|
# PF_WITH_WEB=1 builds the punktfunk-web subpackage too (needs `bun` on PATH — present in the CI
|
|
# builder image, not in a plain mock chroot). Default off so a bare `rpmbuild`/COPR still works.
|
|
WEB_OPT=()
|
|
[ "${PF_WITH_WEB:-0}" = "1" ] && WEB_OPT=(--with web)
|
|
# PF_PREBUILT_WEB_OUTPUT: an already-built web/.output to package instead of building the console a
|
|
# second time (see the pf_prebuilt_web note in the spec's %build). CI restores one from the shared
|
|
# actions cache and points this at it; a plain build leaves it unset and nothing changes.
|
|
# Deliberately validated HERE rather than trusted: an empty or half-restored cache directory must
|
|
# fall back to building, not produce a console-less package. The spec re-asserts the Bun.serve
|
|
# marker on whatever it ends up with.
|
|
PREBUILT_WEB_OPT=()
|
|
if [ "${PF_WITH_WEB:-0}" = "1" ] && [ -n "${PF_PREBUILT_WEB_OUTPUT:-}" ]; then
|
|
if [ -f "${PF_PREBUILT_WEB_OUTPUT}/server/index.mjs" ]; then
|
|
# rpmbuild resolves the macro inside the extracted tarball dir, so it must be absolute.
|
|
PREBUILT_WEB_ABS="$(cd "$PF_PREBUILT_WEB_OUTPUT" && pwd)"
|
|
PREBUILT_WEB_OPT=(--define "pf_prebuilt_web ${PREBUILT_WEB_ABS}")
|
|
echo "==> reusing prebuilt web console: $PREBUILT_WEB_ABS"
|
|
else
|
|
echo "==> PF_PREBUILT_WEB_OUTPUT=$PF_PREBUILT_WEB_OUTPUT has no server/index.mjs — building the console" >&2
|
|
fi
|
|
fi
|
|
# PF_WITH_SCRIPTING=1 builds the punktfunk-scripting subpackage (the plugin/script runner). Same bun
|
|
# requirement as web; default off so a bare `rpmbuild`/COPR still works.
|
|
SCRIPTING_OPT=()
|
|
[ "${PF_WITH_SCRIPTING:-0}" = "1" ] && SCRIPTING_OPT=(--with scripting)
|
|
# PF_WITHOUT_HOST=1 drops the host binary, the tray and the main package, leaving only
|
|
# punktfunk-client. This is what an aarch64 build uses: the client is portable, the host's encode
|
|
# stack (NVENC/QSV/AMF) is x86. Harmless on x86_64 too, if you only want the client RPM.
|
|
HOST_OPT=()
|
|
[ "${PF_WITHOUT_HOST:-0}" = "1" ] && HOST_OPT=(--without host)
|
|
ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
cd "$ROOTDIR"
|
|
|
|
TOP="$(mktemp -d)"
|
|
trap 'rm -rf "$TOP"' EXIT
|
|
mkdir -p "$TOP"/{SOURCES,SPECS,BUILD,BUILDROOT,RPMS,SRPMS}
|
|
|
|
# Source tarball with the prefix %autosetup expects (punktfunk-<version>/). From HEAD so the
|
|
# build is reproducible from a commit (CI checks one out); the spec is read from the working
|
|
# tree directly, so spec edits apply without a re-commit.
|
|
git archive --format=tar.gz --prefix="punktfunk-${PF_VERSION}/" \
|
|
-o "$TOP/SOURCES/punktfunk-${PF_VERSION}.tar.gz" HEAD
|
|
|
|
# libcuda link stub (self-maintaining). The zerocopy FFI links the NVIDIA driver lib (-lcuda), but
|
|
# the CI builder has no GPU and never RUNS CUDA. Synthesize a stub libcuda that DEFINES every cu*
|
|
# driver symbol the host source references, derived from the source HERE so a newly-added cu* call
|
|
# can't silently break the link. (ci/fedora-rpm.Dockerfile ships a frozen list that went stale —
|
|
# undefined cuStreamCreateWithPriority/cuMemcpy2DAsync_v2/…; this regen supersedes it.) Defining
|
|
# extra unused symbols is harmless; a missing one fails the link. Only when /usr/lib64 is writable
|
|
# (CI image runs as root) — COPR/mock provides the real cuda-cudart-devel stub instead.
|
|
if [ "${PF_WITHOUT_HOST:-0}" != "1" ] && [ "$(id -u)" = 0 ] && [ -d /usr/lib64 ]; then
|
|
CU_SYMS="$(grep -rhoE '\bcu[A-Z][A-Za-z0-9_]*' crates/punktfunk-host/src/ | sort -u || true)"
|
|
if [ -n "$CU_SYMS" ]; then
|
|
STUB_C="$(mktemp --suffix=.c)"
|
|
for s in $CU_SYMS; do printf 'int %s(void){return 0;}\n' "$s" >> "$STUB_C"; done
|
|
gcc -shared -fPIC -Wl,-soname,libcuda.so.1 -o /usr/lib64/libcuda.so.1 "$STUB_C"
|
|
ln -sf libcuda.so.1 /usr/lib64/libcuda.so
|
|
rm -f "$STUB_C"; ldconfig 2>/dev/null || true
|
|
echo "== libcuda stub regenerated from source: $(printf '%s\n' "$CU_SYMS" | wc -l) symbols =="
|
|
fi
|
|
fi
|
|
|
|
# --nodeps: the spec's BuildRequires (cargo, rust, *-devel) are for COPR's mock chroot, which
|
|
# resolves them from RPMs. Our builder image provides the toolchain via rustup (so
|
|
# rust-toolchain.toml's pinned channel works) and the -devel libs via dnf, neither of which
|
|
# rpmbuild's RPM-level check sees — skip it; a genuinely missing dep fails the compile/link.
|
|
rpmbuild -bb --nodeps "${WEB_OPT[@]}" "${SCRIPTING_OPT[@]}" "${HOST_OPT[@]}" \
|
|
"${PREBUILT_WEB_OPT[@]}" \
|
|
--define "_topdir $TOP" \
|
|
--define "pf_version ${PF_VERSION}" \
|
|
--define "pf_release ${PF_RELEASE}" \
|
|
--define "pf_channel $(case "${PF_RELEASE:-1}" in 0.ci*) echo canary ;; *) echo stable ;; esac)" \
|
|
packaging/rpm/punktfunk.spec
|
|
|
|
mkdir -p dist
|
|
find "$TOP/RPMS" -name '*.rpm' -exec cp -v {} dist/ \;
|
|
# The libcuda leak check applies to the HOST package (the only thing that links the driver); a
|
|
# client-only build has no such package to inspect.
|
|
if [ "${PF_WITHOUT_HOST:-0}" = "1" ]; then
|
|
echo "== client-only build: no host RPM, libcuda check not applicable =="
|
|
else
|
|
echo "== Requires (must NOT contain libcuda) =="
|
|
rpm -qp --requires dist/punktfunk-${PF_VERSION}-*.rpm 2>/dev/null | grep -iE 'cuda|nvidia' \
|
|
&& echo " !! NVIDIA/CUDA leak !!" || echo " clean"
|
|
fi
|