#!/usr/bin/env bash
# Build the Windows one-click installer (Inno Setup .exe).
#
# Runs the normal Windows packaging (fresh web bundle + cmake build (MSVC,
# Windows-only)), then compiles native/windows/installer/KuroScreensaver.iss
# with the Inno Setup compiler (ISCC) into
# dist-native/KuroScreensaver-Setup-<version>.exe.
#
# ISCC is Windows-only; on macOS/Linux it runs under wine (`wine ISCC.exe ...`).
# If neither is found, this prints instructions and exits 0 after producing the
# publish folder, so the .iss can be compiled on a Windows box or in CI.
#
# Usage: bash scripts/package-windows-installer.sh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
# 1. Fresh web bundle + cmake build (produces the publish/ folder the .iss packs).
bash "$ROOT/scripts/package-windows.sh"
# All three are relative on purpose: we cd'd to $ROOT above, and on Windows $ROOT
# is a Git-Bash path (/d/a/...) that native binaries — node.exe, ISCC.exe — cannot
# resolve. Handing them the absolute form is why this script never ran on Windows.
VERSION="$(node -p "require('./package.json').version")"
ISS="native/windows/installer/KuroScreensaver.iss"
OUT="dist-native"
mkdir -p "$OUT"
# 2. Find an Inno Setup compiler: native ISCC, its default install location
# (Windows runners ship it there but do NOT put it on PATH), or via wine.
#
# MSYS2_ARG_CONV_EXCL: under Git-Bash, MSYS rewrites any argument starting with
# "/" into a Windows path, so ISCC saw /DMyAppVersion=... and /Odist-native as
# two extra script filenames and bailed with "You may not specify more than one
# script filename". Excluding those two prefixes passes them through verbatim.
# The variable is inert outside MSYS, so the wine path is unaffected.
run_iscc() {
local installed
export MSYS2_ARG_CONV_EXCL="/D;/O"
if command -v iscc >/dev/null 2>&1; then
iscc "/DMyAppVersion=$VERSION" "/O$OUT" "$ISS"
elif command -v ISCC >/dev/null 2>&1; then
ISCC "/DMyAppVersion=$VERSION" "/O$OUT" "$ISS"
elif installed="$(ls -d "/c/Program Files (x86)/Inno Setup"*/ISCC.exe 2>/dev/null | head -1)" \
&& [ -n "$installed" ]; then
"$installed" "/DMyAppVersion=$VERSION" "/O$OUT" "$ISS"
elif command -v wine >/dev/null 2>&1 && [ -n "${ISCC_EXE:-}" ] && [ -f "$ISCC_EXE" ]; then
wine "$ISCC_EXE" "/DMyAppVersion=$VERSION" "/O$OUT" "$ISS"
else
# 127 = no compiler at all, distinct from any exit code ISCC itself returns.
return 127
fi
}
echo "=== Inno Setup compile (v$VERSION) ==="
rc=0
run_iscc || rc=$?
if [ "$rc" -eq 0 ]; then
echo "✓ $OUT/KuroScreensaver-Setup-$VERSION.exe"
elif [ "$rc" -ne 127 ]; then
# A compiler ran and rejected the script. Always fatal, strict mode or not —
# reporting "compiler not found" here would send the reader hunting for an
# install that is already present, and passing would hide a broken .iss.
echo "✗ ISCC ran but failed to compile $ISS (exit $rc, see its output above)." >&2
exit 1
else
cat <<EOF
⚠ Inno Setup compiler (ISCC) not found — the publish folder is ready but the
installer .exe was NOT built on this machine.
To finish, compile the installer where Inno Setup 6 is available:
• Windows: ISCC /DMyAppVersion=$VERSION /Odist-native native/windows/installer/KuroScreensaver.iss
• wine: ISCC_EXE="/path/to/ISCC.exe" bash scripts/package-windows-installer.sh
• CI: run the same ISCC step on a windows runner
Inno Setup 6: https://jrsoftware.org/isdl.php
EOF
# Locally a missing compiler is fine (the publish folder is still useful), but
# CI must never report success without having compiled the .iss — that silent
# pass is how a broken installer reaches a release. Set KURO_REQUIRE_ISCC=1
# anywhere the compile is the whole point of the run.
if [ -n "${KURO_REQUIRE_ISCC:-}" ]; then
echo "✗ KURO_REQUIRE_ISCC is set, but no Inno Setup compiler was found." >&2
exit 1
fi
fi