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