Skip to content
Merged
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
118 changes: 110 additions & 8 deletions packages/cli/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,87 @@ function Write-Warn {
Write-Host $Message
}

# Exit code when a Windows native binary cannot load required DLLs (STATUS_DLL_NOT_FOUND).
$script:DllNotFoundExitCode = -1073741515

function Test-IsDllNotFoundExitCode {
param([int]$ExitCode)
if ($ExitCode -eq $script:DllNotFoundExitCode) {
return $true
}
if ($ExitCode -eq 3221225781) {
return $true
}
if ($ExitCode -lt 0) {
$hex = '{0:X8}' -f ($ExitCode -band 0xFFFFFFFF)
return $hex -eq 'C0000135'
}
return $false
}

function Get-DllNotFoundInstallMessage {
$arch = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "arm64" } else { "x64" }
$vcUrl = if ($arch -eq "arm64") {
"https://aka.ms/vs/17/release/vc_redist.arm64.exe"
} else {
"https://aka.ms/vs/17/release/vc_redist.x64.exe"
}
return @"
vp.exe could not start (exit code 0xC0000135).
This usually means Microsoft Visual C++ 2015-2022 Redistributable ($arch) is not installed.

Install: $vcUrl
Then re-run: irm https://vite.plus/ps1 | iex
"@
}

# Internal stop signal: halts install without re-printing an error we already wrote.
$script:InstallStopSignal = 'VP_INSTALL_STOP'

function Test-IsInstallStopException {
param(
[System.Management.Automation.ErrorRecord]$ErrorRecord
)
return $ErrorRecord.Exception.Message -eq $script:InstallStopSignal
}

function Test-ShouldKeepShellOpenAfterFailure {
# Only `irm ... | iex` typed in an already-open interactive shell should keep the
# session alive. CI, script files, and `powershell -Command "..."` must exit non-zero.
if ($env:CI -eq "true") {
return $false
}
if ($PSCommandPath) {
return $false
}
if (-not [Environment]::UserInteractive) {
return $false
}
try {
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$PID").CommandLine
if ($commandLine -match '(^|\s)-Command(\s|$)') {
return $false
}
} catch {
return $false
}
return $true
}

function Exit-Installer {
param([int]$Code = 1)
$global:LASTEXITCODE = $Code
if (-not (Test-ShouldKeepShellOpenAfterFailure)) {
exit $Code
}
throw $script:InstallStopSignal
Comment thread
cheezone marked this conversation as resolved.
}

function Write-Error-Exit {
param([string]$Message)
Write-Host "error: " -ForegroundColor Red -NoNewline
Write-Host $Message
exit 1
Exit-Installer
}

function Test-ReleaseAgeError {
Expand Down Expand Up @@ -114,11 +190,26 @@ function Write-ReleaseAgeOverride {
}

function Write-InstallFailure {
param([string]$LogPath)
param(
[string]$LogPath,
[int]$ExitCode = 0
)

if (Test-IsDllNotFoundExitCode $ExitCode) {
$message = Get-DllNotFoundInstallMessage
if ($env:CI -eq "true") {
Write-Host "error: " -ForegroundColor Red -NoNewline
Write-Host $message
Exit-Installer
}
Write-Error-Exit $message
}

if ($env:CI -eq "true") {
Write-Host "error: " -ForegroundColor Red -NoNewline
Write-Host "Failed to install dependencies. Log output:"
Get-Content -Path $LogPath | ForEach-Object { Write-Host $_ }
Exit-Installer
} else {
Write-Error-Exit "Failed to install dependencies. See log for details: $LogPath"
}
Expand Down Expand Up @@ -157,6 +248,7 @@ function Get-PackageMetadata {
try {
$script:PackageMetadata = Invoke-RestMethod $metadataUrl
} catch {
if (Test-IsInstallStopException $_) { throw }
# Try to extract npm error message from response
$errorMsg = $_.ErrorDetails.Message
if ($errorMsg) {
Expand All @@ -166,6 +258,7 @@ function Get-PackageMetadata {
Write-Error-Exit "Failed to fetch version '${versionPath}': $($errorJson.error)`n URL: $metadataUrl"
}
} catch {
if (Test-IsInstallStopException $_) { throw }
# JSON parsing failed, fall through to generic error
}
}
Expand All @@ -179,6 +272,7 @@ function Get-PackageMetadata {
try {
$script:PackageMetadata = $script:PackageMetadata | ConvertFrom-Json
} catch {
if (Test-IsInstallStopException $_) { throw }
# Not valid JSON - treat as plain string error
Write-Error-Exit "Failed to fetch version '${versionPath}': $script:PackageMetadata`n URL: $metadataUrl"
}
Expand Down Expand Up @@ -593,16 +687,14 @@ function Main {
$retryExitCode = $LASTEXITCODE
$retryOutput | Out-File $installLog
if ($retryExitCode -ne 0) {
Write-InstallFailure $installLog
exit 1
Write-InstallFailure -LogPath $installLog -ExitCode $retryExitCode
}
} else {
Write-ReleaseAgeFailure $installLog
exit 1
Exit-Installer
}
} else {
Write-InstallFailure $installLog
exit 1
Write-InstallFailure -LogPath $installLog -ExitCode $installExitCode
}
}
} finally {
Expand Down Expand Up @@ -749,4 +841,14 @@ exec "`$VP_HOME/current/bin/vp.exe" "`$@"
Write-Host ""
}

Main
try {
Main
} catch {
if (Test-IsInstallStopException $_) {
if (Test-ShouldKeepShellOpenAfterFailure) {
return
}
exit $global:LASTEXITCODE
}
throw
}
Loading