Skip to content

Commit e3fd7d9

Browse files
authored
added windows app sdk fetching and bundling into the installer (#66)
Closes #61
1 parent da29411 commit e3fd7d9

File tree

4 files changed

+69
-8
lines changed

4 files changed

+69
-8
lines changed

Installer/Program.cs

+29-8
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ public class BootstrapperOptions : SharedOptions
116116
[Option('m', "msi-path", Required = true, HelpText = "Path to the MSI package to embed")]
117117
public string MsiPath { get; set; }
118118

119+
[Option('w', "windows-app-sdk-path", Required = true, HelpText = "Path to the Windows App Sdk package to embed")]
120+
public string WindowsAppSdkPath { get; set; }
121+
119122
public new void Validate()
120123
{
121124
base.Validate();
@@ -124,6 +127,8 @@ public class BootstrapperOptions : SharedOptions
124127
throw new ArgumentException($"Logo PNG file not found at '{LogoPng}'", nameof(LogoPng));
125128
if (!SystemFile.Exists(MsiPath))
126129
throw new ArgumentException($"MSI package not found at '{MsiPath}'", nameof(MsiPath));
130+
if (!SystemFile.Exists(WindowsAppSdkPath))
131+
throw new ArgumentException($"Windows App Sdk package not found at '{WindowsAppSdkPath}'", nameof(WindowsAppSdkPath));
127132
}
128133
}
129134

@@ -337,16 +342,11 @@ private static int BuildBundle(BootstrapperOptions opts)
337342
{
338343
opts.Validate();
339344

340-
if (!DotNetRuntimePackagePayloads.TryGetValue(opts.Platform, out var payload))
345+
if (!DotNetRuntimePackagePayloads.TryGetValue(opts.Platform, out var dotNetRuntimePayload))
341346
throw new ArgumentException($"Invalid architecture '{opts.Platform}' specified", nameof(opts.Platform));
342347

343-
// TODO: it would be nice to include the WindowsAppRuntime but
344-
// Microsoft makes it difficult to check from a regular
345-
// installer:
346-
// https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/check-windows-app-sdk-versions
347-
// https://github.com/microsoft/WindowsAppSDK/discussions/2437
348348
var bundle = new Bundle(ProductName,
349-
new ExePackage
349+
new ExePackage // .NET Runtime
350350
{
351351
PerMachine = true,
352352
// Don't uninstall the runtime when the bundle is uninstalled.
@@ -362,7 +362,28 @@ private static int BuildBundle(BootstrapperOptions opts)
362362
// anyway. The MSI will fatally exit if the runtime really isn't
363363
// available, and the user can install it themselves.
364364
Vital = false,
365-
Payloads = [payload],
365+
Payloads = [dotNetRuntimePayload],
366+
},
367+
// TODO: right now we are including the Windows App Sdk in the bundle
368+
// and always install it
369+
// Microsoft makes it difficult to check if it exists from a regular installer:
370+
// https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/check-windows-app-sdk-versions
371+
// https://github.com/microsoft/WindowsAppSDK/discussions/2437
372+
new ExePackage // Windows App Sdk
373+
{
374+
PerMachine = true,
375+
Permanent = true,
376+
Cache = PackageCacheAction.remove,
377+
// There is no license agreement for this SDK.
378+
InstallArguments = "--quiet",
379+
Vital = false,
380+
Payloads =
381+
[
382+
new ExePackagePayload
383+
{
384+
SourceFile = opts.WindowsAppSdkPath
385+
}
386+
],
366387
},
367388
new MsiPackage(opts.MsiPath)
368389
{

scripts/Get-WindowsAppSdk.ps1

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Usage: Get-WindowsAppSdk.ps1 -arch <x64|arm64>
2+
param (
3+
[ValidateSet("x64", "arm64")]
4+
[Parameter(Mandatory = $true)]
5+
[string] $arch
6+
)
7+
8+
function Download-File([string] $url, [string] $outputPath, [string] $etagFile) {
9+
Write-Host "Downloading '$url' to '$outputPath'"
10+
# We use `curl.exe` here because `Invoke-WebRequest` is notoriously slow.
11+
& curl.exe `
12+
--progress-bar `
13+
-v `
14+
--show-error `
15+
--fail `
16+
--location `
17+
--etag-compare $etagFile `
18+
--etag-save $etagFile `
19+
--output $outputPath `
20+
$url
21+
if ($LASTEXITCODE -ne 0) { throw "Failed to download $url" }
22+
if (!(Test-Path $outputPath) -or (Get-Item $outputPath).Length -eq 0) {
23+
throw "Failed to download '$url', output file '$outputPath' is missing or empty"
24+
}
25+
}
26+
27+
# Download the Windows App Sdk binary from Microsoft for this platform if we don't have
28+
# it yet (or it's different).
29+
$windowsAppSdkMajorVersion = "1.6"
30+
$windowsAppSdkFullVersion = "1.6.250228001"
31+
$windowsAppSdkPath = Join-Path $PSScriptRoot "files\windows-app-sdk-$($arch).exe"
32+
$windowsAppSdkUri = "https://aka.ms/windowsappsdk/$($windowsAppSdkMajorVersion)/$($windowsAppSdkFullVersion)/windowsappruntimeinstall-$($arch).exe"
33+
$windowsAppSdkEtagFile = $windowsAppSdkPath + ".etag"
34+
Download-File $windowsAppSdkUri $windowsAppSdkPath $windowsAppSdkEtagFile

scripts/Publish.ps1

+5
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ Copy-Item $mutagenAgentsSrcPath $mutagenAgentsDestPath
175175
if ($LASTEXITCODE -ne 0) { throw "Failed to build MSI" }
176176
Add-CoderSignature $msiOutputPath
177177

178+
$getWindowsAppSdk = Join-Path $scriptRoot "Get-WindowsAppSdk.ps1"
179+
& $getWindowsAppSdk -arch $arch
180+
$windowsAppSdkPath = Join-Path $scriptRoot "files\windows-app-sdk-$($arch).exe"
181+
178182
# Build the bootstrapper
179183
& dotnet.exe run --project .\Installer\Installer.csproj -c Release -- `
180184
build-bootstrapper `
@@ -184,6 +188,7 @@ Add-CoderSignature $msiOutputPath
184188
--output-path $outputPath `
185189
--icon-file "App\coder.ico" `
186190
--msi-path $msiOutputPath `
191+
--windows-app-sdk-path $windowsAppSdkPath `
187192
--logo-png "scripts\files\logo.png"
188193
if ($LASTEXITCODE -ne 0) { throw "Failed to build bootstrapper" }
189194

scripts/files/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
mutagen-*.tar.gz
22
mutagen-*.exe
33
*.etag
4+
windows-app-sdk-*.exe

0 commit comments

Comments
 (0)