Ticket xavierk/voculinux#28, needs #27. One documented command (packaging/void/smoke.sh, just void-smoke) lints, builds, installs and smoke-tests every template under packaging/void/srcpkgs in dependency order in the pinned Void container via podman, failing fast naming the package with the harness echoing each stage. The gate caught three latent breaks in the per-package harness and the app template, fixed here: - container-main.sh scoped the libggml scan to python3-pywhispercpp and gave the leaf packages their own import smokes (pynput by presence: no display in the container), failing loudly for packages without a smoke recipe; - voculinux template drops the deprecated wrksrc override (xbps-src renames the single-top-dir archive itself; xlint rejects wrksrc) and builds the PEP 517 wheel (the sdist ships no setup.py); - post_install promotes the pre-rename sdist names (desktop entry content, icons, /usr/bin launchers) to the renamed identity, and the payload smoke rejects pre-rename leftovers in OS-visible paths. Offline policy tests (tests/test_void_smoke_gate.py) pin the gate to the template set, the app-last order, podman-only pinned inputs and per-package failure identity; the #27 policy tests and the rename sweep cover the harness and template contracts.
146 lines
5.7 KiB
Bash
Executable File
146 lines
5.7 KiB
Bash
Executable File
#!/bin/sh
|
|
# Root-side half of the packaging/void container harness. Runs inside the
|
|
# pinned Void container as root: system setup, the void-packages checkout,
|
|
# then the builder half (container-build.sh) as the builder user, then the
|
|
# install plus import smoke as root again.
|
|
#
|
|
# Not executed directly: build.sh mounts this file and runs it. PKGNAME,
|
|
# XBPS_ARGS, EXPECT_VULKAN and VOID_COMMIT arrive via the environment.
|
|
set -eu
|
|
|
|
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
|
xbps-install -Suy xbps >/dev/null
|
|
xbps-install -y git base-devel xtools binutils zstd >/dev/null
|
|
git clone --quiet --depth 1 https://github.com/void-linux/void-packages /void-packages
|
|
git -C /void-packages fetch --quiet --depth 1 origin "$VOID_COMMIT"
|
|
git -C /void-packages checkout --quiet "$VOID_COMMIT"
|
|
cp -r /overlay/. /void-packages/srcpkgs/
|
|
id builder >/dev/null 2>&1 || useradd -m builder
|
|
cp /mnt/container-build.sh /run-build.sh
|
|
chown builder:builder /void-packages /run-build.sh
|
|
chmod +x /run-build.sh
|
|
su -s /bin/sh builder -c /run-build.sh
|
|
|
|
echo "== install $PKGNAME from the local repository"
|
|
PKGFILE=$(ls /void-packages/hostdir/binpkgs/"$PKGNAME"-*.x86_64.xbps /host/binpkgs/"$PKGNAME"-*.x86_64.xbps 2>/dev/null | head -n1)
|
|
[ -n "$PKGFILE" ] || {
|
|
echo "built package not found" >&2
|
|
exit 1
|
|
}
|
|
echo "built: $PKGFILE"
|
|
xbps-install -Sy >/dev/null
|
|
xbps-install -y --repository="$(dirname "$PKGFILE")" "$PKGNAME" >/dev/null
|
|
|
|
case "$PKGNAME" in
|
|
voculinux)
|
|
echo "== payload $PKGNAME: desktop entry, icons, packaged marker"
|
|
tar -tf "$PKGFILE" 2>/dev/null | grep -q "usr/share/applications/voculinux.desktop" || {
|
|
echo "renamed desktop entry missing from the built package" >&2
|
|
exit 1
|
|
}
|
|
tar -tf "$PKGFILE" 2>/dev/null | grep -q "usr/share/icons/hicolor/scalable/apps/voculinux.svg" || {
|
|
echo "renamed icons missing from the built package" >&2
|
|
exit 1
|
|
}
|
|
tar -tf "$PKGFILE" 2>/dev/null | grep -q "usr/share/voculinux/packaged" || {
|
|
echo "packaged-install marker missing from the built package" >&2
|
|
exit 1
|
|
}
|
|
echo "== payload $PKGNAME: no speech models, no vendored wheels"
|
|
if tar -tf "$PKGFILE" 2>/dev/null | grep -E "models/|\.ggml$|\.bin$|\.pt$|\.whl$"; then
|
|
echo "package payload carries models or wheels" >&2
|
|
exit 1
|
|
fi
|
|
echo "no models or wheels in the shipped package"
|
|
echo "== payload $PKGNAME: no pre-rename leftovers"
|
|
if tar -tf "$PKGFILE" 2>/dev/null | grep -E "usr/share/applications/vocalinux|usr/share/icons/.*/vocalinux"; then
|
|
echo "pre-rename file names in the OS-visible payload" >&2
|
|
exit 1
|
|
fi
|
|
echo "no pre-rename leftovers in the shipped package"
|
|
echo "== version and import smoke $PKGNAME"
|
|
voculinux --version
|
|
cat > /voculinux-smoke.py <<'PYEOF'
|
|
# The 0.18.5 sdist predates the rename: the importable top-level package
|
|
# and the distribution metadata still carry the old name. The first
|
|
# release cut after the rename moves these to voculinux.
|
|
import importlib
|
|
|
|
MODULES = (
|
|
"vocalinux.main",
|
|
"vocalinux.ui.tray_indicator",
|
|
"vocalinux.speech_recognition.recognition_manager",
|
|
"vocalinux.speech_recognition.command_processor",
|
|
"vocalinux.text_injection.text_injector",
|
|
"vocalinux.text_injection.ibus_engine",
|
|
"vocalinux.ui.keyboard_backends",
|
|
"pywhispercpp.model",
|
|
)
|
|
for module in MODULES:
|
|
importlib.import_module(module)
|
|
print("import-smoke OK:", ", ".join(MODULES))
|
|
|
|
from importlib.metadata import version
|
|
print("vocalinux", version("vocalinux"))
|
|
PYEOF
|
|
python3 /voculinux-smoke.py
|
|
;;
|
|
python3-pywhispercpp)
|
|
echo "== compiler flag scan of the shipped ggml library"
|
|
LIBMEMBER=$(tar -tf "$PKGFILE" 2>/dev/null | grep -E "libggml-cpu\.so" | head -n1)
|
|
[ -n "$LIBMEMBER" ] || {
|
|
echo "libggml-cpu missing from the built package" >&2
|
|
exit 1
|
|
}
|
|
echo "member: $LIBMEMBER"
|
|
mkdir -p /flagscan
|
|
tar -xf "$PKGFILE" -C /flagscan "$LIBMEMBER"
|
|
LIBSCAN="/flagscan/${LIBMEMBER#./}"
|
|
echo "-- .GCC.command.line:"
|
|
readelf -p .GCC.command.line "$LIBSCAN" 2>/dev/null || echo "(section absent)"
|
|
echo "-- .comment:"
|
|
readelf -p .comment "$LIBSCAN" 2>/dev/null || echo "(section absent)"
|
|
if readelf -p .GCC.command.line "$LIBSCAN" 2>/dev/null | grep -E "march=native|mcpu=native|mtune=native"; then
|
|
echo "host-native CPU tuning in the shipped library" >&2
|
|
exit 1
|
|
fi
|
|
echo "no host-native tuning in the shipped library"
|
|
|
|
echo "== import smoke $PKGNAME"
|
|
python3 -c "from pywhispercpp.model import Model; print('model submodule ok')"
|
|
cat > /smoke.py <<'PYEOF'
|
|
import glob
|
|
import os
|
|
import pywhispercpp
|
|
pkgdir = os.path.dirname(pywhispercpp.__file__)
|
|
sitedir = os.path.dirname(pkgdir)
|
|
libs = sorted(os.path.basename(p) for p in glob.glob(sitedir + "/lib*.so*"))
|
|
print("shipped libraries:", libs)
|
|
assert any(n.startswith("libwhisper") for n in libs), "libwhisper missing"
|
|
exts = [n for n in os.listdir(sitedir) if n.startswith("_pywhispercpp") and n.endswith(".so")]
|
|
assert exts, "compiled extension missing"
|
|
print("extension:", exts)
|
|
has_vulkan = any("vulkan" in n for n in libs)
|
|
want_vulkan = bool(int(os.environ["EXPECT_VULKAN"]))
|
|
assert has_vulkan == want_vulkan, "vulkan backend present=%s, expected=%s" % (has_vulkan, want_vulkan)
|
|
print("smoke ok")
|
|
PYEOF
|
|
EXPECT_VULKAN="$EXPECT_VULKAN" python3 /smoke.py
|
|
;;
|
|
python3-PyAudio)
|
|
echo "== import smoke $PKGNAME"
|
|
python3 -c "import pyaudio; print('pyaudio', pyaudio.__version__)"
|
|
;;
|
|
python3-pynput)
|
|
# pynput selects a display backend at import and raises without one;
|
|
# the container has no display, so presence plus the installed
|
|
# version (the same proof the native smoke accepts) is the smoke.
|
|
echo "== import smoke $PKGNAME"
|
|
python3 -c "import importlib.metadata, importlib.util; assert importlib.util.find_spec('pynput'), 'pynput not importable'; print('pynput', importlib.metadata.version('pynput'))"
|
|
;;
|
|
*)
|
|
echo "no smoke recipe for package '$PKGNAME' — add one alongside the template" >&2
|
|
exit 1
|
|
;;
|
|
esac
|