Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1165,8 +1165,18 @@ function Publish-AppResources {
"${env:ProgramFiles(x86)}\Windows Kits\10\bin"
) | Where-Object { Test-Path $_ }

# makepri.exe runs on the HOST, not the target. Prefer the host arch first
# so we don't pick e.g. arm64\makepri.exe on an x64 box (which fails with
# "not a valid application for this OS platform").
$hostArch = switch ($env:PROCESSOR_ARCHITECTURE) {
'AMD64' { 'x64' }
'ARM64' { 'arm64' }
default { 'x86' }
}
$toolArchOrder = @($hostArch) + (@('x64','arm64','x86') | Where-Object { $_ -ne $hostArch })

foreach ($root in $sdkBinRoots) {
foreach ($toolArch in @("arm64", "x64", "x86")) {
foreach ($toolArch in $toolArchOrder) {
$candidates = Get-ChildItem "$root\*\$toolArch\makepri.exe" -ErrorAction SilentlyContinue |
Sort-Object { [version]($_.FullName -replace '.*\\(\d+\.\d+\.\d+\.\d+)\\.*', '$1') } -Descending |
Select-Object -First 1
Expand Down
24 changes: 24 additions & 0 deletions installer/BootstrapMate.Installer.wixproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,33 @@
<PackageReference Include="WixToolset.Util.wixext" Version="6.0.2" />
</ItemGroup>

<!-- Suppress ICE03 (Invalid Language Id / String overflow in File.Language).
The WinUI 3 MUI files harvested from publish/app/<arch>/ include locales
(gd-gb, mi-NZ) whose LCIDs are not in the ICE validation table, and the
master Microsoft.ui.xaml.dll has more locales than the File.Language
column's 255-char limit. Both are benign for actual install/uninstall. -->
<PropertyGroup>
<SuppressIces>ICE03</SuppressIces>
</PropertyGroup>

<!-- Skip when the GUI publish output is missing — the BeforeBuild target
below will then fail with a clearer, more actionable message rather
than the harvester script's stack trace. -->
<Target Name="GenerateGuiAppFiles"
BeforeTargets="BeforeBuild"
Condition="Exists('$(AppDir)\BootstrapMate.exe')">
<MakeDir Directories="$(IntermediateOutputPath)" />
<Exec Command="pwsh -NoProfile -ExecutionPolicy Bypass -File &quot;$(MSBuildProjectDirectory)\Generate-GuiAppFiles.ps1&quot; -AppDir &quot;$(AppDir)&quot; -OutputPath &quot;$(IntermediateOutputPath)GuiAppFiles.wxs&quot;" />
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)GuiAppFiles.wxs" />
</ItemGroup>
</Target>

<Target Name="BeforeBuild">
<Error Text="BootstrapMate executable not found at $(BinDir)\installapplications.exe. Please run build.ps1 first."
Condition="!Exists('$(BinDir)\installapplications.exe')" />
<Error Text="BootstrapMate GUI app executable not found at $(AppDir)\BootstrapMate.exe. Run build.ps1 to publish the GUI before building the MSI."
Condition="!Exists('$(AppDir)\BootstrapMate.exe')" />
</Target>

</Project>
15 changes: 11 additions & 4 deletions installer/Generate-GuiAppFiles.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ $lines.Add(' <Fragment>')
$lines.Add(' <ComponentGroup Id="GuiAppFiles" Directory="INSTALLDIR">')

$files = Get-ChildItem -Path $appDir -Recurse -File | Sort-Object FullName
$idx = 0
$sha1 = [System.Security.Cryptography.SHA1]::Create()
foreach ($file in $files) {
$idx++
$relPath = $file.FullName.Substring($appDir.Length + 1)
$relDir = [System.IO.Path]::GetDirectoryName($relPath)
$compId = 'c_{0:D5}' -f $idx
$fileId = 'f_{0:D5}' -f $idx

# Deterministic IDs derived from a SHA1 hash of the relative path so that
# unchanged files keep the same Component Id (and therefore the same
# Guid="*"-derived GUID) across builds. Sequential IDs would shift whenever
# files are added/removed (e.g. WinUI 3 ships a new locale), regenerating
# most GUIDs and breaking MSI upgrade tracking — orphaning old components
# or duplicating files at the same path.
$hashHex = [System.BitConverter]::ToString($sha1.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($relPath.ToLowerInvariant()))).Replace('-','').Substring(0,16).ToLowerInvariant()
$compId = "c_$hashHex"
$fileId = "f_$hashHex"

if ($relDir) {
$lines.Add(" <Component Id=`"$compId`" Guid=`"*`" Subdirectory=`"$relDir`">")
Expand Down
10 changes: 4 additions & 6 deletions installer/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@
<RemoveFile Id="RemoveOldExecutable" Name="installapplications.exe" On="both" />
</Component>

<!-- GUI Application -->
<Component Id="BootstrapMateGuiApp" Directory="INSTALLDIR" Guid="F1A2B3C4-D5E6-7890-ABCD-EF1234567890"
Condition="APP_DIR &lt;&gt; &quot;&quot;">
<File Id="BootstrapMateGuiExe" Source="$(var.APP_DIR)\BootstrapMate.exe" Vital="yes" />
</Component>
<!-- GUI Application files (BootstrapMate.exe + WinUI 3 dependencies) are
harvested from $(var.APP_DIR) into the GuiAppFiles ComponentGroup by
the Generate-GuiAppFiles.ps1 pre-build target in the wixproj. -->

<!-- Registry entries for installation tracking AND detection -->
<Component Id="RegistryEntries" Directory="INSTALLDIR" Guid="E5F6A7B8-C9D0-1234-EF56-789012345ABC">
Expand Down Expand Up @@ -79,7 +77,7 @@
<!-- Feature Definition -->
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="BootstrapMateExecutable" />
<ComponentRef Id="BootstrapMateGuiApp" />
<ComponentGroupRef Id="GuiAppFiles" />
<ComponentRef Id="RegistryEntries" />
<ComponentRef Id="SetPathComponent" />
</Feature>
Expand Down
Loading