-
Notifications
You must be signed in to change notification settings - Fork 0
/
install.ps1
288 lines (249 loc) · 10.7 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
285
286
287
288
#!/usr/bin/env pwsh
param(
# Specify the exact version of xv to install.
[String]$Version = "1.0.0",
# Forces installing the baseline build regardless of what CPU you are actually using.
[Switch]$ForceBaseline = $false,
# Skips adding the xv.exe directory to the user's %PATH%
[Switch]$NoPathUpdate = $false,
# Skips adding the xv to the list of installed programs
[Switch]$NoRegisterInstallation = $false,
# Skips installing powershell completions to your profile
[Switch]$NoCompletions = $true,
# Debugging: Always download with 'Invoke-RestMethod' instead of 'curl.exe'
[Switch]$DownloadWithoutCurl = $false
);
# filter out 32 bit + ARM
if (-not ((Get-CimInstance Win32_ComputerSystem)).SystemType -match "x64-based") {
Write-Output "Install Failed:"
Write-Output "xv 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 "xv 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 xv 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-Xv {
param(
[string]$Version,
[bool]$ForceBaseline = $False
);
# if a semver is given, we need to adjust it to this format: xv-v0.0.0
if ($Version -match "^\d+\.\d+\.\d+$") {
$Version = "v$Version"
}
elseif ($Version -match "^v\d+\.\d+\.\d+$") {
$Version = "$Version"
}
$Arch = "amd64"
$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);
}
$XvRoot = if ($env:XV_INSTALL) { $env:XV_INSTALL } else { "${Home}\.xv" }
$XvBin = mkdir -Force "${XvRoot}\bin"
try {
Remove-Item "${XvBin}\xv.exe" -Force
} catch [System.Management.Automation.ItemNotFoundException] {
# ignore
} catch [System.UnauthorizedAccessException] {
$openProcesses = Get-Process -Name xv | Where-Object { $_.Path -eq "${XvBin}\xv.exe" }
if ($openProcesses.Count -gt 0) {
Write-Output "Install Failed - An older installation exists and is open. Please close open xv 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 = "xv-windows-$Arch"
if ($IsBaseline) {
$Target = "xv-windows-$Arch-baseline"
}
$BaseURL = "https://github.com/mmilian/xv/releases"
$URL = "$BaseURL/$(if ($Version -eq "latest") { "latest/download" } else { "download/$Version" })/$Target.zip"
$ZipPath = "${XvBin}\$Target.zip"
$DisplayVersion = $(
if ($Version -eq "latest") { "Xv" }
elseif ($Version -eq "canary") { "Xv Canary" }
elseif ($Version -match "^v\d+\.\d+\.\d+$") { "Xv $($Version.Substring(4))" }
else { "Xv tag='${Version}'" }
)
$null = mkdir -Force $XvBin
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" "${XvBin}\$Target" -Force
$global:ProgressPreference = $lastProgressPreference
if (!(Test-Path "${XvBin}\$Target\xv.exe")) {
throw "The file '${XvBin}\$Target\xv.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 "${XvBin}\$Target\xv.exe" "${XvBin}\xv.exe" -Force
Move-Item "${XvBin}\$Target\scripts\uninstall.ps1" "${XvRoot}\uninstall.ps1" -Force
Remove-Item "${XvBin}\$Target" -Recurse -Force
Remove-Item $ZipPath -Force
$XvRevision = "$(& "${XvBin}\xv.exe" --revision)"
if ($LASTEXITCODE -eq 1073741795) { # STATUS_ILLEGAL_INSTRUCTION
if ($IsBaseline) {
Write-Output "Install Failed - xv.exe (baseline) is not compatible with your CPU.`n"
Write-Output "Please open a GitHub issue with your CPU model:`nhttps://github.com/creoox/xv-dist/issues/new/choose`n"
return 1
}
Write-Output "Install Failed - xv.exe is not compatible with your CPU. This should have been detected before downloading.`n"
Write-Output "Attempting to download xv.exe (baseline) instead.`n"
Install-Xv -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 xv.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 '${XvBin}\xv.exe --revision' exited with code ${LASTEXITCODE}`n"
return 1
}
if ($LASTEXITCODE -ne 0) {
Write-Output "Install Failed - could not verify xv.exe"
Write-Output "The command '${XvBin}\xv.exe --revision' exited with code ${LASTEXITCODE}`n"
return 1
}
$DisplayVersion = if ($XvRevision -like "*-canary.*") {
"${XvRevision}"
} else {
"$(& "${XvBin}\xv.exe" --version)"
}
$C_RESET = [char]27 + "[0m"
$C_GREEN = [char]27 + "[1;32m"
Write-Output "${C_GREEN}xv ${DisplayVersion} was installed successfully!${C_RESET}"
Write-Output "The binary is located at ${XvBin}\xv.exe`n"
$hasExistingOther = $false;
try {
$existing = Get-Command xv -ErrorAction
if ($existing.Source -ne "${XvBin}\xv.exe") {
Write-Warning "Note: Another xv.exe is already in %PATH% at $($existing.Source)`nTyping 'xv' 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\Xv"
$rootKey = New-Item -Path $RegistryKey -Force
New-ItemProperty -Path $RegistryKey -Name "DisplayName" -Value "Xv" -PropertyType String -Force | Out-Null
New-ItemProperty -Path $RegistryKey -Name "InstallLocation" -Value "${XvRoot}" -PropertyType String -Force | Out-Null
New-ItemProperty -Path $RegistryKey -Name "DisplayIcon" -Value $XvBin\xv.exe -PropertyType String -Force | Out-Null
New-ItemProperty -Path $RegistryKey -Name "UninstallString" -Value "powershell -c `"& `'$XvRoot\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 xv.exe in the path
$Path = (Get-Env -Key "Path") -split ';'
if ($Path -notcontains $XvBin) {
if (-not $NoPathUpdate) {
$Path += $XvBin
Write-Env -Key 'Path' -Value ($Path -join ';')
$env:PATH = $Path;
} else {
Write-Output "Skipping adding '${XvBin}' to the user's %PATH%`n"
}
}
Write-Output "To get started, restart your terminal/editor, then type `"xv --help`"`n"
}
$LASTEXITCODE = 0;
}
Install-Xv -Version $Version -ForceBaseline $ForceBaseline