#!/usr/bin/env bash # Assemble the Windows installer from a finished cross-build. # # ./docker/windows/build.sh docker/windows/package.sh # # Expects `cargo build --release --target x86_64-pc-windows-gnu -p darkroom-desktop` # to have run in the same target directory. Produces # DarkRoom--x86_64-setup.exe in $OUT (default: target-windows/installer). # # Runs inside the container, where makensis is; docs/windows.md §5 is the # specification this implements. set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO="$(cd "${HERE}/../.." && pwd)" # Absolute, whatever CARGO_TARGET_DIR was. NSIS on a POSIX host translates # the backslashes in `${STAGE}\LICENSE` only when it can tell the path is a # POSIX one, which it decides from a leading `/`; a relative `target-windows` # — which is exactly what CI sets — reaches it as a name with a literal # backslash in it and "LicenseData: open failed". The first CI run died there, # after every step before it had passed. TARGET_DIR="$(realpath -m "${CARGO_TARGET_DIR:-${REPO}/target}")" TARGET="${TARGET_DIR}/x86_64-pc-windows-gnu/release" OUT="$(realpath -m "${OUT:-${TARGET_DIR}/installer}")" EXE="${TARGET}/darkroom-desktop.exe" [[ -f "${EXE}" ]] || { echo "error: ${EXE} not built" >&2; exit 1; } # The version, from the workspace rather than restated here — the same single # source tools/set-version.sh writes and the APK packager reads. VERSION="$(sed -n 's/^version = "\(.*\)"$/\1/p' "${REPO}/Cargo.toml" | head -1)" [[ -n "${VERSION}" ]] || { echo "error: no version in Cargo.toml" >&2; exit 1; } echo "==> version ${VERSION}" # Staging: exactly what the installer carries (windows.md §5.2), and nothing # from a previous run — a model dropped from the tree must not linger here # and go on shipping. STAGE="${OUT}/stage" rm -rf "${STAGE}" mkdir -p "${STAGE}/models" cp "${EXE}" "${STAGE}/darkroom.exe" # CRLF for the licence page: it is shown in a Windows edit control, which # draws a bare LF as nothing and runs the whole GPL together. sed 's/$/\r/' "${REPO}/LICENSE" > "${STAGE}/LICENSE" # The models, with the guard every other packager carries: an LFS pointer is # ~130 bytes and looks exactly like a model to `cp`. Shipped, it fails inside # tract on the user's machine with a message about a broken graph rather than # a checkout that needed `git lfs pull`. Only the weights are checked; the # scene model's vocabulary and category descriptor are legitimately small. for dir in face scene; do for f in "${REPO}/models/${dir}"/*; do case "$(basename "${f}")" in README.md) continue ;; esac if [[ "${f}" == *.onnx && "$(stat -c%s "${f}")" -lt 100000 ]]; then echo "error: $(basename "${f}") is $(stat -c%s "${f}") bytes — an LFS pointer, not a model." >&2 echo " run: git lfs pull" >&2 exit 1 fi cp "${f}" "${STAGE}/models/" done done echo "==> staged $(ls "${STAGE}/models" | wc -l) model file(s)" # One installer in the output directory, the one just built. The directory # is cached between CI runs, so after a version bump a glob over it would find # two and the smoke test would hand Wine both names as one path. rm -f "${OUT}"/DarkRoom-*-x86_64-setup.exe INSTALLER="${OUT}/DarkRoom-${VERSION}-x86_64-setup.exe" # NSIS wants Windows-style paths in File directives even on a POSIX host, and # the script takes its inputs by define so nothing about the layout here is # written into it. makensis -V2 \ -DVERSION="${VERSION}" \ -DSTAGE="${STAGE}" \ -DOUT="${INSTALLER}" \ "${REPO}/packaging/windows/darkroom.nsi" ls -la "${INSTALLER}" echo "==> ${INSTALLER}"