diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index fd0ffe18..d8cb9e1a 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -575,27 +575,11 @@ jobs: # No fork guard here: this workflow only triggers on tag pushes and # workflow_dispatch, both of which need write access to this repo. runs-on: [self-hosted, linux, x64, lab-2204] - # This runner sets no locale, and two tools in this job read one. icotool - # says so outright - "icotool: cannot set locale: No such file or - # directory" - and WiX then refuses a plainly relative Directory/@Name: - # - # meshbench.wxs(135) : error WIX0389: The Directory/@Name attribute's - # value, 'MeshBench', is not a relative path. - # - # 'MeshBench' is relative by any reading, so that is WiX's own path - # handling and not the authoring. It is a known shape on Linux - # (wixtoolset/issues#7154, Ubuntu 22.04, closed "not planned") and it turns - # up in minimal environments - that issue, and the Docker SDK images in the - # discussion beside it - which is what a runner with no locale is. - # - # C.UTF-8 rather than a generated en_GB: glibc has carried it built in - # since 2.35, which is exactly this runner's floor, so nothing has to be - # installed for it to exist. - # - # v0.0.5's installer was built by wixl, which had no such trouble. WiX - # arrived with the dialogs, wixl building none, and the Windows job has - # failed before reaching the MSI on every run since - so this is the first - # time WiX has actually run here. + # This runner sets no locale, and icotool reads one: "icotool: cannot set + # locale: No such file or directory". C.UTF-8, which glibc has carried + # built in since 2.35 - this runner's floor - so nothing is installed for + # it. (WiX met the same missing locale here before it was moved to the + # windows-msi job, which is where it can actually build.) env: LANG: C.UTF-8 LC_ALL: C.UTF-8 @@ -615,19 +599,16 @@ jobs: - name: Dependencies run: | sudo apt-get update - # msitools is msiinfo and msibuild: one reads the built package for - # verify-msi.sh and the other puts back the single row WiX will not - # author. wixl used to build the installer and no longer does - it - # builds no dialogs, and the installer was asked for two. # icoutils is for the one file Windows wants that the repository does # not carry: an .ico holding every size, built from the committed # PNGs the same way macos-app.sh builds the .icns. python3-pil - # composes the two dialog bitmaps from the same committed artwork - - # ImageMagick would have done, but 22.04 carries version 6, whose - # command is `convert` and not `magick`, and a build that works where - # it was written and fails where it runs is the worst kind. + # composes the installer's two dialog bitmaps from the same committed + # artwork - ImageMagick would have done, but 22.04 carries version 6, + # whose command is `convert` and not `magick`. The installer itself + # is built in the windows-msi job and read back in + # windows-msi-verify, which installs msitools for that. sudo apt-get install -y --no-install-recommends \ - gcc-mingw-w64-x86-64 zip msitools icoutils python3-pil + gcc-mingw-w64-x86-64 zip icoutils python3-pil - name: Build @@ -658,6 +639,7 @@ jobs: { echo "::error::version '$VERSION' is not X.Y.Z or X.Y.Z-dev.N"; exit 1; } ;; esac go run ./tools/licgen -text dist/meshbench/LICENCES + mkdir -p dist/msi GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc \ go build -trimpath \ -ldflags "-H windowsgui -X gioui.org/app.ID=io.github.meshbench.meshbench \ @@ -719,8 +701,11 @@ jobs: https://github.com/googlefonts/noto-emoji/raw/v2.051/fonts/NotoColorEmoji.ttf echo compact > dist/meshbench/VARIANT (cd dist && zip -qr meshbench-windows-x86_64-compact.zip meshbench) - packaging/windows-msi.sh dist/meshbench "$VERSION" \ - "dist/meshbench-windows-x86_64-compact.msi" + # The installer's half of the compact pair: the tree as it stands, + # and what the WiX build needs from this side. The .msi itself is + # built on Windows by the windows-msi job (#508). + cp -a dist/meshbench dist/msi/stage-compact + packaging/windows-msi.sh dist/msi/stage-compact "$VERSION" dist/msi/extra-compact # Now the emulators, making the same tree the bundled variant. . packaging/emulator-pins.env @@ -774,25 +759,18 @@ jobs: ls -la dist/*.zip file dist/meshbench/meshbench.exe - - name: The installer + - name: The installer's half from here # An MSI as well as the zip rather than instead of it. The zip is a # complete build and stays the download for a memory stick, a build # agent, or anyone who wants no installer. # - # What the installer adds is a deliberate location. This bundle finds - # the emulators and the chip model beside meshbench.exe, so a user who - # unpacks the zip into Downloads and then moves the one executable - # somewhere tidy - which is the natural thing to do with a single - # executable - has broken emulation and will not be told why. The - # installer puts the whole directory somewhere on purpose, and brings - # an entry in Apps and Features, an uninstall, and an upgrade that - # replaces the previous version instead of accumulating beside it. - # - # Still no Windows runner: WiX reads packaging/meshbench.wxs and - # writes the .msi here, beside the mingw cross-build that made the - # .exe. The script checks the tables of what it built before it - # returns, because an installer that is wrong about upgrading looks - # exactly like one that is right until somebody installs two versions. + # What the installer adds is a deliberate location, an entry in Apps + # and Features, an uninstall, an upgrade that replaces the previous + # version - and, since #508, a wizard that asks where to go and says + # when it has finished. That needs the WiX toolset, which builds an MSI + # only on Windows, so this step prepares and the windows-msi job + # builds: the icon and the dialog bitmaps need icotool and Pillow, + # which are here, and the database needs msi.dll, which is there. run: | set -e VERSION="${{ inputs.version }}" @@ -802,9 +780,18 @@ jobs: *) VERSION="0.0.0-dev-$(git rev-parse --short HEAD)" ;; esac fi - packaging/windows-msi.sh dist/meshbench "$VERSION" \ - "dist/meshbench-windows-x86_64-bundled.msi" - ls -la dist/*.msi + cp -a dist/meshbench dist/msi/stage-bundled + packaging/windows-msi.sh dist/msi/stage-bundled "$VERSION" dist/msi/extra-bundled + ls dist/msi + + # Both staged trees and what goes with them, for the Windows runner. Not + # a release asset: the release takes the MSIs once verify-msi.sh has read + # them back. + - uses: actions/upload-artifact@v7 + with: + name: msi-stage + retention-days: 1 + path: dist/msi - uses: actions/upload-artifact@v7 if: inputs.release || startsWith(github.ref, 'refs/tags/v') @@ -812,9 +799,84 @@ jobs: name: meshbench-windows # As the Linux upload above. retention-days: ${{ inputs.release && 1 || 3 }} + path: dist/*.zip + + windows-msi: + timeout-minutes: 30 + # The installer, built where WiX can build one. WiX writes the MSI + # database through Windows' own msi.dll and refuses everywhere else - on + # Linux every Directory/@Name is "not a relative path", and with the + # names removed it dies on "Unable to load shared library 'msi.dll'" + # (#508). wixl runs on Linux and builds no dialogs, so a double-clicked + # installer showed a progress bar and closed without a word. + # + # windows-latest is a hosted runner, which this public repository pays + # nothing for. Only the WiX build runs here; staging is on Linux above, + # and the check is on Linux below, where msitools reads the tables. + needs: windows + if: inputs.windows || startsWith(github.ref, 'refs/tags/v') + runs-on: windows-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/download-artifact@v8 + with: { name: msi-stage, path: msi } + - name: WiX + shell: pwsh + run: | + dotnet tool install --global wix --version 5.0.2 + wix extension add -g WixToolset.UI.wixext/5.0.2 + wix --version + - name: Build both installers + shell: pwsh + run: | + New-Item -ItemType Directory -Force dist | Out-Null + packaging/windows-msi.ps1 -Stage msi/stage-compact -Extra msi/extra-compact ` + -Out dist/meshbench-windows-x86_64-compact.msi + packaging/windows-msi.ps1 -Stage msi/stage-bundled -Extra msi/extra-bundled ` + -Out dist/meshbench-windows-x86_64-bundled.msi + - uses: actions/upload-artifact@v7 + with: + name: msi-unverified + retention-days: 1 path: | - dist/*.zip dist/*.msi + dist/*.msi.files + + windows-msi-verify: + timeout-minutes: 15 + # What Windows will act on, read back out of each database rather than out + # of the source: the upgrade code and version, the file count, ALLUSERS, + # the dialogs, and where an upgrade goes. Only what passes is offered to + # the release, as meshbench-windows-msi. + needs: windows-msi + if: inputs.windows || startsWith(github.ref, 'refs/tags/v') + runs-on: [self-hosted, linux, x64, lab-2204] + steps: + - uses: actions/checkout@v7 + - uses: actions/download-artifact@v8 + with: { name: msi-stage, path: msi } + - uses: actions/download-artifact@v8 + with: { name: msi-unverified, path: dist } + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends msitools + - name: Read both back + run: | + set -e + for v in compact bundled; do + . "msi/extra-$v/msi.env" + msi="dist/meshbench-windows-x86_64-$v.msi" + # The count of what WiX harvested, taken on the Windows runner. + files=$(cat "$msi.files") + packaging/verify-msi.sh "$msi" "$MSIVERSION" "$UPGRADE" "$((files + 1))" + done + - uses: actions/upload-artifact@v7 + if: inputs.release || startsWith(github.ref, 'refs/tags/v') + with: + name: meshbench-windows-msi + retention-days: ${{ inputs.release && 1 || 3 }} + path: dist/*.msi release: timeout-minutes: 20 @@ -840,7 +902,10 @@ jobs: if: >- always() && (inputs.release || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v'))) - needs: [linux, macos, windows] + # windows-msi-verify, not just windows: the MSIs are built and read back + # after the windows job finishes, so without it this job would start + # before meshbench-windows-msi exists and refuse a zip with no .msi. + needs: [linux, macos, windows, windows-msi-verify] # Hosted, unlike every job above it, because this one builds nothing. It # downloads what they built, checks it, and hands it to gh - so the glibc # floor the lab-2204 label exists to pin does not apply here at all. That @@ -869,8 +934,11 @@ jobs: tag: ${{ steps.publish.outputs.tag }} steps: - uses: actions/checkout@v7 + # The release artefacts only: the MSI stage and the unverified MSIs are + # working files between jobs, and only meshbench-windows-msi has been + # read back. - uses: actions/download-artifact@v8 - with: { path: incoming } + with: { path: incoming, pattern: 'meshbench-*' } # This job is the one that still needs gh: creating and uploading a # release is a write, and reimplementing that over curl would be a worse @@ -939,7 +1007,7 @@ jobs: if ls dist/*windows*.zip >/dev/null 2>&1 && ! ls dist/*windows*.msi >/dev/null 2>&1; then echo "::error::a Windows zip was built and no .msi came with it;"\ "the installer is packaging/meshbench.wxs, built by the"\ - "windows job's installer step" + "windows-msi job and read back by windows-msi-verify" exit 1 fi # The project's own licence is checked by the linux job, which has diff --git a/CHANGELOG.md b/CHANGELOG.md index a38e02b4..bb79a90b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,12 @@ had changed in them - which is the gap this file exists to close. ### Changed +- **The Windows installer asks where to go and says when it has finished.** + It is built by the WiX toolset again, now on a Windows runner, which is the + only place WiX can build one: a Destination Folder page with a Change button, + a completion page, the brand on both, and the install location in Apps and + Features. Staging stays on Linux, and the tables are read back there before + the release takes the installers. - **`sim.state` says when the wall clock decided something.** `reproducible` is false, with the reason, once a node-writing verb ran at a playing clock without `at_ms`, a client outside the simulation wrote to a served diff --git a/docs/install.md b/docs/install.md index 0dfd39ab..cb5b8c4a 100644 --- a/docs/install.md +++ b/docs/install.md @@ -94,21 +94,14 @@ Intel Macs are not built yet. Ask if you need one. Two downloads, and either is a complete build. -`meshbench-windows-x86_64-bundled.msi` is the installer. Double-click it and it -installs to `C:\Program Files\MeshBench`, adds a Start menu entry, and appears -in Apps and Features with an uninstall. Installing a newer one replaces the -installation rather than putting a second copy beside it. The uninstall removes -what it installed and nothing else: your fixtures, cached firmware, terrain -tiles and settings live under your profile and are left alone. - -It asks nothing while it runs. The toolset that builds it cannot draw dialogs, -and the one that can only runs on Windows, which this pipeline has none of. To -install somewhere else, or per-user, pass it on the command line: - -``` -msiexec /i meshbench-windows-x86_64-bundled.msi INSTALLDIR="D:\Tools\MeshBench" -msiexec /i meshbench-windows-x86_64-bundled.msi MSIINSTALLPERUSER=1 -``` +`meshbench-windows-x86_64-bundled.msi` is the installer. Double-click it and it asks +where to go — `C:\Program Files\MeshBench` unless you browse somewhere else — +adds a Start menu entry, and appears in Apps and Features with an uninstall and +the location it used. Installing a newer one replaces the installation rather +than putting a second copy beside it, and keeps the directory you chose. The +uninstall removes what it installed and nothing else: your fixtures, cached +firmware, terrain tiles and settings live under your profile and are left +alone. Everything the wizard offers can also be a switch, which is what you want for an unattended install, and there are two it does not offer. From a Command diff --git a/packaging/meshbench.wxs b/packaging/meshbench.wxs index 5838c925..bcd4f322 100644 --- a/packaging/meshbench.wxs +++ b/packaging/meshbench.wxs @@ -1,56 +1,44 @@ - - + + Version="$(var.Version)" + ProductCode="$(var.ProductCode)" + UpgradeCode="6f2a1c84-7f3b-4c9e-9a6d-0d8f5b1e2c30" + Language="1033" + Codepage="1252" + InstallerVersion="500" + Compressed="yes"> - - + - + - - - - + - - - - - - NOT NEWERVERSIONDETECTED OR Installed - + + + - - - - + + - + + + - + + + + - - - - - - - + + + + - - + + + + - + - - + + - - + - - + + - - + + + + - + - + + + + + + + + + + + + diff --git a/packaging/verify-msi.sh b/packaging/verify-msi.sh index 54cc1950..6e54ef92 100755 --- a/packaging/verify-msi.sh +++ b/packaging/verify-msi.sh @@ -66,9 +66,13 @@ say "product code $got, derived from the version" upgrades=$(table Upgrade | upper) holds "$upgrades" "$want" || bad "$msi has no Upgrade row for $want, so it would install beside an older version" -holds "$upgrades" OLDERVERSIONBEINGUPGRADED || +# The property names are the toolset's: WiX 4 and later's MajorUpgrade writes +# WIX_UPGRADE_DETECTED and WIX_DOWNGRADE_DETECTED, where WiX 3 and hand-authored +# packages used OLDERVERSIONBEINGUPGRADED and NEWERVERSIONDETECTED. Either pair +# is the same two rows; the check is that both rows exist. +holds "$upgrades" "WIX_UPGRADE_DETECTED\|OLDERVERSIONBEINGUPGRADED" || bad "$msi detects no older version to remove" -holds "$upgrades" NEWERVERSIONDETECTED || +holds "$upgrades" "WIX_DOWNGRADE_DETECTED\|NEWERVERSIONDETECTED" || bad "$msi would let an older build install over a newer one" say "older versions are removed and a newer one is refused" @@ -92,6 +96,38 @@ case "$(prop SecureCustomProperties)" in esac say "installs under Program Files, per machine or per user, into a chosen location" +# The location it chose, said back. Nothing sets ARPINSTALLLOCATION by itself, +# and without it Apps and Features shows a blank Install location - so a person +# who wants to know where their copy went has to guess. The action is generated +# from the SetProperty in meshbench.wxs and named after the property it sets. +holds "$(table CustomAction)" SetARPINSTALLLOCATION || + bad "$msi does not set ARPINSTALLLOCATION, so Apps and Features would show no install location" +holds "$(table InstallExecuteSequence)" SetARPINSTALLLOCATION || + bad "$msi never runs SetARPINSTALLLOCATION, so the property is authored and unset" +say "reports its install location to Apps and Features" + +# The dialogs. WiX builds them and wixl could not, which is the whole reason +# this package moved toolset - so a build that quietly lost them would undo it. +dlgs=$(table Dialog) +for d in WelcomeDlg InstallDirDlg BrowseDlg ExitDialog; do + holds "$dlgs" "$d" || bad "$msi has no $d, so the installer cannot ask or report" +done +say "asks where to install, and says when it has finished" + +# And where an upgrade goes. Without the search, a version installed into a +# chosen directory comes back in Program Files and the choice is silently +# undone; measured before it was added. +holds "$(table Registry)" InstallDir || + bad "$msi does not record its install directory, so an upgrade would not stay put" +say "remembers where it was installed" + +# And that it can be taken off again. An MSI gets this for nothing, which is +# exactly why it is worth asserting: the maintenance dialogs come from the UI +# extension, and a package that lost them would still install perfectly and +# only be found wanting by somebody trying to remove it. +holds "$dlgs" MaintenanceTypeDlg || + bad "$msi has no maintenance dialog, so running it again offers no Remove" +say "offers Repair and Remove when run again" holds "$(table Shortcut)" ProgramMenuFolder || bad "$msi makes no Start menu entry" say "Start menu entry present" diff --git a/packaging/windows-msi.ps1 b/packaging/windows-msi.ps1 new file mode 100644 index 00000000..826fd48d --- /dev/null +++ b/packaging/windows-msi.ps1 @@ -0,0 +1,61 @@ +# Build a Windows installer with the WiX toolset, on Windows. +# +# packaging/windows-msi.ps1 -Stage -Extra -Out +# +# is what packaging/windows-msi.sh made on Linux: the icon, the dialog +# bitmaps, the installer's note and msi.env. WiX builds the dialogs wixl could +# not - a Destination Folder page with a Change button, and a page that says the +# install finished - and it only builds an MSI on Windows (#508). +param( + [Parameter(Mandatory)] [string] $Stage, + [Parameter(Mandatory)] [string] $Extra, + [Parameter(Mandatory)] [string] $Out +) +$ErrorActionPreference = 'Stop' + +$cfg = @{} +Get-Content (Join-Path $Extra 'msi.env') | ForEach-Object { + $k, $v = $_ -split '=', 2 + if ($k) { $cfg[$k] = $v } +} + +$wxs = Join-Path $PSScriptRoot 'meshbench.wxs' +$Stage = (Resolve-Path $Stage).Path +$Extra = (Resolve-Path $Extra).Path +$Out = [System.IO.Path]::GetFullPath($Out) + +# One command, and no harvest step: WiX walks the tree itself, in its own +# order, so the same tree built twice is the same installer. +& wix build -arch x64 ` + -d "ProductCode=$($cfg.PRODUCT)" -d "Version=$($cfg.MSIVERSION)" ` + -d "Stage=$Stage" -d "Extra=$Extra" ` + -ext WixToolset.UI.wixext ` + -o $Out $wxs +if ($LASTEXITCODE -ne 0) { throw "wix build failed with $LASTEXITCODE" } + +# ALLUSERS back to 2, which is the one thing the toolset will not author. +# +# This package has always been dual-purpose: per-machine by default, and +# per-user with MSIINSTALLPERUSER=1, which is what lets somebody without +# administrator rights install into their own profile. WiX 4 removed the +# option and emits ALLUSERS=1, so the row is corrected here, through Windows +# Installer's own database API, rather than a documented install route being +# dropped to suit a schema. verify-msi.sh checks it. +$installer = New-Object -ComObject WindowsInstaller.Installer +$db = $installer.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $null, $installer, @($Out, 1)) +$view = $db.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $db, + @("UPDATE ``Property`` SET ``Value``='2' WHERE ``Property``='ALLUSERS'")) +$view.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $view, $null) | Out-Null +$view.GetType().InvokeMember('Close', 'InvokeMethod', $null, $view, $null) | Out-Null +$db.GetType().InvokeMember('Commit', 'InvokeMethod', $null, $db, $null) | Out-Null +[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($db) | Out-Null + +# How many files WiX harvested from, for verify-msi.sh to hold the package to. +# Counted here rather than where the tree was staged: it reached this runner as +# an artifact, which stores each symlink in the emulators as the file it points +# at, so a count from the Linux side came out short. +$files = (Get-ChildItem -Path $Stage -Recurse -File -Force).Count +Set-Content -Path "$Out.files" -Value $files -NoNewline + +Get-Item $Out | Format-List Name, Length +"$files files staged" diff --git a/packaging/windows-msi.sh b/packaging/windows-msi.sh index 8d06e14d..05b8c481 100755 --- a/packaging/windows-msi.sh +++ b/packaging/windows-msi.sh @@ -1,43 +1,48 @@ #!/usr/bin/env bash -# Build the Windows installer from an assembled bundle, on Linux. +# Get a Windows installer ready to build: everything the WiX step needs that is +# made from the repository rather than harvested from the staged tree. # -# packaging/windows-msi.sh +# packaging/windows-msi.sh # -# is the directory meshbench.exe sits in, the same one the zip is -# made from, and everything in it goes into the installer. That is the point: -# the emulators and the SX1262 model are found beside the binary, so an -# installer that carried the binary alone would produce a build that cannot -# emulate a board and cannot say why. +# The installer itself is built by the WiX toolset, on Windows, by +# packaging/windows-msi.ps1. WiX cannot build an MSI anywhere else: it needs +# Windows' own msi.dll to write the database, and on Linux it dies on +# "Unable to load shared library 'msi.dll'" after refusing every +# Directory/@Name (#508). wixl, which does run here, builds no dialogs. So the +# work is split: this half runs on Linux with the tools that only Linux has +# (icotool, Pillow), the build runs on a Windows runner, and verify-msi.sh +# reads the result back on Linux with msitools. # -# No Windows runner. wixl reads the WiX source and writes the .msi here, beside -# the mingw cross-build that produced the .exe. What that costs is the -# installer's user interface: wixl builds no dialogs, so msiexec shows a -# progress bar and takes its answers from the command line instead. Those -# answers - a location, per-user, a desktop shortcut - are written out for -# somebody installing this in docs/install.md. +# What lands in : the icon, the two dialog bitmaps, the note the +# installer adds beside the binary, and msi.env, which carries the version the +# MSI is stamped with, the product and upgrade codes, and how many files the +# stage holds here. The check uses the count windows-msi.ps1 takes of the tree +# WiX actually harvested instead, because the tree crosses to the Windows +# runner as an artifact and the emulators' symlinks arrive as the files they +# point at - a count taken on this side came out short. set -euo pipefail stage=${1:?the directory meshbench.exe sits in} version=${2:?the release version} -out=${3:?the .msi to write} +extra=${3:?the directory to write into} here=$(cd "$(dirname "$0")" && pwd) missing="" -for t in wixl wixl-heat msiinfo msibuild icotool python3; do +for t in icotool python3; do command -v "$t" >/dev/null || missing="$missing $t" done if [ -n "$missing" ]; then - echo "::error::windows-msi: missing:$missing - wixl and wixl-heat are the" \ - "'wixl' package on Debian and Ubuntu rather than 'msitools', which is" \ - "where msiinfo lives; icotool is 'icoutils'" >&2 + echo "::error::windows-msi: missing:$missing - icotool is 'icoutils'" >&2 exit 1 fi +# The dialog bitmaps are composed with Pillow, which python3 does not carry by +# itself. Checked here rather than met as a traceback minutes into a release. +python3 -c 'import PIL' 2>/dev/null || { + echo "::error::windows-msi: python3 cannot import PIL - install python3-pil" >&2 + exit 1 +} -# Windows Installer compares three numeric fields and ignores anything after -# them, so a development version has no version to compare and is given the -# lowest one. Every real release is a plain X.Y.Z and passes through. -msiversion=$version # A development build's suffix is not an MSI version, but its base is: the # pre-release of 0.0.11 installs as 0.0.11, so the MSI ordering it takes part # in is the one the tag means. A version that is not X.Y.Z at all is 0.0.0. @@ -55,76 +60,26 @@ import uuid, sys print(uuid.uuid5(uuid.UUID('$upgrade'), sys.argv[1]).urn[9:].upper()) " "$msiversion") -# wixl reads every File Source relative to the directory it is run from, and -# hands an absolute one to g_file_get_child, which rejects it with a GLib -# assertion and then says it cannot find the file. So the two source trees are -# linked into one working directory and named relatively from there. -work=$(mktemp -d) -trap 'rm -rf "$work"' EXIT -extra=$work/extra mkdir -p "$extra" -ln -s "$(cd "$stage" && pwd)" "$work/stage" -out=$(cd "$(dirname "$out")" && pwd)/$(basename "$out") - # Windows wants one icon file holding every size, the way macOS wants one -# .icns. Built here from the committed PNGs for the same reason macos-app.sh -# builds the .icns there: one set of source images, and no second copy of the -# mark to go stale. +# .icns, built from the committed PNGs so there is no second copy of the mark. icotool -c -o "$extra/meshbench.ico" \ "$here/icons/meshbench-16.png" "$here/icons/meshbench-32.png" \ "$here/icons/meshbench-48.png" "$here/icons/meshbench-64.png" \ "$here/icons/meshbench-128.png" "$here/icons/meshbench-256.png" - +# The two bitmaps the dialogs are drawn on; see dialog-bitmaps.py. +python3 "$here/dialog-bitmaps.py" \ + "$here/../docs/brand/meshbench-card.png" \ + "$here/icons/meshbench-256.png" \ + "$extra" sed "s//$version/" "$here/installed-by-msi.txt" \ > "$extra/installed-by-msi.txt" -# Everything in the bundle, as components. Sorted, so the source that goes -# into a build is the same from one run to the next and a diff of two builds -# is about what changed rather than about what order find walked in. -(cd "$stage" && find . -type f | sed 's|^\./||' | LC_ALL=C sort) | - wixl-heat --var var.Stage --directory-ref INSTALLDIR \ - --component-group Bundle --prefix "" --win64 > "$work/bundle.wxs" - -files=$(grep -c ' "$extra/msi.env" <