|
| 1 | +# install.ps1 |
| 2 | +param( |
| 3 | + [string]$Tag = "latest", |
| 4 | + [string]$InstallDir = "$env:LOCALAPPDATA\Programs\loops" |
| 5 | +) |
| 6 | + |
| 7 | +$ErrorActionPreference = "Stop" |
| 8 | + |
| 9 | +$GHRepo = "loops-so/cli" |
| 10 | +$GHAssetsUrl = "https://github.com/$GHRepo/releases/download" |
| 11 | +$ProjName = "loops_cli" |
| 12 | +$BinName = "loops.exe" |
| 13 | + |
| 14 | +$Arch = switch ($env:PROCESSOR_ARCHITECTURE) { |
| 15 | + "AMD64" { "x86_64" } |
| 16 | + "ARM64" { "arm64" } |
| 17 | + "x86" { "i386" } |
| 18 | + default { throw "Unsupported architecture: $env:PROCESSOR_ARCHITECTURE" } |
| 19 | +} |
| 20 | + |
| 21 | +$AuthHeader = @{} |
| 22 | +if ($env:GITHUB_TOKEN) { |
| 23 | + $AuthHeader["Authorization"] = "Bearer $env:GITHUB_TOKEN" |
| 24 | +} |
| 25 | + |
| 26 | +function Get-GithubRelease { |
| 27 | + param([string]$Repo, [string]$Version) |
| 28 | + $url = if ($Version -eq "latest") { |
| 29 | + "https://api.github.com/repos/$Repo/releases/latest" |
| 30 | + } else { |
| 31 | + "https://api.github.com/repos/$Repo/releases/tags/$Version" |
| 32 | + } |
| 33 | + $response = Invoke-RestMethod -Uri $url -Headers $AuthHeader |
| 34 | + return $response.tag_name |
| 35 | +} |
| 36 | + |
| 37 | +function Confirm-Checksum { |
| 38 | + param([string]$FilePath, [string]$ChecksumsPath) |
| 39 | + $filename = Split-Path $FilePath -Leaf |
| 40 | + $line = Get-Content $ChecksumsPath | Where-Object { $_ -match [regex]::Escape($filename) } |
| 41 | + if (-not $line) { |
| 42 | + throw "Could not find checksum for $filename" |
| 43 | + } |
| 44 | + $want = ($line -split '\s+')[0].ToLower() |
| 45 | + $got = (Get-FileHash -Algorithm SHA256 -Path $FilePath).Hash.ToLower() |
| 46 | + if ($want -ne $got) { |
| 47 | + throw "Checksum mismatch for $filename`: expected $want, got $got" |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +$release = Get-GithubRelease -Repo $GHRepo -Version $Tag |
| 52 | +$versionNoV = $release -replace '^v', '' |
| 53 | +$archiveName = "${ProjName}_windows_${Arch}.zip" |
| 54 | +$checksumsName = "${ProjName}_${versionNoV}_checksums.txt" |
| 55 | +$downloadUrl = "$GHAssetsUrl/$release/$archiveName" |
| 56 | +$checksumsUrl = "$GHAssetsUrl/$release/$checksumsName" |
| 57 | + |
| 58 | +Write-Host "Installing $ProjName $release for windows/$Arch..." |
| 59 | + |
| 60 | +$tmpDir = Join-Path $env:TEMP ([System.IO.Path]::GetRandomFileName()) |
| 61 | +New-Item -ItemType Directory -Path $tmpDir | Out-Null |
| 62 | + |
| 63 | +try { |
| 64 | + Invoke-WebRequest -Uri $downloadUrl -OutFile "$tmpDir\$archiveName" -Headers $AuthHeader |
| 65 | + Invoke-WebRequest -Uri $checksumsUrl -OutFile "$tmpDir\$checksumsName" -Headers $AuthHeader |
| 66 | + |
| 67 | + Confirm-Checksum -FilePath "$tmpDir\$archiveName" -ChecksumsPath "$tmpDir\$checksumsName" |
| 68 | + |
| 69 | + Expand-Archive -Path "$tmpDir\$archiveName" -DestinationPath $tmpDir -Force |
| 70 | + |
| 71 | + if (-not (Test-Path $InstallDir)) { |
| 72 | + New-Item -ItemType Directory -Path $InstallDir | Out-Null |
| 73 | + } |
| 74 | + |
| 75 | + Copy-Item "$tmpDir\$BinName" "$InstallDir\$BinName" -Force |
| 76 | + |
| 77 | + $userPath = [System.Environment]::GetEnvironmentVariable("Path", "User") |
| 78 | + if ($userPath -notlike "*$InstallDir*") { |
| 79 | + [System.Environment]::SetEnvironmentVariable("Path", "$userPath;$InstallDir", "User") |
| 80 | + $env:PATH = "$env:PATH;$InstallDir" |
| 81 | + Write-Host "Added $InstallDir to your PATH" |
| 82 | + } |
| 83 | +} finally { |
| 84 | + Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue |
| 85 | +} |
| 86 | + |
| 87 | +Write-Host "Done!" |
| 88 | +Write-Host "Installed to $InstallDir\$BinName" |
0 commit comments