bundle-windows.ps1

  1[CmdletBinding()]
  2Param(
  3    [Parameter()][Alias('i')][switch]$Install,
  4    [Parameter()][Alias('h')][switch]$Help,
  5    [Parameter()][Alias('a')][string]$Architecture,
  6    [Parameter()][string]$Name
  7)
  8
  9. "$PSScriptRoot/lib/blob-store.ps1"
 10. "$PSScriptRoot/lib/workspace.ps1"
 11
 12# https://stackoverflow.com/questions/57949031/powershell-script-stops-if-program-fails-like-bash-set-o-errexit
 13$ErrorActionPreference = 'Stop'
 14$PSNativeCommandUseErrorActionPreference = $true
 15
 16$buildSuccess = $false
 17
 18$OSArchitecture = switch ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) {
 19    "X64" { "x86_64" }
 20    "Arm64" { "aarch64" }
 21    default { throw "Unsupported architecture" }
 22}
 23
 24$Architecture = if ($Architecture) {
 25    $Architecture
 26} else {
 27    $OSArchitecture
 28}
 29
 30$CargoOutDir = "./target/$Architecture-pc-windows-msvc/release"
 31
 32function Get-VSArch {
 33    param(
 34        [string]$Arch
 35    )
 36
 37    switch ($Arch) {
 38        "x86_64" { "amd64" }
 39        "aarch64" { "arm64" }
 40    }
 41}
 42
 43Push-Location
 44& "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Launch-VsDevShell.ps1" -Arch (Get-VSArch -Arch $Architecture) -HostArch (Get-VSArch -Arch $OSArchitecture)
 45Pop-Location
 46
 47$target = "$Architecture-pc-windows-msvc"
 48
 49if ($Help) {
 50    Write-Output "Usage: test.ps1 [-Install] [-Help]"
 51    Write-Output "Build the installer for Windows.\n"
 52    Write-Output "Options:"
 53    Write-Output "  -Architecture, -a Which architecture to build (x86_64 or aarch64)"
 54    Write-Output "  -Install, -i      Run the installer after building."
 55    Write-Output "  -Help, -h         Show this help message."
 56    exit 0
 57}
 58
 59Push-Location -Path crates/zed
 60$channel = Get-Content "RELEASE_CHANNEL"
 61$env:ZED_RELEASE_CHANNEL = $channel
 62$env:RELEASE_CHANNEL = $channel
 63Pop-Location
 64
 65function CheckEnvironmentVariables {
 66    if(-not $env:CI) {
 67        return
 68    }
 69
 70    $requiredVars = @(
 71        'ZED_WORKSPACE', 'RELEASE_VERSION', 'ZED_RELEASE_CHANNEL',
 72        'AZURE_TENANT_ID', 'AZURE_CLIENT_ID', 'AZURE_CLIENT_SECRET',
 73        'ACCOUNT_NAME', 'CERT_PROFILE_NAME', 'ENDPOINT',
 74        'FILE_DIGEST', 'TIMESTAMP_DIGEST', 'TIMESTAMP_SERVER'
 75    )
 76
 77    foreach ($var in $requiredVars) {
 78        if (-not (Test-Path "env:$var")) {
 79            Write-Error "$var is not set"
 80            exit 1
 81        }
 82    }
 83}
 84
 85function PrepareForBundle {
 86    if (Test-Path "$innoDir") {
 87        Remove-Item -Path "$innoDir" -Recurse -Force
 88    }
 89    New-Item -Path "$innoDir" -ItemType Directory -Force
 90    Copy-Item -Path "$env:ZED_WORKSPACE\crates\zed\resources\windows\*" -Destination "$innoDir" -Recurse -Force
 91    New-Item -Path "$innoDir\make_appx" -ItemType Directory -Force
 92    New-Item -Path "$innoDir\appx" -ItemType Directory -Force
 93    New-Item -Path "$innoDir\bin" -ItemType Directory -Force
 94    New-Item -Path "$innoDir\tools" -ItemType Directory -Force
 95
 96    rustup target add $target
 97}
 98
 99function GenerateLicenses {
100    $oldErrorActionPreference = $ErrorActionPreference
101    $ErrorActionPreference = 'Continue'
102    . $PSScriptRoot/generate-licenses.ps1
103    $ErrorActionPreference = $oldErrorActionPreference
104}
105
106function BuildZedAndItsFriends {
107    Write-Output "Building Zed and its friends, for channel: $channel"
108    # Build zed.exe, cli.exe and auto_update_helper.exe
109    cargo build --release --package zed --package cli --package auto_update_helper --target $target
110    Copy-Item -Path ".\$CargoOutDir\zed.exe" -Destination "$innoDir\Zed.exe" -Force
111    Copy-Item -Path ".\$CargoOutDir\cli.exe" -Destination "$innoDir\cli.exe" -Force
112    Copy-Item -Path ".\$CargoOutDir\auto_update_helper.exe" -Destination "$innoDir\auto_update_helper.exe" -Force
113    # Build explorer_command_injector.dll
114    switch ($channel) {
115        "stable" {
116            cargo build --release --features stable --no-default-features --package explorer_command_injector --target $target
117        }
118        "preview" {
119            cargo build --release --features preview --no-default-features --package explorer_command_injector --target $target
120        }
121        default {
122            cargo build --release --package explorer_command_injector --target $target
123        }
124    }
125    Copy-Item -Path ".\$CargoOutDir\explorer_command_injector.dll" -Destination "$innoDir\zed_explorer_command_injector.dll" -Force
126}
127
128function ZipZedAndItsFriendsDebug {
129    $items = @(
130        ".\$CargoOutDir\zed.pdb",
131        ".\$CargoOutDir\cli.pdb",
132        ".\$CargoOutDir\auto_update_helper.pdb",
133        ".\$CargoOutDir\explorer_command_injector.pdb"
134    )
135
136    Compress-Archive -Path $items -DestinationPath ".\$CargoOutDir\zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip" -Force
137}
138
139
140function UploadToSentry {
141    if (-not (Get-Command "sentry-cli" -ErrorAction SilentlyContinue)) {
142        Write-Output "sentry-cli not found. skipping sentry upload."
143        Write-Output "install with: 'winget install -e --id=Sentry.sentry-cli'"
144        return
145    }
146    if (-not (Test-Path "env:SENTRY_AUTH_TOKEN")) {
147        Write-Output "missing SENTRY_AUTH_TOKEN. skipping sentry upload."
148        return
149    }
150    Write-Output "Uploading zed debug symbols to sentry..."
151    sentry-cli debug-files upload --include-sources --wait -p zed -o zed-dev $CargoOutDir
152}
153
154function MakeAppx {
155    switch ($channel) {
156        "stable" {
157            $manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest.xml"
158        }
159        "preview" {
160            $manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest-Preview.xml"
161        }
162        default {
163            $manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest-Nightly.xml"
164        }
165    }
166    Copy-Item -Path "$manifestFile" -Destination "$innoDir\make_appx\AppxManifest.xml"
167    # Add makeAppx.exe to Path
168    $sdk = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
169    $env:Path += ';' + $sdk
170    makeAppx.exe pack /d "$innoDir\make_appx" /p "$innoDir\zed_explorer_command_injector.appx" /nv
171}
172
173function SignZedAndItsFriends {
174    if (-not $env:CI) {
175        return
176    }
177
178    $files = "$innoDir\Zed.exe,$innoDir\cli.exe,$innoDir\auto_update_helper.exe,$innoDir\zed_explorer_command_injector.dll,$innoDir\zed_explorer_command_injector.appx"
179    & "$innoDir\sign.ps1" $files
180}
181
182function DownloadAMDGpuServices {
183    # If you update the AGS SDK version, please also update the version in `crates/gpui/src/platform/windows/directx_renderer.rs`
184    $url = "https://codeload.github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/zip/refs/tags/v6.3.0"
185    $zipPath = ".\AGS_SDK_v6.3.0.zip"
186    # Download the AGS SDK zip file
187    Invoke-WebRequest -Uri $url -OutFile $zipPath
188    # Extract the AGS SDK zip file
189    Expand-Archive -Path $zipPath -DestinationPath "." -Force
190}
191
192function DownloadConpty {
193    $url = "https://www.nuget.org/api/v2/package/CI.Microsoft.Windows.Console.ConPTY/1.22.250314001"
194    $zipPath = ".\conpty.zip"
195    Invoke-WebRequest -Uri $url -OutFile $zipPath
196    Expand-Archive -Path $zipPath -DestinationPath ".\conpty" -Force
197}
198
199function CollectFiles {
200    Move-Item -Path "$innoDir\zed_explorer_command_injector.appx" -Destination "$innoDir\appx\zed_explorer_command_injector.appx" -Force
201    Move-Item -Path "$innoDir\zed_explorer_command_injector.dll" -Destination "$innoDir\appx\zed_explorer_command_injector.dll" -Force
202    Move-Item -Path "$innoDir\cli.exe" -Destination "$innoDir\bin\zed.exe" -Force
203    Move-Item -Path "$innoDir\zed.sh" -Destination "$innoDir\bin\zed" -Force
204    Move-Item -Path "$innoDir\auto_update_helper.exe" -Destination "$innoDir\tools\auto_update_helper.exe" -Force
205    Move-Item -Path ".\AGS_SDK-6.3.0\ags_lib\lib\amd_ags_x64.dll" -Destination "$innoDir\amd_ags_x64.dll" -Force
206    Move-Item -Path ".\conpty\build\native\runtimes\x64\OpenConsole.exe" -Destination "$innoDir\OpenConsole.exe" -Force
207    Move-Item -Path ".\conpty\runtimes\win10-x64\native\conpty.dll" -Destination "$innoDir\conpty.dll" -Force
208}
209
210function BuildInstaller {
211    $issFilePath = "$innoDir\zed.iss"
212    switch ($channel) {
213        "stable" {
214            $appId = "{{2DB0DA96-CA55-49BB-AF4F-64AF36A86712}"
215            $appIconName = "app-icon"
216            $appName = "Zed"
217            $appDisplayName = "Zed"
218            $appSetupName = "Zed-$Architecture"
219            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
220            $appMutex = "Zed-Stable-Instance-Mutex"
221            $appExeName = "Zed"
222            $regValueName = "Zed"
223            $appUserId = "ZedIndustries.Zed"
224            $appShellNameShort = "Z&ed"
225            $appAppxFullName = "ZedIndustries.Zed_1.0.0.0_neutral__japxn1gcva8rg"
226        }
227        "preview" {
228            $appId = "{{F70E4811-D0E2-4D88-AC99-D63752799F95}"
229            $appIconName = "app-icon-preview"
230            $appName = "Zed Preview"
231            $appDisplayName = "Zed Preview"
232            $appSetupName = "Zed-$Architecture"
233            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
234            $appMutex = "Zed-Preview-Instance-Mutex"
235            $appExeName = "Zed"
236            $regValueName = "ZedPreview"
237            $appUserId = "ZedIndustries.Zed.Preview"
238            $appShellNameShort = "Z&ed Preview"
239            $appAppxFullName = "ZedIndustries.Zed.Preview_1.0.0.0_neutral__japxn1gcva8rg"
240        }
241        "nightly" {
242            $appId = "{{1BDB21D3-14E7-433C-843C-9C97382B2FE0}"
243            $appIconName = "app-icon-nightly"
244            $appName = "Zed Nightly"
245            $appDisplayName = "Zed Nightly"
246            $appSetupName = "Zed-$Architecture"
247            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
248            $appMutex = "Zed-Nightly-Instance-Mutex"
249            $appExeName = "Zed"
250            $regValueName = "ZedNightly"
251            $appUserId = "ZedIndustries.Zed.Nightly"
252            $appShellNameShort = "Z&ed Editor Nightly"
253            $appAppxFullName = "ZedIndustries.Zed.Nightly_1.0.0.0_neutral__japxn1gcva8rg"
254        }
255        "dev" {
256            $appId = "{{8357632E-24A4-4F32-BA97-E575B4D1FE5D}"
257            $appIconName = "app-icon-dev"
258            $appName = "Zed Dev"
259            $appDisplayName = "Zed Dev"
260            $appSetupName = "Zed-$Architecture"
261            # The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
262            $appMutex = "Zed-Dev-Instance-Mutex"
263            $appExeName = "Zed"
264            $regValueName = "ZedDev"
265            $appUserId = "ZedIndustries.Zed.Dev"
266            $appShellNameShort = "Z&ed Dev"
267            $appAppxFullName = "ZedIndustries.Zed.Dev_1.0.0.0_neutral__japxn1gcva8rg"
268        }
269        default {
270            Write-Error "can't bundle installer for $channel."
271            exit 1
272        }
273    }
274
275    # Windows runner 2022 default has iscc in PATH, https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
276    # Currently, we are using Windows 2022 runner.
277    # Windows runner 2025 doesn't have iscc in PATH for now, https://github.com/actions/runner-images/issues/11228
278    $innoSetupPath = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
279
280    $definitions = @{
281        "AppId"          = $appId
282        "AppIconName"    = $appIconName
283        "OutputDir"      = "$env:ZED_WORKSPACE\target"
284        "AppSetupName"   = $appSetupName
285        "AppName"        = $appName
286        "AppDisplayName" = $appDisplayName
287        "RegValueName"   = $regValueName
288        "AppMutex"       = $appMutex
289        "AppExeName"     = $appExeName
290        "ResourcesDir"   = "$innoDir"
291        "ShellNameShort" = $appShellNameShort
292        "AppUserId"      = $appUserId
293        "Version"        = "$env:RELEASE_VERSION"
294        "SourceDir"      = "$env:ZED_WORKSPACE"
295        "AppxFullName"   = $appAppxFullName
296    }
297
298    $defs = @()
299    foreach ($key in $definitions.Keys) {
300        $defs += "/d$key=`"$($definitions[$key])`""
301    }
302
303    $innoArgs = @($issFilePath) + $defs
304    if($env:CI) {
305        $signTool = "powershell.exe -ExecutionPolicy Bypass -File $innoDir\sign.ps1 `$f"
306        $innoArgs += "/sDefaultsign=`"$signTool`""
307    }
308
309    # Execute Inno Setup
310    Write-Host "🚀 Running Inno Setup: $innoSetupPath $innoArgs"
311    $process = Start-Process -FilePath $innoSetupPath -ArgumentList $innoArgs -NoNewWindow -Wait -PassThru
312
313    if ($process.ExitCode -eq 0) {
314        Write-Host "✅ Inno Setup successfully compiled the installer"
315        Write-Output "SETUP_PATH=target/$appSetupName.exe" >> $env:GITHUB_ENV
316        $script:buildSuccess = $true
317    }
318    else {
319        Write-Host "❌ Inno Setup failed: $($process.ExitCode)"
320        $script:buildSuccess = $false
321    }
322}
323
324ParseZedWorkspace
325$innoDir = "$env:ZED_WORKSPACE\inno"
326$debugArchive = "$CargoOutDir\zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip"
327$debugStoreKey = "$env:ZED_RELEASE_CHANNEL/zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip"
328
329CheckEnvironmentVariables
330PrepareForBundle
331GenerateLicenses
332BuildZedAndItsFriends
333MakeAppx
334SignZedAndItsFriends
335ZipZedAndItsFriendsDebug
336DownloadAMDGpuServices
337DownloadConpty
338CollectFiles
339BuildInstaller
340
341if($env:CI) {
342    UploadToBlobStorePublic -BucketName "zed-debug-symbols" -FileToUpload $debugArchive -BlobStoreKey $debugStoreKey
343    UploadToSentry
344}
345
346if ($buildSuccess) {
347    Write-Output "Build successful"
348    if ($Install) {
349        Write-Output "Installing Zed..."
350        Start-Process -FilePath "$env:ZED_WORKSPACE/target/ZedEditorUserSetup-x64-$env:RELEASE_VERSION.exe"
351    }
352    exit 0
353}
354else {
355    Write-Output "Build failed"
356    exit 1
357}