build_all: parallelize manual/pyinstaller/flatpak/appimage
Serial prep (venv tool installs + flatpak runtimes + wheel, which the AppImage depends on), then the four heavy builds run concurrently. The shared venv is only written during prep, so the parallel builds (read-only on the venv) don't race on pip. Per-step logs under dist/.build-logs/; failing logs are printed. --serial falls back to one-at-a-time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
178
build_all.sh
178
build_all.sh
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Build every distribution channel of testium, in order:
|
# Build every distribution channel of testium:
|
||||||
# 1. Manual PDF -> dist/testium-manual-<v>.pdf
|
# 1. Manual PDF -> dist/testium-manual-<v>.pdf
|
||||||
# 2. Wheel -> dist/testium-<v>-py3-none-any.whl (PEP 427 name)
|
# 2. Wheel -> dist/testium-<v>-py3-none-any.whl (PEP 427 name)
|
||||||
# 3. PyInstaller binary -> dist/testium-<v>
|
# 3. PyInstaller binary -> dist/testium-<v>
|
||||||
@@ -11,6 +11,15 @@
|
|||||||
# By default, a step is skipped if its artifact already exists in dist/.
|
# By default, a step is skipped if its artifact already exists in dist/.
|
||||||
# Pass --clean to remove existing dist/ artifacts and rebuild everything.
|
# Pass --clean to remove existing dist/ artifacts and rebuild everything.
|
||||||
#
|
#
|
||||||
|
# Parallelism: the wheel is built first (the AppImage installs it), then the
|
||||||
|
# manual, PyInstaller, Flatpak and AppImage builds run concurrently. The shared
|
||||||
|
# venv at test/tmp/.venv is only WRITTEN during the serial prep phase (the
|
||||||
|
# `pip install` of build/sphinx/pyinstaller); the parallel builds only read it,
|
||||||
|
# so there is no concurrent-pip race. Pass --serial to build one step at a time
|
||||||
|
# (useful when debugging or on a resource-constrained machine). Per-step output
|
||||||
|
# of the parallel phase is captured under dist/.build-logs/<step>.log and the
|
||||||
|
# log of any failing step is printed at the end.
|
||||||
|
#
|
||||||
# All artifacts are collected (copied) under <repo>/dist/. Original outputs in
|
# All artifacts are collected (copied) under <repo>/dist/. Original outputs in
|
||||||
# src/dist/, package/*/dist/, doc/manual/ are left in place. Wheel and AppImage
|
# src/dist/, package/*/dist/, doc/manual/ are left in place. Wheel and AppImage
|
||||||
# keep their original names (which already contain the version); manual,
|
# keep their original names (which already contain the version); manual,
|
||||||
@@ -26,9 +35,11 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
CLEAN=0
|
CLEAN=0
|
||||||
|
SERIAL=0
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--clean|-c) CLEAN=1 ;;
|
--clean|-c) CLEAN=1 ;;
|
||||||
|
--serial) SERIAL=1 ;;
|
||||||
*) echo "Unknown option: $arg" >&2; exit 1 ;;
|
*) echo "Unknown option: $arg" >&2; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -70,50 +81,77 @@ step() {
|
|||||||
echo "================================================================"
|
echo "================================================================"
|
||||||
}
|
}
|
||||||
|
|
||||||
skip() { echo " (already built — skipping)"; }
|
# ---------- artifact paths ----------------------------------------------------
|
||||||
|
|
||||||
# 1. Manual PDF
|
|
||||||
MANUAL="$DIST_DIR/testium-manual-${VERSION}.pdf"
|
MANUAL="$DIST_DIR/testium-manual-${VERSION}.pdf"
|
||||||
step "1/5 Manual PDF (version $VERSION)"
|
PYI_BIN="$DIST_DIR/testium-${VERSION}"
|
||||||
if [ ! -f "$MANUAL" ]; then
|
FLATPAK_BUNDLE="$DIST_DIR/testium-${VERSION}.flatpak"
|
||||||
python -m pip install --quiet --upgrade sphinx linuxdoc
|
wheel_in_dist() { ls -1t "$DIST_DIR"/testium-${VERSION}-*.whl 2>/dev/null | head -1; }
|
||||||
bash "$SCRIPT_DIR/doc/manual/sphinx/build_doc.sh"
|
appimage_in_dist() { ls -1t "$DIST_DIR"/Testium-${VERSION}-*.AppImage 2>/dev/null | head -1; }
|
||||||
cp -f "$SCRIPT_DIR/doc/manual/testium_manual.pdf" "$MANUAL"
|
|
||||||
else
|
|
||||||
skip
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 2. Wheel — PEP 427 name kept (already contains version)
|
# ---------- per-step build functions (assume tools are installed) -------------
|
||||||
step "2/5 Wheel (version $VERSION)"
|
|
||||||
WHEEL=$(ls -1t "$DIST_DIR"/testium-${VERSION}-*.whl 2>/dev/null | head -1)
|
build_wheel() {
|
||||||
if [ -z "$WHEEL" ]; then
|
if [ -n "$(wheel_in_dist)" ]; then echo "wheel: already built — skipping"; return 0; fi
|
||||||
python -m pip install --quiet --upgrade build
|
echo "wheel: building"
|
||||||
(
|
(
|
||||||
cd "$SCRIPT_DIR/src"
|
cd "$SCRIPT_DIR/src"
|
||||||
rm -rf dist build *.egg-info
|
rm -rf dist build *.egg-info
|
||||||
python -m build --wheel
|
python -m build --wheel
|
||||||
)
|
)
|
||||||
WHEEL_SRC=$(ls -1t "$SCRIPT_DIR/src/dist"/*.whl | head -1)
|
local src; src=$(ls -1t "$SCRIPT_DIR/src/dist"/*.whl | head -1)
|
||||||
WHEEL="$DIST_DIR/$(basename "$WHEEL_SRC")"
|
cp -f "$src" "$DIST_DIR/$(basename "$src")"
|
||||||
cp -f "$WHEEL_SRC" "$WHEEL"
|
echo "wheel: done"
|
||||||
else
|
}
|
||||||
skip
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3. PyInstaller binary
|
build_manual() {
|
||||||
PYI_BIN="$DIST_DIR/testium-${VERSION}"
|
if [ -f "$MANUAL" ]; then echo "manual: already built — skipping"; return 0; fi
|
||||||
step "3/5 PyInstaller binary (version $VERSION)"
|
echo "manual: building"
|
||||||
if [ ! -f "$PYI_BIN" ]; then
|
bash "$SCRIPT_DIR/doc/manual/sphinx/build_doc.sh"
|
||||||
python -m pip install --quiet --upgrade pyinstaller
|
cp -f "$SCRIPT_DIR/doc/manual/testium_manual.pdf" "$MANUAL"
|
||||||
|
echo "manual: done"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_pyinstaller() {
|
||||||
|
if [ -f "$PYI_BIN" ]; then echo "pyinstaller: already built — skipping"; return 0; fi
|
||||||
|
echo "pyinstaller: building"
|
||||||
bash "$SCRIPT_DIR/package/pyinstaller/build.sh"
|
bash "$SCRIPT_DIR/package/pyinstaller/build.sh"
|
||||||
cp -f "$SCRIPT_DIR/package/pyinstaller/dist/testium" "$PYI_BIN"
|
cp -f "$SCRIPT_DIR/package/pyinstaller/dist/testium" "$PYI_BIN"
|
||||||
else
|
echo "pyinstaller: done"
|
||||||
skip
|
}
|
||||||
fi
|
|
||||||
|
build_flatpak() {
|
||||||
|
if [ -f "$FLATPAK_BUNDLE" ]; then echo "flatpak: already built — skipping"; return 0; fi
|
||||||
|
echo "flatpak: building"
|
||||||
|
(
|
||||||
|
cd "$SCRIPT_DIR/package/flatpak"
|
||||||
|
bash build.sh
|
||||||
|
)
|
||||||
|
cp -f "$SCRIPT_DIR/package/flatpak/testium.flatpak" "$FLATPAK_BUNDLE"
|
||||||
|
echo "flatpak: done"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_appimage() {
|
||||||
|
if [ -n "$(appimage_in_dist)" ]; then echo "appimage: already built — skipping"; return 0; fi
|
||||||
|
echo "appimage: building"
|
||||||
|
(
|
||||||
|
cd "$SCRIPT_DIR/package/appimage"
|
||||||
|
bash build.sh
|
||||||
|
)
|
||||||
|
local src; src=$(ls -1t "$SCRIPT_DIR/package/appimage"/*.AppImage 2>/dev/null | head -1)
|
||||||
|
cp -f "$src" "$DIST_DIR/$(basename "$src")"
|
||||||
|
chmod +x "$DIST_DIR/$(basename "$src")"
|
||||||
|
echo "appimage: done"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- serial prep: tool installs (shared venv) + flatpak runtimes -------
|
||||||
|
|
||||||
|
step "Prep: build tools + runtimes (serial — shared venv)"
|
||||||
|
|
||||||
|
[ -f "$MANUAL" ] || python -m pip install --quiet --upgrade sphinx linuxdoc
|
||||||
|
[ -n "$(wheel_in_dist)" ] || python -m pip install --quiet --upgrade build
|
||||||
|
[ -f "$PYI_BIN" ] || python -m pip install --quiet --upgrade pyinstaller
|
||||||
|
|
||||||
# 4. Flatpak bundle
|
|
||||||
FLATPAK_BUNDLE="$DIST_DIR/testium-${VERSION}.flatpak"
|
|
||||||
step "4/5 Flatpak bundle (version $VERSION)"
|
|
||||||
if [ ! -f "$FLATPAK_BUNDLE" ]; then
|
if [ ! -f "$FLATPAK_BUNDLE" ]; then
|
||||||
FLATPAK_DEPS=(
|
FLATPAK_DEPS=(
|
||||||
"org.kde.Platform//6.10"
|
"org.kde.Platform//6.10"
|
||||||
@@ -130,35 +168,65 @@ if [ ! -f "$FLATPAK_BUNDLE" ]; then
|
|||||||
flatpak install --user --noninteractive flathub "$dep"
|
flatpak install --user --noninteractive flathub "$dep"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
(
|
|
||||||
cd "$SCRIPT_DIR/package/flatpak"
|
|
||||||
bash build.sh
|
|
||||||
)
|
|
||||||
cp -f "$SCRIPT_DIR/package/flatpak/testium.flatpak" "$FLATPAK_BUNDLE"
|
|
||||||
else
|
|
||||||
skip
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5. AppImage
|
# ---------- serial: wheel (the AppImage installs it) --------------------------
|
||||||
step "5/5 AppImage (version $VERSION)"
|
|
||||||
APPIMAGE=$(ls -1t "$DIST_DIR"/Testium-${VERSION}-*.AppImage 2>/dev/null | head -1)
|
step "1/5 Wheel (version $VERSION)"
|
||||||
if [ -z "$APPIMAGE" ]; then
|
build_wheel
|
||||||
(
|
|
||||||
cd "$SCRIPT_DIR/package/appimage"
|
# ---------- build the rest --------------------------------------------------
|
||||||
bash build.sh
|
|
||||||
)
|
REST=(manual pyinstaller flatpak appimage)
|
||||||
APPIMAGE_SRC=$(ls -1t "$SCRIPT_DIR/package/appimage"/*.AppImage 2>/dev/null | head -1)
|
|
||||||
APPIMAGE="$DIST_DIR/$(basename "$APPIMAGE_SRC")"
|
if [ "$SERIAL" -eq 1 ]; then
|
||||||
cp -f "$APPIMAGE_SRC" "$APPIMAGE"
|
n=2
|
||||||
chmod +x "$APPIMAGE"
|
for name in "${REST[@]}"; do
|
||||||
|
step "$n/5 $name (version $VERSION)"
|
||||||
|
"build_$name"
|
||||||
|
n=$((n + 1))
|
||||||
|
done
|
||||||
else
|
else
|
||||||
skip
|
step "2-5/5 manual + pyinstaller + flatpak + appimage (parallel)"
|
||||||
|
LOGDIR="$DIST_DIR/.build-logs"
|
||||||
|
mkdir -p "$LOGDIR"
|
||||||
|
declare -A PID2NAME
|
||||||
|
for name in "${REST[@]}"; do
|
||||||
|
log="$LOGDIR/$name.log"
|
||||||
|
echo " -> launching $name (log: $log)"
|
||||||
|
( "build_$name" ) >"$log" 2>&1 &
|
||||||
|
PID2NAME[$!]="$name"
|
||||||
|
done
|
||||||
|
|
||||||
|
FAILED=()
|
||||||
|
for pid in "${!PID2NAME[@]}"; do
|
||||||
|
name="${PID2NAME[$pid]}"
|
||||||
|
if wait "$pid"; then
|
||||||
|
echo " -> $name: OK"
|
||||||
|
else
|
||||||
|
echo " -> $name: FAILED (rc=$?)"
|
||||||
|
FAILED+=("$name")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${#FAILED[@]}" -gt 0 ]; then
|
||||||
|
for name in "${FAILED[@]}"; do
|
||||||
|
echo
|
||||||
|
echo "===================== $name log ====================="
|
||||||
|
cat "$LOGDIR/$name.log"
|
||||||
|
done
|
||||||
|
echo >&2
|
||||||
|
echo "BUILD FAILED: ${FAILED[*]} (logs under $LOGDIR)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---------- summary -----------------------------------------------------------
|
||||||
|
|
||||||
step "All packages built"
|
step "All packages built"
|
||||||
printf " manual : %s\n" "$MANUAL"
|
printf " manual : %s\n" "$MANUAL"
|
||||||
printf " wheel : %s\n" "$WHEEL"
|
printf " wheel : %s\n" "$(wheel_in_dist)"
|
||||||
printf " pyinstaller : %s\n" "$PYI_BIN"
|
printf " pyinstaller : %s\n" "$PYI_BIN"
|
||||||
printf " flatpak : %s\n" "$FLATPAK_BUNDLE"
|
printf " flatpak : %s\n" "$FLATPAK_BUNDLE"
|
||||||
printf " appimage : %s\n" "$APPIMAGE"
|
printf " appimage : %s\n" "$(appimage_in_dist)"
|
||||||
printf " release_note : %s\n" "$RELEASE_NOTE"
|
printf " release_note : %s\n" "$RELEASE_NOTE"
|
||||||
|
|||||||
Reference in New Issue
Block a user