#!/usr/bin/env bash # Build a Windows .msi for FEnigma, entirely on this Linux host, no # Windows machine or GitHub required: boots a real Windows VM inside a # container (dockur/windows, QEMU+KVM), provisions it once (MSYS2 + # GTK4/libadwaita/PyGObject + WiX, see oem/install.bat), then drives every # build over a shared folder -- drop a request, wait for the .msi to show # up. # # UNTESTED end to end (no KVM/Windows available in the environment this # was written in) -- expect to debug oem/*.bat and product.wxs against a # real run. Watch the first boot/install at http://localhost:8006 (noVNC) # to see what's actually happening; it also has RDP on :3389 if you'd # rather use a real RDP client. # # First run: full unattended Windows install + provisioning, likely # 30-90 minutes. Every run after that: just boot + build, a few minutes. set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" REPO_ROOT="$(cd .. && cd .. && pwd)" VERSION="${1:-0.1.0}" TIMEOUT_S="${BUILD_TIMEOUT_S:-7200}" # generous: covers a from-scratch first run OUT_DIR="${REPO_ROOT}/dist-windows" if [ ! -e /dev/kvm ]; then echo "No /dev/kvm -- dockur/windows needs KVM (check virtualization is" >&2 echo "enabled and your user is in the 'kvm' group: groups | grep kvm)." >&2 exit 1 fi command -v docker >/dev/null 2>&1 || { echo "docker not found." >&2; exit 1; } mkdir -p storage oem shared/src shared/dist "$OUT_DIR" # dockur/windows itself warns about this ("you are using the BTRFS # filesystem for /storage, this might introduce issues with Windows # Setup!") and it's not idle: confirmed on this host as a genuine # multi-hour Windows Setup boot-loop (repeating the same boot-manager # log lines forever, disk barely growing) -- QEMU disk images on a # copy-on-write filesystem are a known bad combination. +C only takes # effect for files created AFTER it's set on an empty directory, so # this only helps on a fresh/emptied storage/; it's a no-op (harmless, # chattr just errors quietly) on a non-btrfs filesystem or an # already-populated storage/ from a previous run. chattr +C storage 2>/dev/null || true echo "==> starting the Windows build VM (docker compose up -d)" docker compose up -d echo "==> syncing FEnigma source into the VM's shared folder" rm -rf shared/src mkdir -p shared/src cp -r "${REPO_ROOT}/src" shared/src/ echo "$VERSION" > shared/BUILD_VERSION rm -f shared/BUILD_DONE shared/BUILD_FAILED rm -rf shared/dist mkdir -p shared/dist echo "==> requesting a build (version $VERSION)" touch shared/BUILD_REQUEST echo "==> waiting for it (up to ${TIMEOUT_S}s -- first run is slow, see" echo " this script's own header comment; watch http://localhost:8006" echo " if you want to see what's actually happening)" elapsed=0 while [ ! -e shared/BUILD_DONE ] && [ ! -e shared/BUILD_FAILED ]; do if [ "$elapsed" -ge "$TIMEOUT_S" ]; then echo "Timed out after ${TIMEOUT_S}s waiting for the build." >&2 echo "Check the VM directly (http://localhost:8006) -- it may still" >&2 echo "be mid Windows-install, or oem/install.bat may have wedged." >&2 exit 1 fi sleep 10 elapsed=$((elapsed + 10)) printf '.' done echo if [ -e shared/BUILD_FAILED ]; then echo "==> build FAILED. Log:" >&2 cat shared/dist/build.log 2>/dev/null || cat shared/build.log.failed 2>/dev/null || true exit 1 fi msi="$(find shared/dist -maxdepth 1 -name '*.msi' | head -n1)" if [ -z "$msi" ]; then echo "BUILD_DONE appeared but no .msi found in shared/dist -- see" >&2 echo "shared/dist/build.log" >&2 exit 1 fi cp "$msi" "$OUT_DIR/" echo "==> done: $OUT_DIR/$(basename "$msi")"