Skip to content

Commit 9c6ee8f

Browse files
authored
feat: windows powershell install script (#45)
1 parent d2c889d commit 9c6ee8f

3 files changed

Lines changed: 111 additions & 1 deletion

File tree

.github/workflows/test-install.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,19 @@ jobs:
2727
else
2828
"$INSTALL_DIR/loops" version
2929
fi
30+
31+
test-ps1:
32+
name: install ps1 (windows)
33+
runs-on: windows-latest
34+
steps:
35+
- uses: actions/checkout@v6
36+
- shell: pwsh
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
run: |
40+
$InstallDir = "$env:TEMP\loops-test"
41+
.\install.ps1 -InstallDir $InstallDir
42+
- shell: pwsh
43+
run: |
44+
$InstallDir = "$env:TEMP\loops-test"
45+
& "$InstallDir\loops.exe" version

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,20 @@ Run `loops --help` to see available commands, or `loops [command] --help` for de
2121
brew install loops-so/tap/loops
2222
```
2323

24-
### Script
24+
### Script for macOS, Linux, Windows via WSL
2525

2626
```bash
2727
curl -fsSL --proto '=https' --tlsv1.2 https://raw.githubusercontent.com/loops-so/cli/main/install.sh | bash
2828
```
2929

3030
To install a specific version or to a custom path, append `-s -- <version> <path>` to `bash` in the command above. The default installation path is `~/.local/bin`.
3131

32+
### Script for Windows PowerShell
33+
34+
```
35+
irm https://raw.githubusercontent.com/Loops-so/cli/main/install.ps1 | iex
36+
```
37+
3238
## Auth
3339

3440
The CLI requires a Loops API key. Get one from [Settings > API](https://app.loops.so/settings?page=api).

install.ps1

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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

Comments
 (0)