added packaging
This commit is contained in:
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package
|
||||||
|
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||||
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
|
IgnorableNamespaces="uap desktop rescap">
|
||||||
|
|
||||||
|
<Identity
|
||||||
|
Name="{IdentityName}"
|
||||||
|
Publisher="{Publisher}"
|
||||||
|
Version="{Version}"
|
||||||
|
ProcessorArchitecture="{Architecture}"/>
|
||||||
|
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>CursorLang</DisplayName>
|
||||||
|
<PublisherDisplayName>{PublisherDisplayName}</PublisherDisplayName>
|
||||||
|
<Logo>Assets\StoreLogo.png</Logo>
|
||||||
|
</Properties>
|
||||||
|
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.26100.0"/>
|
||||||
|
</Dependencies>
|
||||||
|
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="en-us"/>
|
||||||
|
<Resource Language="ru-ru"/>
|
||||||
|
</Resources>
|
||||||
|
|
||||||
|
<Applications>
|
||||||
|
<Application Id="App" Executable="CursorLang.exe" EntryPoint="Windows.FullTrustApplication">
|
||||||
|
<uap:VisualElements
|
||||||
|
DisplayName="CursorLang"
|
||||||
|
Description="Shows the keyboard layout at the cursor"
|
||||||
|
BackgroundColor="transparent"
|
||||||
|
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||||
|
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||||
|
<uap:DefaultTile
|
||||||
|
Square71x71Logo="Assets\Square71x71Logo.png"
|
||||||
|
Square310x310Logo="Assets\Square310x310Logo.png"
|
||||||
|
Wide310x150Logo="Assets\Wide310x150Logo.png"/>
|
||||||
|
</uap:VisualElements>
|
||||||
|
|
||||||
|
<Extensions>
|
||||||
|
<desktop:Extension Category="windows.startupTask" Executable="CursorLang.exe"
|
||||||
|
EntryPoint="Windows.FullTrustApplication">
|
||||||
|
<desktop:StartupTask TaskId="CursorLangStartup" Enabled="false" DisplayName="CursorLang"/>
|
||||||
|
</desktop:Extension>
|
||||||
|
</Extensions>
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
|
||||||
|
<Capabilities>
|
||||||
|
<rescap:Capability Name="runFullTrust"/>
|
||||||
|
</Capabilities>
|
||||||
|
|
||||||
|
</Package>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,232 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Draws the application icons: the logos for MSIX and the .ico for the exe.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
The icons are drawn by code rather than kept as pictures so that the whole
|
||||||
|
set of sizes is rebuilt by a single command whenever another drawing is
|
||||||
|
wanted.
|
||||||
|
|
||||||
|
The current drawing is a placeholder: a dark rounded square with a white
|
||||||
|
"Aя". Before publishing to the Store it is worth replacing with a real one:
|
||||||
|
rewriting New-Logo is enough, the rest of the script does not depend on the
|
||||||
|
drawing.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
pwsh -File Packaging\New-Assets.ps1
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
# Where to put the MSIX logos
|
||||||
|
[string] $AssetsPath,
|
||||||
|
|
||||||
|
# Where to put the .ico for the exe
|
||||||
|
[string] $IconPath
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# The defaults are worked out here rather than in the parameter declarations:
|
||||||
|
# in Windows PowerShell $PSScriptRoot is still empty inside param()
|
||||||
|
$root = $PSScriptRoot
|
||||||
|
if (-not $AssetsPath) { $AssetsPath = Join-Path $root 'Assets' }
|
||||||
|
if (-not $IconPath) { $IconPath = Join-Path $root '..\CursorLang\Resources\CursorLang.ico' }
|
||||||
|
|
||||||
|
Add-Type -AssemblyName System.Drawing
|
||||||
|
|
||||||
|
$Background = [System.Drawing.Color]::FromArgb(255, 0x20, 0x20, 0x20)
|
||||||
|
$Foreground = [System.Drawing.Color]::FromArgb(255, 0xFF, 0xFF, 0xFF)
|
||||||
|
$Glyph = 'Aя'
|
||||||
|
|
||||||
|
function New-Logo {
|
||||||
|
param(
|
||||||
|
[int] $Width,
|
||||||
|
[int] $Height,
|
||||||
|
|
||||||
|
# The plate under the glyph. The Windows taskbar draws its shortcut
|
||||||
|
# without one, so for those sizes only the white glyph remains
|
||||||
|
[bool] $WithPlate = $true
|
||||||
|
)
|
||||||
|
|
||||||
|
$bitmap = New-Object System.Drawing.Bitmap($Width, $Height, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
||||||
|
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
||||||
|
$graphics.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAliasGridFit
|
||||||
|
$graphics.Clear([System.Drawing.Color]::Transparent)
|
||||||
|
|
||||||
|
$side = [Math]::Min($Width, $Height)
|
||||||
|
|
||||||
|
if ($WithPlate) {
|
||||||
|
# The corner radius is taken as a share of the side so that small
|
||||||
|
# sizes do not turn into a circle and large ones do not look like a
|
||||||
|
# plain square
|
||||||
|
$radius = [Math]::Max(2, [int]($side * 0.18))
|
||||||
|
$plate = New-Object System.Drawing.Drawing2D.GraphicsPath
|
||||||
|
|
||||||
|
$plate.AddArc(0, 0, $radius * 2, $radius * 2, 180, 90)
|
||||||
|
$plate.AddArc($Width - $radius * 2 - 1, 0, $radius * 2, $radius * 2, 270, 90)
|
||||||
|
$plate.AddArc($Width - $radius * 2 - 1, $Height - $radius * 2 - 1, $radius * 2, $radius * 2, 0, 90)
|
||||||
|
$plate.AddArc(0, $Height - $radius * 2 - 1, $radius * 2, $radius * 2, 90, 90)
|
||||||
|
$plate.CloseFigure()
|
||||||
|
|
||||||
|
$brush = New-Object System.Drawing.SolidBrush($Background)
|
||||||
|
try { $graphics.FillPath($brush, $plate) } finally { $brush.Dispose(); $plate.Dispose() }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Typographic metrics leave out the side bearings MeasureString reports by
|
||||||
|
# default. Measured with those bearings the glyph looks wider than it is,
|
||||||
|
# the fitted type comes out too small, and at 16 px the strokes wash out
|
||||||
|
[System.Drawing.StringFormat] $format = [System.Drawing.StringFormat]::GenericTypographic.Clone()
|
||||||
|
|
||||||
|
try {
|
||||||
|
# The type size is found by trying: with different tile sizes the same
|
||||||
|
# share of the side gives text that is either cramped or too small
|
||||||
|
$target = $side * 0.80
|
||||||
|
$ceiling = $side * 0.86
|
||||||
|
$fontSize = $side * 0.9
|
||||||
|
$font = $null
|
||||||
|
$measured = $null
|
||||||
|
|
||||||
|
for ($attempt = 0; $attempt -lt 20; $attempt++) {
|
||||||
|
if ($font) { $font.Dispose() }
|
||||||
|
$font = New-Object System.Drawing.Font('Segoe UI', $fontSize, [System.Drawing.FontStyle]::Bold, [System.Drawing.GraphicsUnit]::Pixel)
|
||||||
|
$measured = $graphics.MeasureString($Glyph, $font, ([System.Drawing.PointF]::new(0, 0)), $format)
|
||||||
|
|
||||||
|
if ($measured.Width -le $target -and $measured.Height -le $ceiling) { break }
|
||||||
|
|
||||||
|
# Both dimensions are pulled in at once, otherwise a tall glyph
|
||||||
|
# keeps overflowing while the width already fits
|
||||||
|
$scale = [Math]::Min($target / $measured.Width, $ceiling / $measured.Height)
|
||||||
|
$fontSize = $fontSize * $scale * 0.98
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
# AntiAliasGridFit snaps the stems onto the pixel grid, so the
|
||||||
|
# glyph is placed at a whole pixel: a fractional origin spreads
|
||||||
|
# every stem across two pixels, which is what blurred the small
|
||||||
|
# sizes when the text was centred inside a RectangleF
|
||||||
|
$x = [Math]::Round(($Width - $measured.Width) / 2.0)
|
||||||
|
$y = [Math]::Round(($Height - $measured.Height) / 2.0)
|
||||||
|
|
||||||
|
$brush = New-Object System.Drawing.SolidBrush($Foreground)
|
||||||
|
$origin = New-Object System.Drawing.PointF($x, $y)
|
||||||
|
|
||||||
|
try { $graphics.DrawString($Glyph, $font, $brush, $origin, $format) }
|
||||||
|
finally { $brush.Dispose() }
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$font.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$format.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$graphics.Dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
function Save-Logo {
|
||||||
|
param(
|
||||||
|
[string] $Path,
|
||||||
|
[int] $Width,
|
||||||
|
[int] $Height,
|
||||||
|
[bool] $WithPlate = $true
|
||||||
|
)
|
||||||
|
|
||||||
|
$bitmap = New-Logo -Width $Width -Height $Height -WithPlate $WithPlate
|
||||||
|
try { $bitmap.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png) } finally { $bitmap.Dispose() }
|
||||||
|
Write-Host " $([System.IO.Path]::GetFileName($Path))"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Save-Icon {
|
||||||
|
param(
|
||||||
|
[string] $Path,
|
||||||
|
[int[]] $Sizes
|
||||||
|
)
|
||||||
|
|
||||||
|
# The .ico is put together by hand: System.Drawing can only save a single
|
||||||
|
# size to that format, and the icon of the exe is needed in several at once
|
||||||
|
$images = @()
|
||||||
|
|
||||||
|
foreach ($size in $Sizes) {
|
||||||
|
$bitmap = New-Logo -Width $size -Height $size
|
||||||
|
try {
|
||||||
|
$stream = New-Object System.IO.MemoryStream
|
||||||
|
$bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||||
|
$images += , @{ Size = $size; Bytes = $stream.ToArray() }
|
||||||
|
$stream.Dispose()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$bitmap.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = New-Object System.IO.MemoryStream
|
||||||
|
$writer = New-Object System.IO.BinaryWriter($output)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$writer.Write([uint16]0) # reserved
|
||||||
|
$writer.Write([uint16]1) # type: icon
|
||||||
|
$writer.Write([uint16]$images.Count)
|
||||||
|
|
||||||
|
# The directory of entries comes before the pictures themselves, so the
|
||||||
|
# offsets are worked out beforehand: the header plus 16 bytes per entry
|
||||||
|
$offset = 6 + 16 * $images.Count
|
||||||
|
|
||||||
|
foreach ($image in $images) {
|
||||||
|
# 256 does not fit in a byte and is written as zero — the format
|
||||||
|
# means it that way
|
||||||
|
$dimension = if ($image.Size -ge 256) { 0 } else { $image.Size }
|
||||||
|
|
||||||
|
$writer.Write([byte]$dimension) # width
|
||||||
|
$writer.Write([byte]$dimension) # height
|
||||||
|
$writer.Write([byte]0) # palette colours: no palette
|
||||||
|
$writer.Write([byte]0) # reserved
|
||||||
|
$writer.Write([uint16]1) # planes
|
||||||
|
$writer.Write([uint16]32) # bits per pixel
|
||||||
|
$writer.Write([uint32]$image.Bytes.Length)
|
||||||
|
$writer.Write([uint32]$offset)
|
||||||
|
|
||||||
|
$offset += $image.Bytes.Length
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($image in $images) {
|
||||||
|
$writer.Write($image.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
$writer.Flush()
|
||||||
|
[System.IO.File]::WriteAllBytes($Path, $output.ToArray())
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$writer.Dispose()
|
||||||
|
$output.Dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host " $([System.IO.Path]::GetFileName($Path))"
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $AssetsPath -Force | Out-Null
|
||||||
|
New-Item -ItemType Directory -Path (Split-Path -Parent $IconPath) -Force | Out-Null
|
||||||
|
|
||||||
|
Write-Host 'MSIX logos:'
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'StoreLogo.png') -Width 50 -Height 50
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square44x44Logo.png') -Width 44 -Height 44
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square71x71Logo.png') -Width 71 -Height 71
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square150x150Logo.png') -Width 150 -Height 150
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square310x310Logo.png') -Width 310 -Height 310
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Wide310x150Logo.png') -Width 310 -Height 150
|
||||||
|
|
||||||
|
# The taskbar and the application list take the shortcut without a plate
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square44x44Logo.targetsize-24_altform-unplated.png') -Width 24 -Height 24 -WithPlate $false
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square44x44Logo.targetsize-32_altform-unplated.png') -Width 32 -Height 32 -WithPlate $false
|
||||||
|
Save-Logo -Path (Join-Path $AssetsPath 'Square44x44Logo.targetsize-48_altform-unplated.png') -Width 48 -Height 48 -WithPlate $false
|
||||||
|
|
||||||
|
Write-Host 'The exe icon:'
|
||||||
|
Save-Icon -Path ([System.IO.Path]::GetFullPath($IconPath)) -Sizes @(16, 24, 32, 48, 64, 128, 256)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<!--
|
||||||
|
The project exists for the sake of a single dependency: the package brings
|
||||||
|
makeappx.exe. That way the MSIX build gets by without an installed Windows SDK
|
||||||
|
and repeats itself on any machine that has the .NET SDK. The project is not
|
||||||
|
meant to be built — build-msix.ps1 restores it and takes the program from the
|
||||||
|
packages folder. It is kept out of the build in CursorLang.sln for the same
|
||||||
|
reason.
|
||||||
|
-->
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584">
|
||||||
|
<!-- Only the programs from the package are needed, there are no assemblies to reference -->
|
||||||
|
<ExcludeAssets>all</ExcludeAssets>
|
||||||
|
<GeneratePathProperty>true</GeneratePathProperty>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -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