bagger 0.1.0-beta.10

Bagger is a CLI implementation of Scoop in Rust
#Requires -Version 5.1
<#
.SYNOPSIS
    One-liner install script for bagger (Scoop in Rust).
.DESCRIPTION
    Downloads a bagger release binary from GitHub and places it on PATH
    (per-user or system-wide).
.NOTES
    Windows-only.  Requires PowerShell 5.1+ and an internet connection.
.EXAMPLE
    PS> iwr -useb https://raw.githubusercontent.com/vincentmathis/bagger/main/scripts/install.ps1 | iex
#>
param(
    [switch]$System,          # install to Program Files (machine-wide, requires admin)
    [string]$Dir,             # override install directory
    [switch]$NoEnv,           # do not modify user/system PATH
    [switch]$Force,           # reinstall even if already present & newer
    [string]$Tag = "latest"   # GitHub tag / release to fetch
)

$ErrorActionPreference = "Stop"

# — helpers ──────────────────────────────────────────────────────────────
function Write-Step([string]$msg) { Write-Host "[bagger] " -NoNewline -ForegroundColor Cyan; Write-Host $msg }
function Die([string]$msg, [int]$code = 1) { Write-Host "[bagger] ERROR: $msg" -ForegroundColor Red; exit $code }

# — resolve install dir ─────────────────────────────────────────────────
if (-not $Dir) {
    if ($System) {
        if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
            Die "Admin rights are required for a system-wide (-System) installation."
        }
        $Dir = "$Env:ProgramFiles\bagger"
    } else {
        $Dir = "$Env:LOCALAPPDATA\bagger"
    }
}
$Dir = [System.IO.Path]::GetFullPath($Dir)

# — fetch release asset URL ─────────────────────────────────────────
Write-Step "Resolving release ..."
$apiBase = "https://api.github.com/repos/vincentmathis/bagger/releases"
$release = if ($Tag -eq "latest") {
    irm "$apiBase/latest"
} else {
    $t = $Tag.TrimStart('v')
    try { irm "$apiBase/tags/v$t" } catch { irm "$apiBase/tags/$t" }
}
if (-not $release) { Die "Could not find release '$Tag'." }
try { $remote = [Version]($release.tag_name.TrimStart('v')) } catch { $remote = $null }

# Pick the asset matching this machine's architecture.
$arch = if ([System.Environment]::Is64BitOperatingSystem) {
    if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'aarch64' } else { 'x86_64' }
} else { 'i686' }
$want = "bagger-$arch-pc-windows-msvc.zip"
$asset = @($release.assets | Where-Object { $_.name -eq $want })[0]
if (-not $asset) { Die "Release $($release.tag_name) has no asset '$want'." }

$zipUrl = $asset.browser_download_url
$zipTmp = "$env:TEMP\bagger-install.zip"

# — check existing ─────────────────────────────────────────────────────
if (-not $Force -and (Test-Path "$Dir\bagger.exe")) {
    try {
        $local = [Version]((Get-Item "$Dir\bagger.exe").VersionInfo.ProductVersion)
    } catch { $local = $null }
    if ($local -and $remote -and ($local -ge $remote)) {
        Write-Step "$Dir\bagger.exe (v$local) is up to date (remote v$remote). Use -Force to reinstall."
        exit 0
    }
}

# — download ───────────────────────────────────────────────────────────
Write-Step "Downloading $($asset.name) ..."
irm -Uri $zipUrl -OutFile $zipTmp

# — extract ────────────────────────────────────────────────────────────
Write-Step "Extracting to $Dir ..."
New-Item -ItemType Directory -Force -Path $Dir | Out-Null
Expand-Archive -LiteralPath $zipTmp -DestinationPath $Dir -Force

$exe = "$Dir\bagger.exe"
if (-not (Test-Path $exe)) { Die "Extraction did not yield bagger.exe" }
Remove-Item $zipTmp -ErrorAction SilentlyContinue

# — PATH ───────────────────────────────────────────────────────────────
if (-not $NoEnv) {
    $scope = if ($System) { "Machine" } else { "User" }
    $path = [Environment]::GetEnvironmentVariable("Path", $scope)
    if (-not ($path -split ';' | Where-Object { $_ -and (Get-Item $_ -ErrorAction SilentlyContinue) -and (Get-Item $_).FullName -eq $Dir })) {
        Write-Step "Adding $Dir to $scope PATH ..."
        $new = if ([string]::IsNullOrEmpty($path)) { $Dir } else { "$path;$Dir" }
        [Environment]::SetEnvironmentVariable("Path", $new, $scope)
    }
}

# — smoke test ─────────────────────────────────────────────────────────
Write-Step "Verifying install ..."
$env:Path = "$Dir;$env:Path"
$verOut = (bagger --version 2>$null)
if ($verOut -match 'bagger (\S+)') { Write-Host "bagger $($Matches[1]) installed to $exe" -ForegroundColor Green }
else { Die "bagger.exe failed to start after install." }
Write-Host "Run 'bagger help' to get started." -ForegroundColor Green