added packaging
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Builds the CursorLang MSIX package for the Microsoft Store.
|
||||
|
||||
.DESCRIPTION
|
||||
Neither Visual Studio nor the Windows SDK is needed: makeappx arrives as a
|
||||
NuGet package (Tools\SdkTools.csproj) and the application is built by the
|
||||
plain .NET SDK.
|
||||
|
||||
The package is handed to Partner Center as it comes out of here — the Store
|
||||
is where it gets everything else done to it.
|
||||
|
||||
The application is published with its own copy of .NET: Windows does not
|
||||
carry one, and MSIX cannot install the runtime as a package dependency.
|
||||
|
||||
.PARAMETER IdentityName
|
||||
The identity of the package — from Partner Center, the "Product identity"
|
||||
section. It is handed out there together with the reserved application name;
|
||||
the default is only good enough for a check on your own machine.
|
||||
|
||||
.EXAMPLE
|
||||
# A check on your own machine: your architecture alone
|
||||
pwsh -File Packaging\build-msix.ps1 -Architectures x64
|
||||
|
||||
.EXAMPLE
|
||||
# A build for the Store — the identity comes from Partner Center
|
||||
pwsh -File Packaging\build-msix.ps1 -Version 1.0.1.0 `
|
||||
-IdentityName 12345AleksandrNeychev.CursorLang -Publisher "CN=ABCD1234-..."
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
# Four numbers, the last one has to be 0: that is what the Store requires
|
||||
[string] $Version = '1.0.0.0',
|
||||
|
||||
[string] $IdentityName = 'CursorLang',
|
||||
[string] $Publisher = 'CN=Aleksandr Neychev',
|
||||
[string] $PublisherDisplayName = 'Aleksandr Neychev',
|
||||
|
||||
[ValidateSet('x64', 'arm64')]
|
||||
[string[]] $Architectures = @('x64', 'arm64'),
|
||||
|
||||
[string] $OutputPath
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = $PSScriptRoot
|
||||
$repository = Split-Path -Parent $root
|
||||
$project = Join-Path $repository 'CursorLang\CursorLang.csproj'
|
||||
$assets = Join-Path $root 'Assets'
|
||||
$manifestTemplate = Join-Path $root 'AppxManifest.xml'
|
||||
$toolsProject = Join-Path $root 'Tools\SdkTools.csproj'
|
||||
|
||||
if (-not $OutputPath) { $OutputPath = Join-Path $repository 'artifacts' }
|
||||
$layoutRoot = Join-Path $OutputPath 'layout'
|
||||
$packagesPath = Join-Path $OutputPath 'packages'
|
||||
|
||||
if ($Version -notmatch '^\d+\.\d+\.\d+\.0$') {
|
||||
throw "The version '$Version' does not fit: the Store takes four numbers ending in zero, for example 1.0.0.0."
|
||||
}
|
||||
|
||||
if (-not (Test-Path $assets)) {
|
||||
throw "No logos found in '$assets'. Run Packaging\New-Assets.ps1 first."
|
||||
}
|
||||
|
||||
function Invoke-Tool {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Runs a program and fails the build if it returned an error.
|
||||
.DESCRIPTION
|
||||
A wrapper of our own is needed because PowerShell does not treat the
|
||||
failure of an external program as an error and quietly moves on.
|
||||
#>
|
||||
param(
|
||||
[string] $Path,
|
||||
[string[]] $Arguments
|
||||
)
|
||||
|
||||
& $Path @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "'$([System.IO.Path]::GetFileName($Path))' exited with code $LASTEXITCODE."
|
||||
}
|
||||
}
|
||||
|
||||
function Get-SdkToolsPath {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Returns the folder of the restored Windows SDK Build Tools package.
|
||||
.DESCRIPTION
|
||||
The path is asked of MSBuild rather than searched for in the package
|
||||
cache: the project pins one version of the package, and MSBuild
|
||||
names exactly it. A search would also find the versions left over
|
||||
from other builds.
|
||||
#>
|
||||
$path = (& dotnet msbuild $toolsProject -getProperty:PkgMicrosoft_Windows_SDK_BuildTools -nologo) |
|
||||
Where-Object { $_ -and $_.Trim() } |
|
||||
Select-Object -Last 1
|
||||
|
||||
if ($LASTEXITCODE -ne 0 -or -not $path -or -not (Test-Path $path.Trim())) {
|
||||
throw 'The Windows SDK Build Tools package folder could not be found. Did the restore go through?'
|
||||
}
|
||||
|
||||
return $path.Trim()
|
||||
}
|
||||
|
||||
function Get-SdkTool {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Returns the path of a program from the Windows SDK Build Tools package.
|
||||
#>
|
||||
param(
|
||||
[string] $Name,
|
||||
[string] $PackagePath
|
||||
)
|
||||
|
||||
# The bitness of the program has nothing to do with the bitness of the
|
||||
# package being built: we take the one that runs on this machine
|
||||
$host64 = if ([Environment]::Is64BitOperatingSystem) { 'x64' } else { 'x86' }
|
||||
|
||||
$tool = Get-ChildItem (Join-Path $PackagePath 'bin') -Recurse -Filter $Name -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.FullName -match "\\$host64\\" } |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $tool) {
|
||||
throw "'$Name' was not found in the Windows SDK Build Tools package."
|
||||
}
|
||||
|
||||
return $tool.FullName
|
||||
}
|
||||
|
||||
Write-Host 'Fetching the Windows SDK programs...' -ForegroundColor Cyan
|
||||
Invoke-Tool -Path 'dotnet' -Arguments @('restore', $toolsProject, '--nologo')
|
||||
|
||||
$sdkTools = Get-SdkToolsPath
|
||||
$makeappx = Get-SdkTool -Name 'makeappx.exe' -PackagePath $sdkTools
|
||||
|
||||
Remove-Item $layoutRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Path $packagesPath -Force | Out-Null
|
||||
|
||||
$built = @()
|
||||
|
||||
foreach ($architecture in $Architectures) {
|
||||
Write-Host "Building $architecture..." -ForegroundColor Cyan
|
||||
|
||||
$layout = Join-Path $layoutRoot $architecture
|
||||
|
||||
Invoke-Tool -Path 'dotnet' -Arguments @(
|
||||
'publish', $project,
|
||||
'--configuration', 'Release',
|
||||
'--runtime', "win-$architecture",
|
||||
'--self-contained', 'true',
|
||||
"-p:Version=$($Version.Substring(0, $Version.LastIndexOf('.')))",
|
||||
'--output', $layout,
|
||||
'--nologo'
|
||||
)
|
||||
|
||||
# Debug symbols have no place in the package: they take up room, the user
|
||||
# has no use for them, and for crash reports the Store takes them separately
|
||||
Get-ChildItem $layout -Recurse -Filter '*.pdb' | Remove-Item -Force
|
||||
|
||||
Copy-Item $assets -Destination (Join-Path $layout 'Assets') -Recurse -Force
|
||||
|
||||
$manifest = (Get-Content $manifestTemplate -Raw).
|
||||
Replace('{IdentityName}', $IdentityName).
|
||||
Replace('{Publisher}', $Publisher).
|
||||
Replace('{PublisherDisplayName}', $PublisherDisplayName).
|
||||
Replace('{Version}', $Version).
|
||||
Replace('{Architecture}', $architecture)
|
||||
|
||||
Set-Content -Path (Join-Path $layout 'AppxManifest.xml') -Value $manifest -Encoding UTF8
|
||||
|
||||
$package = Join-Path $packagesPath "CursorLang-$Version-$architecture.msix"
|
||||
Invoke-Tool -Path $makeappx -Arguments @('pack', '/o', '/d', $layout, '/p', $package)
|
||||
|
||||
$built += $package
|
||||
}
|
||||
|
||||
$result = $built[0]
|
||||
|
||||
if ($built.Count -gt 1) {
|
||||
Write-Host 'Bringing the architectures into one package...' -ForegroundColor Cyan
|
||||
|
||||
# makeappx bundle takes everything from a folder, so the separate packages
|
||||
# are gathered into one of their own first — otherwise the results of
|
||||
# earlier builds would end up in the bundle
|
||||
$bundleInput = Join-Path $OutputPath 'bundle'
|
||||
Remove-Item $bundleInput -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Path $bundleInput -Force | Out-Null
|
||||
$built | ForEach-Object { Copy-Item $_ -Destination $bundleInput }
|
||||
|
||||
$result = Join-Path $packagesPath "CursorLang-$Version.msixbundle"
|
||||
Invoke-Tool -Path $makeappx -Arguments @('bundle', '/o', '/d', $bundleInput, '/p', $result, '/bv', $Version)
|
||||
|
||||
Remove-Item $bundleInput -Recurse -Force
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host 'Done.' -ForegroundColor Green
|
||||
Write-Host " $result"
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ' This file is uploaded to Partner Center as it is.'
|
||||
Reference in New Issue
Block a user