leftovers Reviewed-on: #5 Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
This commit was merged in pull request #5.
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Builds the CursorLang installer for handing the application round outside
|
||||
the Store.
|
||||
|
||||
.DESCRIPTION
|
||||
Nothing has to be installed beyond the .NET SDK: WiX arrives as a NuGet
|
||||
package, the same way makeappx does for the MSIX build.
|
||||
|
||||
Nobody signs the result, so Windows warns about an unknown publisher and the
|
||||
user has to insist. Short of a certificate from a trusted authority there is
|
||||
no way round that, and it is the reason this installer is meant for people who
|
||||
already know where the file came from.
|
||||
|
||||
The application is published with its own copy of .NET: Windows carries no
|
||||
runtime of its own, and a self-contained build is tied to x64.
|
||||
|
||||
.PARAMETER Install
|
||||
Runs the installer once it is built, to see the thing through the way a user
|
||||
would.
|
||||
|
||||
.EXAMPLE
|
||||
# Build and run it, to see what a user sees
|
||||
pwsh -File Packaging\build-installer.ps1 -Install
|
||||
|
||||
.EXAMPLE
|
||||
# What a release needs
|
||||
pwsh -File Packaging\build-installer.ps1 -Version 1.0.1
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
# Three numbers: unlike the Store, an installer keeps no place for a fourth
|
||||
[string] $Version = '1.0.0',
|
||||
|
||||
[switch] $Install,
|
||||
|
||||
[string] $OutputPath
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = $PSScriptRoot
|
||||
$repository = Split-Path -Parent $root
|
||||
$agentProject = Join-Path $repository 'CursorLang.Agent\CursorLang.Agent.csproj'
|
||||
$settingsProject = Join-Path $repository 'CursorLang.Settings\CursorLang.Settings.csproj'
|
||||
$installerProject = Join-Path $root 'Installer\CursorLang.wixproj'
|
||||
$icon = Join-Path $repository 'CursorLang.Core\Resources\CursorLang.ico'
|
||||
$license = Join-Path $repository 'LICENSE'
|
||||
|
||||
if (-not $OutputPath) { $OutputPath = Join-Path $repository 'artifacts' }
|
||||
$stagingRoot = Join-Path $OutputPath 'installer-staging'
|
||||
$installersPath = Join-Path $OutputPath 'installers'
|
||||
|
||||
if ($Version -notmatch '^\d+\.\d+\.\d+$') {
|
||||
throw "The version '$Version' does not fit: an installer is versioned by three numbers, for example 1.0.0."
|
||||
}
|
||||
|
||||
if (-not (Test-Path $icon)) {
|
||||
throw "The icon is missing from '$icon'. Git LFS may have left a pointer in its place: run git lfs pull."
|
||||
}
|
||||
|
||||
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 Write-LicenseRtf {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Turns the plain-text LICENSE into the RTF the wizard needs.
|
||||
.DESCRIPTION
|
||||
The licence page of a Windows Installer wizard reads RTF and nothing
|
||||
else, and keeping a second copy of the licence in the repository would
|
||||
mean keeping the two in step by hand. The conversion is as plain as it
|
||||
looks: the text carries no formatting to preserve.
|
||||
#>
|
||||
param([string] $Path)
|
||||
|
||||
$text = (Get-Content $license -Raw) -replace '\\', '\\\\' -replace '{', '\{' -replace '}', '\}'
|
||||
$body = ($text -split "`r?`n") -join '\par' + "`r`n"
|
||||
|
||||
Set-Content -Path $Path -Value "{\rtf1\ansi\deff0{\fonttbl{\f0 Segoe UI;}}\fs18 $body}" -Encoding ASCII
|
||||
}
|
||||
|
||||
Remove-Item $stagingRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Path $installersPath -Force | Out-Null
|
||||
|
||||
$licenseRtf = Join-Path $stagingRoot 'License.rtf'
|
||||
New-Item -ItemType Directory -Path $stagingRoot -Force | Out-Null
|
||||
Write-LicenseRtf -Path $licenseRtf
|
||||
|
||||
Write-Host 'Building...' -ForegroundColor Cyan
|
||||
|
||||
$staging = Join-Path $stagingRoot 'x64'
|
||||
|
||||
# Both halves go into one folder: each of them looks for the other beside
|
||||
# itself — the tray menu opens the settings window, and the settings window
|
||||
# registers the agent for startup
|
||||
foreach ($half in @($agentProject, $settingsProject)) {
|
||||
Invoke-Tool -Path 'dotnet' -Arguments @(
|
||||
'publish', $half,
|
||||
'--configuration', 'Release',
|
||||
'--runtime', 'win-x64',
|
||||
'--self-contained', 'true',
|
||||
"-p:Version=$Version",
|
||||
'--output', $staging,
|
||||
'--nologo'
|
||||
)
|
||||
}
|
||||
|
||||
# Debug symbols only make the download bigger; they are of no use to anyone
|
||||
# who installs the application
|
||||
Get-ChildItem $staging -Recurse -Filter '*.pdb' | Remove-Item -Force
|
||||
|
||||
$installer = Join-Path $installersPath "CursorLang-$Version-x64.msi"
|
||||
|
||||
Invoke-Tool -Path 'dotnet' -Arguments @(
|
||||
'build', $installerProject,
|
||||
'--configuration', 'Release',
|
||||
# The architecture of the package is the architecture of what goes in it:
|
||||
# a self-contained build fits nothing else
|
||||
'-p:InstallerPlatform=x64',
|
||||
# Handed over one by one rather than as a ready list of constants: a
|
||||
# semicolon in a property value is where MSBuild stops reading it. The
|
||||
# project gathers them into DefineConstants itself
|
||||
"-p:CursorLangVersion=$Version",
|
||||
"-p:PayloadDir=$staging",
|
||||
"-p:IconFile=$icon",
|
||||
"-p:LicenseFile=$licenseRtf",
|
||||
"-p:OutputPath=$installersPath\",
|
||||
"-p:OutputName=CursorLang-$Version-x64",
|
||||
'--nologo'
|
||||
)
|
||||
|
||||
if ($Install) {
|
||||
Write-Host "Running $([System.IO.Path]::GetFileName($installer))..." -ForegroundColor Cyan
|
||||
|
||||
# Started the way a user would, with the wizard showing: the point of -Install
|
||||
# is to see what the person on the other end sees
|
||||
Start-Process 'msiexec.exe' -ArgumentList '/i', "`"$installer`"" -Wait
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host 'Done.' -ForegroundColor Green
|
||||
Write-Host " $installer"
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ' Nobody signed it, so Windows warns about an unknown publisher.'
|
||||
Reference in New Issue
Block a user