ci: Created Loki installation scripts

This commit is contained in:
2025-11-07 11:48:08 -07:00
parent 71d89eaaba
commit 6508940d11
2 changed files with 359 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
<#
loki installer (Windows/PowerShell 5+ and PowerShell 7)
Examples:
powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://raw.githubusercontent.com/Dark-Alex-17/loki/main/scripts/install_loki.ps1 | iex"
pwsh -c "irm https://raw.githubusercontent.com/Dark-Alex-17/loki/main/scripts/install_loki.ps1 | iex -Version vX.Y.Z"
Parameters:
-Version <tag> (default: latest)
-BinDir <path> (default: %LOCALAPPDATA%\loki\bin on Windows; ~/.local/bin on *nix PowerShell)
#>
[CmdletBinding()]
param(
[string]$Version = $env:LOKI_VERSION,
[string]$BinDir = $env:BIN_DIR
)
$Repo = 'Dark-Alex-17/loki'
function Write-Info($msg) { Write-Host "[loki-install] $msg" }
function Fail($msg) { Write-Error $msg; exit 1 }
Add-Type -AssemblyName System.Runtime
$isWin = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)
$isMac = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::OSX)
$isLin = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Linux)
if ($isWin) { $os = 'windows' }
elseif ($isMac) { $os = 'darwin' }
elseif ($isLin) { $os = 'linux' }
else { Fail "Unsupported OS" }
switch ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) {
'X64' { $arch = 'x86_64' }
'Arm64'{ $arch = 'aarch64' }
default { Fail "Unsupported arch: $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)" }
}
if (-not $BinDir) {
if ($isWin) { $BinDir = Join-Path $env:LOCALAPPDATA 'loki\bin' }
else { $home = $env:HOME; if (-not $home) { $home = (Get-Item -Path ~).FullName }; $BinDir = Join-Path $home '.local/bin' }
}
New-Item -ItemType Directory -Force -Path $BinDir | Out-Null
Write-Info "Target: $os-$arch"
$apiBase = "https://api.github.com/repos/$Repo/releases"
$relUrl = if ($Version) { "$apiBase/tags/$Version" } else { "$apiBase/latest" }
Write-Info "Fetching release: $relUrl"
try {
$release = Invoke-RestMethod -UseBasicParsing -Headers @{ 'User-Agent' = 'loki-installer' } -Uri $relUrl -Method GET
} catch { Fail "Failed to fetch release metadata. $_" }
if (-not $release.assets) { Fail "No assets found in the release." }
$candidates = @()
if ($os -eq 'windows') {
if ($arch -eq 'x86_64') { $candidates += 'loki-x86_64-pc-windows-msvc.zip' }
else { $candidates += 'loki-aarch64-pc-windows-msvc.zip' }
} elseif ($os -eq 'darwin') {
if ($arch -eq 'x86_64') { $candidates += 'loki-x86_64-apple-darwin.tar.gz' }
else { $candidates += 'loki-aarch64-apple-darwin.tar.gz' }
} elseif ($os -eq 'linux') {
if ($arch -eq 'x86_64') {
$candidates += 'loki-x86_64-unknown-linux-gnu.tar.gz'
$candidates += 'loki-x86_64-unknown-linux-musl.tar.gz'
} else {
$candidates += 'loki-aarch64-unknown-linux-musl.tar.gz'
}
} else {
Fail "Unsupported OS for this installer: $os"
}
$asset = $null
foreach ($c in $candidates) {
$asset = $release.assets | Where-Object { $_.name -eq $c } | Select-Object -First 1
if ($asset) { break }
}
if (-not $asset) {
Write-Error "No matching asset found for $os-$arch. Tried:"; $candidates | ForEach-Object { Write-Error " - $_" }
exit 1
}
Write-Info "Selected asset: $($asset.name)"
Write-Info "Download URL: $($asset.browser_download_url)"
$tmp = New-Item -ItemType Directory -Force -Path ([IO.Path]::Combine([IO.Path]::GetTempPath(), "loki-$(Get-Random)"))
$archive = Join-Path $tmp.FullName 'asset'
try { Invoke-WebRequest -UseBasicParsing -Headers @{ 'User-Agent' = 'loki-installer' } -Uri $asset.browser_download_url -OutFile $archive } catch { Fail "Failed to download asset. $_" }
$extractDir = Join-Path $tmp.FullName 'extract'; New-Item -ItemType Directory -Force -Path $extractDir | Out-Null
if ($asset.name -match '\.zip$') {
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($archive, $extractDir)
} elseif ($asset.name -match '\.tar\.gz$' -or $asset.name -match '\.tgz$') {
$tar = Get-Command tar -ErrorAction SilentlyContinue
if ($tar) { & $tar.FullName -xzf $archive -C $extractDir }
else { Fail "Asset is tar archive but 'tar' is not available." }
} else {
try { Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory($archive, $extractDir) }
catch {
$tar = Get-Command tar -ErrorAction SilentlyContinue
if ($tar) { & $tar.FullName -xf $archive -C $extractDir } else { Fail "Unknown archive format; neither zip nor tar workable." }
}
}
$bin = $null
Get-ChildItem -Recurse -File $extractDir | ForEach-Object {
if ($isWin) { if ($_.Name -ieq 'loki.exe') { $bin = $_.FullName } }
else { if ($_.Name -ieq 'loki') { $bin = $_.FullName } }
}
if (-not $bin) { Fail "Could not find loki binary inside the archive." }
if (-not $isWin) { try { & chmod +x -- $bin } catch {} }
$exec = if ($isWin) { 'loki.exe'} else { 'loki' }
$dest = Join-Path $BinDir $exec
Copy-Item -Force $bin $dest
Write-Info "Installed: $dest"
if ($isWin) {
$pathParts = ($env:Path -split ';') | Where-Object { $_ -ne '' }
if ($pathParts -notcontains $BinDir) {
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User'); if (-not $userPath) { $userPath = '' }
if (-not ($userPath -split ';' | Where-Object { $_ -eq $BinDir })) {
$newUserPath = if ($userPath.Trim().Length -gt 0) { "$userPath;$BinDir" } else { $BinDir }
[Environment]::SetEnvironmentVariable('Path', $newUserPath, 'User')
Write-Info "Added to User PATH: $BinDir (restart shell to take effect)"
}
}
} else {
if (-not ($env:PATH -split ':' | Where-Object { $_ -eq $BinDir })) {
Write-Info "Note: $BinDir is not in PATH. Add it to your shell profile."
}
}
Write-Info "Done. Try: loki --help"
+220
View File
@@ -0,0 +1,220 @@
#!/usr/bin/env bash
set -euo pipefail
# loki installer (Linux/macOS)
#
# Usage examples:
# curl -fsSL https://raw.githubusercontent.com/Dark-Alex-17/loki/main/scripts/install_loki.sh | bash
# curl -fsSL https://raw.githubusercontent.com/Dark-Alex-17/loki/main/scripts/install_loki.sh | bash -s -- --version vX.Y.Z
# BIN_DIR="$HOME/.local/bin" bash scripts/install_loki.sh
#
# Flags / Env:
# --version <tag> Release tag (default: latest). Or set LOKI_VERSION.
# --bin-dir <dir> Install directory (default: /usr/local/bin or ~/.local/bin). Or set BIN_DIR.
REPO="Dark-Alex-17/loki"
VERSION="${LOKI_VERSION:-}"
BIN_DIR="${BIN_DIR:-}"
usage() {
echo "loki installer (Linux/macOS)"
echo
echo "Options:"
echo " --version <tag> Release tag (default: latest)"
echo " --bin-dir <dir> Install directory (default: /usr/local/bin or ~/.local/bin)"
echo " -h, --help Show help"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--version) VERSION="$2"; shift 2;;
--bin-dir) BIN_DIR="$2"; shift 2;;
-h|--help) usage; exit 0;;
*) echo "Unknown argument: $1" >&2; usage; exit 2;;
esac
done
if [[ -z "${BIN_DIR}" ]]; then
if [[ -w "/usr/local/bin" ]]; then
BIN_DIR="/usr/local/bin"
else
BIN_DIR="${HOME}/.local/bin"
fi
fi
mkdir -p "${BIN_DIR}"
log() {
echo "[loki-install] $*"
}
need_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "Error: required command '$1' not found" >&2
exit 1
fi
}
need_cmd uname
need_cmd mktemp
need_cmd tar
if command -v curl >/dev/null 2>&1; then
DL=curl
elif command -v wget >/dev/null 2>&1; then
DL=wget
else
echo "Error: need curl or wget" >&2
exit 1
fi
UNAME_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$UNAME_OS" in
linux) OS=linux ;;
darwin) OS=darwin ;;
*) echo "Error: unsupported OS '$UNAME_OS'" >&2; exit 1;;
esac
UNAME_ARCH=$(uname -m)
case "$UNAME_ARCH" in
x86_64|amd64) ARCH=x86_64 ;;
aarch64|arm64) ARCH=aarch64 ;;
*) echo "Error: unsupported arch '$UNAME_ARCH'" >&2; exit 1;;
esac
log "Target: ${OS}-${ARCH}"
API_BASE="https://api.github.com/repos/${REPO}/releases"
if [[ -z "${VERSION}" ]]; then
RELEASE_URL="${API_BASE}/latest"
else
RELEASE_URL="${API_BASE}/tags/${VERSION}"
fi
http_get() {
if [[ "$DL" == "curl" ]]; then
curl -fsSL -H 'User-Agent: loki-installer' "$1"
else
wget -qO- --header='User-Agent: loki-installer' "$1"
fi
}
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
log "Fetching release metadata from $RELEASE_URL"
JSON="$TMPDIR/release.json"
if ! http_get "$RELEASE_URL" > "$JSON"; then
echo "Error: failed to fetch release metadata. Check version tag." >&2
exit 1
fi
ASSET_CANDIDATES=()
if [[ "$OS" == "darwin" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
ASSET_CANDIDATES+=("loki-x86_64-apple-darwin.tar.gz")
else
ASSET_CANDIDATES+=("loki-aarch64-apple-darwin.tar.gz")
fi
elif [[ "$OS" == "linux" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
LIBC="musl"
if command -v getconf >/dev/null 2>&1 && getconf GNU_LIBC_VERSION >/dev/null 2>&1; then LIBC="gnu"; fi
if ldd --version 2>&1 | grep -qi glibc; then LIBC="gnu"; fi
if [[ "$LIBC" == "gnu" ]]; then
ASSET_CANDIDATES+=("loki-x86_64-unknown-linux-gnu.tar.gz")
fi
ASSET_CANDIDATES+=("loki-x86_64-unknown-linux-musl.tar.gz")
else
ASSET_CANDIDATES+=("loki-aarch64-unknown-linux-musl.tar.gz")
fi
else
echo "Error: unsupported OS for this installer: $OS" >&2; exit 1
fi
ASSET_NAME=""; ASSET_URL=""
for candidate in "${ASSET_CANDIDATES[@]}"; do
NAME=$(grep -oE '"name":\s*"[^"]+"' "$JSON" | sed 's/"name":\s*"//; s/"$//' | grep -Fx "$candidate" || true)
if [[ -n "$NAME" ]]; then
ASSET_NAME="$NAME"
ASSET_URL=$(awk -v pat="$NAME" '
BEGIN{ FS=":"; want=0 }
/"name"/ {
line=$0;
gsub(/^\s+|\s+$/,"",line);
gsub(/"name"\s*:\s*"|"/ ,"", line);
want = (line==pat) ? 1 : 0;
next
}
want==1 && /"browser_download_url"/ {
u=$0;
gsub(/^\s+|\s+$/,"",u);
gsub(/.*"browser_download_url"\s*:\s*"|".*/ ,"", u);
print u;
exit
}
' "$JSON")
if [[ -n "$ASSET_URL" ]]; then break; fi
fi
done
if [[ -z "$ASSET_URL" ]]; then
echo "Error: no matching asset found for ${OS}-${ARCH}. Tried:" >&2
for c in "${ASSET_CANDIDATES[@]}"; do echo " - $c" >&2; done
exit 1
fi
log "Selected asset: $ASSET_NAME"
log "Download URL: $ASSET_URL"
ARCHIVE="$TMPDIR/asset"
if [[ "$DL" == "curl" ]]; then
curl -fL -H 'User-Agent: loki-installer' "$ASSET_URL" -o "$ARCHIVE"
else
wget -q --header='User-Agent: loki-installer' "$ASSET_URL" -O "$ARCHIVE"
fi
WORK="$TMPDIR/work"; mkdir -p "$WORK"
EXTRACTED_DIR="$WORK/extracted"; mkdir -p "$EXTRACTED_DIR"
if tar -tf "$ARCHIVE" >/dev/null 2>&1; then
tar -xzf "$ARCHIVE" -C "$EXTRACTED_DIR"
else
if command -v unzip >/dev/null 2>&1; then
unzip -q "$ARCHIVE" -d "$EXTRACTED_DIR"
else
echo "Error: unknown archive format; install 'unzip'" >&2
exit 1
fi
fi
BIN_PATH=""
while IFS= read -r -d '' f; do
base=$(basename "$f")
if [[ "$base" == "loki" ]]; then
BIN_PATH="$f"
break
fi
done < <(find "$EXTRACTED_DIR" -type f -print0)
if [[ -z "$BIN_PATH" ]]; then
echo "Error: could not find 'loki' binary in the archive" >&2
exit 1
fi
chmod +x "$BIN_PATH"
install -m 0755 "$BIN_PATH" "${BIN_DIR}/loki"
log "Installed: ${BIN_DIR}/loki"
case ":$PATH:" in
*":${BIN_DIR}:"*) ;;
*)
log "Note: ${BIN_DIR} is not in PATH. Add it, e.g.:"
log " export PATH=\"${BIN_DIR}:\$PATH\""
;;
esac
log "Done. Try: loki --help"