# Zyvra installer for Windows (PowerShell 5.1 or newer). # irm /install.ps1 | iex # # Downloads the newest release, checks the archive's SHA-256 against the release information, and installs # the program for the current user (no administrator rights). Windows PowerShell cannot check Ed25519 # signatures, so to check the signature yourself, run `zyvra verify` on the files listed under # "How we verify downloads". Settings (environment): # ZYVRA_INSTALL_DIR where to put it (default: %LOCALAPPDATA%\Programs\Zyvra) # ZYVRA_RELEASES_URL where releases are published (a mirror) # ZYVRA_MIRROR_URL where to look when that is busy or down (default: the Zyvra website) $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 function Fail($msg) { Write-Error "zyvra install: $msg"; exit 1 } $base = if ($env:ZYVRA_RELEASES_URL) { $env:ZYVRA_RELEASES_URL.TrimEnd('/') } else { 'https://gitlab.com/zyvra-release/releases/-/releases/permalink/latest/downloads' } $mirror = if ($null -ne $env:ZYVRA_MIRROR_URL) { $env:ZYVRA_MIRROR_URL.TrimEnd('/') } else { 'https://zyvra-eight.vercel.app' } $dest = if ($env:ZYVRA_INSTALL_DIR) { $env:ZYVRA_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'Programs\Zyvra' } # Only an amd64 build exists; Windows on ARM runs it through emulation. if ($env:PROCESSOR_ARCHITECTURE -notin @('AMD64', 'ARM64')) { Fail "no build for the processor $($env:PROCESSOR_ARCHITECTURE)" } Write-Host 'Looking up the newest Zyvra release...' # The release host throttles anonymous requests now and then; the website serves the same files. $m = $null foreach ($b in @($base, $mirror)) { if (-not $b) { continue } try { $m = Invoke-RestMethod -Uri "$b/latest.json" -UseBasicParsing; break } catch { Write-Host "Could not reach $b, trying another address..." } } if (-not $m) { Fail 'could not download the release information (the release server may be busy: try again in a few minutes)' } $asset = $m.platforms.'windows-amd64' if (-not $asset) { Fail 'this release has no Windows build' } if ($asset.url -notmatch '^(https://|http://127\.0\.0\.1:|http://localhost:)') { Fail 'the release points at a download that is not https' } if ($asset.sha256 -notmatch '^[0-9a-f]{64}$') { Fail 'the release information is incomplete' } $tmp = Join-Path ([IO.Path]::GetTempPath()) ("zyvra-install-" + [Guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Path $tmp | Out-Null try { Write-Host "Downloading Zyvra $($m.version)..." $zip = Join-Path $tmp 'zyvra.zip' Invoke-WebRequest -Uri $asset.url -OutFile $zip -UseBasicParsing $got = (Get-FileHash -Algorithm SHA256 -Path $zip).Hash.ToLower() if ($got -ne $asset.sha256) { Fail 'the download does not match its checksum. Nothing was installed.' } $x = Join-Path $tmp 'x' Expand-Archive -Path $zip -DestinationPath $x $exe = Get-ChildItem -Path $x -Recurse -Filter 'zyvra.exe' | Select-Object -First 1 if (-not $exe) { Fail 'the download has no zyvra.exe in it' } New-Item -ItemType Directory -Force -Path $dest | Out-Null $target = Join-Path $dest 'zyvra.exe' if (Test-Path $target) { Move-Item -Force $target "$target.old" } # a running copy can be renamed, not overwritten Copy-Item $exe.FullName $target Remove-Item -Force "$target.old" -ErrorAction SilentlyContinue } finally { Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue } $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') if (($userPath -split ';') -notcontains $dest) { [Environment]::SetEnvironmentVariable('Path', ($userPath.TrimEnd(';') + ';' + $dest), 'User') Write-Host "Added $dest to your PATH (open a new terminal to use it)." } Write-Host '' Write-Host "Installed Zyvra $($m.version) to $target" Write-Host 'Next: zyvra init my-project; zyvra up Update later with: zyvra update'