-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
install.ps1
284 lines (246 loc) · 10.5 KB
/
install.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#!/usr/bin/env pwsh
param(
# TODO: change this to 'latest' when Bun for Windows is stable.
[String]$Version = "canary",
# Forces installing the baseline build regardless of what CPU you are actually using.
[Switch]$ForceBaseline = $false,
# Skips adding the bun.exe directory to the user's %PATH%
[Switch]$NoPathUpdate = $false,
# Skips adding the bun to the list of installed programs
[Switch]$NoRegisterInstallation = $false
);
# filter out 32 bit + ARM
if ($env:PROCESSOR_ARCHITECTURE -ne "AMD64") {
Write-Output "Install Failed:"
Write-Output "Bun for Windows is only available for x86 64-bit Windows.`n"
exit 1
}
# This corresponds to .win10_rs5 in build.zig
$MinBuild = 17763;
$MinBuildName = "Windows 10 1809"
$WinVer = [System.Environment]::OSVersion.Version
if ($WinVer.Major -lt 10 -or ($WinVer.Major -eq 10 -and $WinVer.Build -lt $MinBuild)) {
Write-Warning "Bun requires at ${MinBuildName} or newer.`n`nThe install will still continue but it may not work.`n"
exit 1
}
$ErrorActionPreference = "Stop"
# These three environment functions are roughly copied from https://github.com/prefix-dev/pixi/pull/692
# They are used instead of `SetEnvironmentVariable` because of unwanted variable expansions.
function Publish-Env {
if (-not ("Win32.NativeMethods" -as [Type])) {
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
"@
}
$HWND_BROADCAST = [IntPtr] 0xffff
$WM_SETTINGCHANGE = 0x1a
$result = [UIntPtr]::Zero
[Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST,
$WM_SETTINGCHANGE,
[UIntPtr]::Zero,
"Environment",
2,
5000,
[ref] $result
) | Out-Null
}
function Write-Env {
param([String]$Key, [String]$Value)
$RegisterKey = Get-Item -Path 'HKCU:'
$EnvRegisterKey = $RegisterKey.OpenSubKey('Environment', $true)
if ($null -eq $Value) {
$EnvRegisterKey.DeleteValue($Key)
} else {
$RegistryValueKind = if ($Value.Contains('%')) {
[Microsoft.Win32.RegistryValueKind]::ExpandString
} elseif ($EnvRegisterKey.GetValue($Key)) {
$EnvRegisterKey.GetValueKind($Key)
} else {
[Microsoft.Win32.RegistryValueKind]::String
}
$EnvRegisterKey.SetValue($Key, $Value, $RegistryValueKind)
}
Publish-Env
}
function Get-Env {
param([String] $Key)
$RegisterKey = Get-Item -Path 'HKCU:'
$EnvRegisterKey = $RegisterKey.OpenSubKey('Environment')
$EnvRegisterKey.GetValue($Key, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
}
# The installation of bun is it's own function so that in the unlikely case the $IsBaseline check fails, we can do a recursive call.
# There are also lots of sanity checks out of fear of anti-virus software or other weird Windows things happening.
function Install-Bun {
param(
[string]$Version,
[bool]$ForceBaseline = $False
);
# if a semver is given, we need to adjust it to this format: bun-v0.0.0
if ($Version -match "^\d+\.\d+\.\d+$") {
$Version = "bun-v$Version"
}
elseif ($Version -match "^v\d+\.\d+\.\d+$") {
$Version = "bun-$Version"
}
# todo: remove this when Bun for Windows is stable
elseif ($Version -eq "latest") {
$Version = "canary"
}
$Arch = "x64"
$IsBaseline = $ForceBaseline
if (!$IsBaseline) {
$IsBaseline = !( `
Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' `
-Name 'Kernel32' -Namespace 'Win32' -PassThru `
)::IsProcessorFeaturePresent(40);
}
$BunRoot = if ($env:BUN_INSTALL) { $env:BUN_INSTALL } else { "${Home}\.bun" }
$BunBin = mkdir -Force "${BunRoot}\bin"
try {
Remove-Item "${BunBin}\bun.exe" -Force
} catch [System.Management.Automation.ItemNotFoundException] {
# ignore
} catch [System.UnauthorizedAccessException] {
$openProcesses = Get-Process -Name bun | Where-Object { $_.Path -eq "${BunBin}\bun.exe" }
if ($openProcesses.Count -gt 0) {
Write-Output "Install Failed - An older installation exists and is open. Please close open Bun processes and try again."
exit 1
}
Write-Output "Install Failed - An unknown error occurred while trying to remove the existing installation"
Write-Output $_
exit 1
} catch {
Write-Output "Install Failed - An unknown error occurred while trying to remove the existing installation"
Write-Output $_
exit 1
}
$Target = "bun-windows-$Arch"
if ($IsBaseline) {
$Target = "bun-windows-$Arch-baseline"
}
$BaseURL = "https://github.com/oven-sh/bun/releases"
$URL = "$BaseURL/$(if ($Version -eq "latest") { "latest/download" } else { "download/$Version" })/$Target.zip"
$ZipPath = "${BunBin}\$Target.zip"
$DisplayVersion = $(
if ($Version -eq "latest") { "Bun" }
elseif ($Version -eq "canary") { "Bun Canary" }
elseif ($Version -match "^bun-v\d+\.\d+\.\d+$") { "Bun $($Version.Substring(4))" }
else { "Bun tag='${Version}'" }
)
$null = mkdir -Force $BunBin
Remove-Item -Force $ZipPath -ErrorAction SilentlyContinue
# curl.exe is faster than PowerShell 5's 'Invoke-WebRequest'
# note: 'curl' is an alias to 'Invoke-WebRequest'. so the exe suffix is required
curl.exe "-#SfLo" "$ZipPath" "$URL"
if ($LASTEXITCODE -ne 0) {
Write-Output "Install Failed - could not download $URL"
Write-Output "The command 'curl.exe $URL -o $ZipPath' exited with code ${LASTEXITCODE}`n"
exit 1
}
if (!(Test-Path $ZipPath)) {
Write-Output "Install Failed - could not download $URL"
Write-Output "The file '$ZipPath' does not exist. Did an antivirus delete it?`n"
exit 1
}
try {
$lastProgressPreference = $global:ProgressPreference
$global:ProgressPreference = 'SilentlyContinue';
Expand-Archive "$ZipPath" "$BunBin" -Force
$global:ProgressPreference = $lastProgressPreference
if (!(Test-Path "${BunBin}\$Target\bun.exe")) {
throw "The file '${BunBin}\$Target\bun.exe' does not exist. Download is corrupt or intercepted Antivirus?`n"
}
} catch {
Write-Output "Install Failed - could not unzip $ZipPath"
Write-Error $_
exit 1
}
Move-Item "${BunBin}\$Target\bun.exe" "${BunBin}\bun.exe" -Force
Remove-Item "${BunBin}\$Target" -Recurse -Force
Remove-Item $ZipPath -Force
$BunRevision = "$(& "${BunBin}\bun.exe" --revision)"
if ($LASTEXITCODE -eq 1073741795) { # STATUS_ILLEGAL_INSTRUCTION
if ($IsBaseline) {
Write-Output "Install Failed - bun.exe (baseline) is not compatible with your CPU.`n"
Write-Output "Please open a GitHub issue with your CPU model:`nhttps://github.com/oven-sh/bun/issues/new/choose`n"
exit 1
}
Write-Output "Install Failed - bun.exe is not compatible with your CPU. This should have been detected before downloading.`n"
Write-Output "Attempting to download bun.exe (baseline) instead.`n"
Install-Bun -Version $Version -ForceBaseline $True
exit 1
}
# '-1073741515' was spotted in the wild, but not clearly documented as a status code:
# https://discord.com/channels/876711213126520882/1149339379446325248/1205194965383250081
# http://community.sqlbackupandftp.com/t/error-1073741515-solved/1305
if (($LASTEXITCODE -eq 3221225781) -or ($LASTEXITCODE -eq -1073741515)) # STATUS_DLL_NOT_FOUND
{
Write-Output "Install Failed - You are missing a DLL required to run bun.exe"
Write-Output "This can be solved by installing the Visual C++ Redistributable from Microsoft:`nSee https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist`nDirect Download -> https://aka.ms/vs/17/release/vc_redist.x64.exe`n`n"
Write-Output "The command '${BunBin}\bun.exe --revision' exited with code ${LASTEXITCODE}`n"
exit 1
}
if ($LASTEXITCODE -ne 0) {
Write-Output "Install Failed - could not verify bun.exe"
Write-Output "The command '${BunBin}\bun.exe --revision' exited with code ${LASTEXITCODE}`n"
exit 1
}
$env:IS_BUN_AUTO_UPDATE = "1"
$null = "$(& "${BunBin}\bun.exe" completions)"
if ($LASTEXITCODE -ne 0) {
Write-Output "Install Failed - could not finalize installation"
Write-Output "The command '${BunBin}\bun.exe completions' exited with code ${LASTEXITCODE}`n"
exit 1
}
$env:IS_BUN_AUTO_UPDATE = $null
$DisplayVersion = if ($BunRevision -like "*-canary.*") {
"${BunRevision}"
} else {
"$(& "${BunBin}\bun.exe" --version)"
}
$C_RESET = [char]27 + "[0m"
$C_GREEN = [char]27 + "[1;32m"
Write-Output "${C_GREEN}Bun ${DisplayVersion} was installed successfully!${C_RESET}"
Write-Output "The binary is located at ${BunBin}\bun.exe`n"
Write-Warning "Bun for Windows is currently experimental.`nFor a more stable experience, please install Bun within WSL:`nhttps://bun.sh/docs/installation`n"
$hasExistingOther = $false;
try {
$existing = Get-Command bun -ErrorAction
if ($existing.Source -ne "${BunBin}\bun.exe") {
Write-Warning "Note: Another bun.exe is already in %PATH% at $($existing.Source)`nTyping 'bun' in your terminal will not use what was just installed.`n"
$hasExistingOther = $true;
}
} catch {}
if (-not $NoRegisterInstallation) {
$rootKey = $null
try {
$RegistryKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\Bun"
$rootKey = New-Item -Path $RegistryKey -Force
New-ItemProperty -Path $RegistryKey -Name "DisplayName" -Value "Bun" -PropertyType String -Force | Out-Null
New-ItemProperty -Path $RegistryKey -Name "InstallLocation" -Value "${BunRoot}" -PropertyType String -Force | Out-Null
New-ItemProperty -Path $RegistryKey -Name "DisplayIcon" -Value $BunBin\bun.exe -PropertyType String -Force | Out-Null
New-ItemProperty -Path $RegistryKey -Name "UninstallString" -Value "powershell -c `"& `'$BunRoot\uninstall.ps1`' -PauseOnError`"" -PropertyType String -Force | Out-Null
} catch {
if ($rootKey -ne $null) {
Remove-Item -Path $RegistryKey -Force
}
}
}
if(!$hasExistingOther) {
# Only try adding to path if there isn't already a bun.exe in the path
$Path = (Get-Env -Key "Path") -split ';'
if ($Path -notcontains $BunBin) {
if (-not $NoPathUpdate) {
$Path += $BunBin
Write-Env -Key 'Path' -Value ($Path -join ';')
} else {
Write-Output "Skipping adding '${BunBin}' to the user's %PATH%`n"
}
}
Write-Output "To get started, restart your terminal/editor, then type `"bun`"`n"
}
}
Install-Bun -Version $Version -ForceBaseline $ForceBaseline