Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows Pin Bun version #3192

Merged
merged 2 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion reflex/constants/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Bun(SimpleNamespace):
"""Bun constants."""

# The Bun version.
VERSION = "1.1.5"
VERSION = "1.1.6"
# Min Bun Version
MIN_VERSION = "0.7.0"
# The directory to store the bun.
Expand All @@ -46,6 +46,10 @@ class Bun(SimpleNamespace):
)
# URL to bun install script.
INSTALL_URL = "https://bun.sh/install"
# URL to windows install script.
WINDOWS_INSTALL_URL = (
"https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/install.ps1"
)


# FNM config.
Expand Down
11 changes: 9 additions & 2 deletions reflex/utils/prerequisites.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,15 @@ def install_bun():
# if unzip is installed
if constants.IS_WINDOWS:
processes.new_process(
["powershell", "-c", f"irm {constants.Bun.INSTALL_URL}.ps1|iex"],
env={"BUN_INSTALL": constants.Bun.ROOT_PATH},
[
"powershell",
"-c",
f"irm {constants.Bun.INSTALL_URL}.ps1|iex",
], # TODO: change install url to constants.BUN.WINDOWS_INSTALL_URL
env={
"BUN_INSTALL": constants.Bun.ROOT_PATH,
"BUN_VERSION": constants.Bun.VERSION,
},
shell=True,
run=True,
show_logs=console.is_debug(),
Expand Down
305 changes: 305 additions & 0 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
#!/usr/bin/env pwsh
param(
# 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,
# Skips installing powershell completions to your profile
[Switch]$NoCompletions = $false,

# Debugging: Always download with 'Invoke-RestMethod' instead of 'curl.exe'
[Switch]$DownloadWithoutCurl = $false
);
$Version = if ($env:BUN_VERSION) { $env:BUN_VERSION } else { "latest" }
# filter out 32 bit + ARM
if (-not ((Get-CimInstance Win32_ComputerSystem)).SystemType -match "x64-based") {
Write-Output "Install Failed:"
Write-Output "Bun for Windows is currently only available for x86 64-bit Windows.`n"
return 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"
return 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"
}

$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."
return 1
}
Write-Output "Install Failed - An unknown error occurred while trying to remove the existing installation"
Write-Output $_
return 1
} catch {
Write-Output "Install Failed - An unknown error occurred while trying to remove the existing installation"
Write-Output $_
return 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
if (-not $DownloadWithoutCurl) {
curl.exe "-#SfLo" "$ZipPath" "$URL"
}
if ($DownloadWithoutCurl -or ($LASTEXITCODE -ne 0)) {
Write-Warning "The command 'curl.exe $URL -o $ZipPath' exited with code ${LASTEXITCODE}`nTrying an alternative download method..."
try {
# Use Invoke-RestMethod instead of Invoke-WebRequest because Invoke-WebRequest breaks on
# some machines, see
Invoke-RestMethod -Uri $URL -OutFile $ZipPath
} catch {
Write-Output "Install Failed - could not download $URL"
Write-Output "The command 'Invoke-RestMethod $URL -OutFile $ZipPath' exited with code ${LASTEXITCODE}`n"
return 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"
return 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 $_
return 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"
return 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
return 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"
return 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"
return 1
}

try {
$env:IS_BUN_AUTO_UPDATE = "1"
# TODO: When powershell completions are added, make this switch actually do something
if ($NoCompletions) {
$env:BUN_NO_INSTALL_COMPLETIONS = "1"
}
# This completions script in general will install some extra stuff, mainly the `bunx` link.
# It also installs completions.
$output = "$(& "${BunBin}\bun.exe" completions 2>&1)"
if ($LASTEXITCODE -ne 0) {
Write-Output $output
Write-Output "Install Failed - could not finalize installation"
Write-Output "The command '${BunBin}\bun.exe completions' exited with code ${LASTEXITCODE}`n"
return 1
}
} catch {
# it is possible on powershell 5 that an error happens, but it is probably fine?
}
$env:IS_BUN_AUTO_UPDATE = $null
$env:BUN_NO_INSTALL_COMPLETIONS = $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"

$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`" -ExecutionPolicy Bypass" -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 ';')
$env:PATH = $Path;
} 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"
}

$LASTEXITCODE = 0;
}

Install-Bun -Version $Version -ForceBaseline $ForceBaseline
Loading