mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-18 13:53:01 +08:00
110 lines
5.3 KiB
PowerShell
110 lines
5.3 KiB
PowerShell
# CodeGraph standalone installer for Windows (PowerShell).
|
|
#
|
|
# Downloads a self-contained bundle (a vendored Node runtime + the app) from
|
|
# GitHub Releases. No Node.js, no build tools required.
|
|
#
|
|
# irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex
|
|
#
|
|
# Upgrade with `codegraph upgrade` (or just re-run this). To uninstall: remove
|
|
# $env:LOCALAPPDATA\codegraph and drop its \current\bin entry from your user PATH.
|
|
#
|
|
# Environment:
|
|
# CODEGRAPH_VERSION release tag to install (default: latest)
|
|
# CODEGRAPH_INSTALL_DIR install location (default: %LOCALAPPDATA%\codegraph)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$repo = 'colbymchenry/codegraph'
|
|
$installDir = if ($env:CODEGRAPH_INSTALL_DIR) { $env:CODEGRAPH_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'codegraph' }
|
|
|
|
# 1. Detect architecture -> target matching the release archives.
|
|
$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' }
|
|
$target = "win32-$arch"
|
|
|
|
# 2. Resolve the version (latest release unless pinned).
|
|
$version = $env:CODEGRAPH_VERSION
|
|
if (-not $version) {
|
|
$version = (Invoke-RestMethod "https://api.github.com/repos/$repo/releases/latest").tag_name
|
|
}
|
|
if (-not $version) { throw "codegraph: could not resolve latest version; set CODEGRAPH_VERSION." }
|
|
|
|
if ($version -notmatch '^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?\z') { throw 'codegraph: invalid release version.' }
|
|
if (-not $version.StartsWith('v')) { $version = "v$version" }
|
|
|
|
# 3. Download + extract the bundle into a stable 'current' dir (overwritten on upgrade).
|
|
$url = "https://github.com/$repo/releases/download/$version/codegraph-$target.zip"
|
|
Write-Host "Installing CodeGraph $version ($target)..."
|
|
$tmp = Join-Path $env:TEMP ("cg-" + [guid]::NewGuid().ToString())
|
|
New-Item -ItemType Directory -Force -Path $tmp | Out-Null
|
|
$zip = Join-Path $tmp 'cg.zip'
|
|
Invoke-WebRequest -Uri $url -OutFile $zip
|
|
$asset = "codegraph-$target.zip"
|
|
$sumsPath = Join-Path $tmp 'SHA256SUMS'
|
|
Invoke-WebRequest -Uri "https://github.com/$repo/releases/download/$version/SHA256SUMS" -OutFile $sumsPath
|
|
$pattern = '^([0-9a-fA-F]{64})\s+\*?' + [regex]::Escape($asset) + '$'
|
|
$entries = @(Get-Content -LiteralPath $sumsPath | Where-Object { $_.Trim() -match $pattern })
|
|
if ($entries.Count -ne 1) { throw 'codegraph: missing or ambiguous archive checksum.' }
|
|
$null = $entries[0].Trim() -match $pattern
|
|
$expectedHash = $Matches[1]
|
|
# Use .NET directly: Windows PowerShell launched from pwsh can lack Get-FileHash.
|
|
$hasher = [System.Security.Cryptography.SHA256]::Create()
|
|
$stream = [System.IO.File]::OpenRead($zip)
|
|
try { $actualHash = [BitConverter]::ToString($hasher.ComputeHash($stream)).Replace('-', '') }
|
|
finally { $stream.Dispose(); $hasher.Dispose() }
|
|
if ($actualHash -ne $expectedHash) { throw 'codegraph: archive checksum mismatch; installation unchanged.' }
|
|
|
|
|
|
$dest = Join-Path $installDir 'current'
|
|
if (Test-Path $dest) { Remove-Item -Recurse -Force $dest }
|
|
New-Item -ItemType Directory -Force -Path $dest | Out-Null
|
|
Expand-Archive -Path $zip -DestinationPath $dest -Force
|
|
# Archives contain a top-level codegraph-<target>\ dir; flatten it.
|
|
$inner = Join-Path $dest "codegraph-$target"
|
|
if (Test-Path $inner) {
|
|
Get-ChildItem -Force $inner | Move-Item -Destination $dest -Force
|
|
Remove-Item -Recurse -Force $inner
|
|
}
|
|
Remove-Item -Recurse -Force $tmp
|
|
|
|
# 4. Put the launcher dir on the user's PATH.
|
|
$binDir = Join-Path $dest 'bin'
|
|
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
if (($userPath -split ';') -notcontains $binDir) {
|
|
[Environment]::SetEnvironmentVariable('Path', "$binDir;$userPath", 'User')
|
|
Write-Host "Added $binDir to your PATH (restart your terminal to pick it up)."
|
|
}
|
|
|
|
Write-Host "Installed to $dest"
|
|
|
|
# 5. Warn if a different codegraph earlier on PATH will shadow this install.
|
|
# Most often a stale `npm i -g @colbymchenry/codegraph`, whose launcher keeps
|
|
# running its own version-pinned bundle — so `codegraph --version` disagrees
|
|
# with what we just installed (issue #1071). Check both the persisted PATH a
|
|
# fresh shell sees (Machine + User) and this session's PATH (catches dirs a
|
|
# shell profile injects, e.g. conda / npm).
|
|
$expected = Join-Path $binDir 'codegraph.cmd'
|
|
function Find-FirstCodegraph([string]$pathStr) {
|
|
foreach ($dir in ($pathStr -split ';')) {
|
|
if (-not $dir) { continue }
|
|
foreach ($leaf in @('codegraph.cmd', 'codegraph.exe', 'codegraph.bat', 'codegraph.ps1')) {
|
|
$cand = Join-Path $dir $leaf
|
|
if (Test-Path -LiteralPath $cand) { return $cand }
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
$machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine')
|
|
$freshPath = ((@($machinePath, [Environment]::GetEnvironmentVariable('Path', 'User')) | Where-Object { $_ }) -join ';')
|
|
$shadow = $null
|
|
foreach ($winner in @((Find-FirstCodegraph $env:Path), (Find-FirstCodegraph $freshPath))) {
|
|
if ($winner -and ($winner -ne $expected)) { $shadow = $winner; break }
|
|
}
|
|
if ($shadow) {
|
|
Write-Warning "Another codegraph is earlier on your PATH and will run instead of this install:"
|
|
Write-Warning " $shadow"
|
|
Write-Warning " (this install: $expected)"
|
|
Write-Warning "If 'codegraph --version' shows an unexpected version, remove the other copy"
|
|
Write-Warning "(e.g. 'npm rm -g @colbymchenry/codegraph') or put '$binDir' first on your PATH."
|
|
}
|
|
|
|
Write-Host "Run: codegraph --help"
|