feat(build): add tar.xz support and unified installer scripts
- Add tar.xz archive support using Borg's compress package - ArchiveXZ() and ArchiveWithFormat() for configurable compression - Better compression ratio than gzip for release artifacts - Consolidate 12 installer scripts into 2 unified scripts - install.sh and install.bat with BunnyCDN edge variable support - Subdomains: setup.core.help, ci.core.help, dev.core.help, etc. - MODE and VARIANT transformed at edge based on subdomain - Installers prefer tar.xz with automatic fallback to tar.gz - Fixed CodeRabbit issues: HTTP status patterns, tar error handling, verify_install params, VARIANT validation, CI PATH persistence Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cb5f7030d6
commit
e084ccbd51
18 changed files with 595 additions and 760 deletions
1
go.mod
1
go.mod
|
|
@ -58,6 +58,7 @@ require (
|
|||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/wI2L/jsondiff v0.7.0 // indirect
|
||||
github.com/woodsbury/decimal128 v1.4.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -142,6 +142,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
|||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/wI2L/jsondiff v0.7.0 h1:1lH1G37GhBPqCfp/lrs91rf/2j3DktX6qYAKZkLuCQQ=
|
||||
github.com/wI2L/jsondiff v0.7.0/go.mod h1:KAEIojdQq66oJiHhDyQez2x+sRit0vIzC9KeK0yizxM=
|
||||
github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc=
|
||||
|
|
|
|||
180
install.bat
Normal file
180
install.bat
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
@echo off
|
||||
REM Core CLI unified installer (Windows)
|
||||
REM Served via *.core.help with BunnyCDN edge transformation
|
||||
REM
|
||||
REM Usage:
|
||||
REM curl -fsSL setup.core.help -o install.bat && install.bat # Interactive (default)
|
||||
REM curl -fsSL ci.core.help -o install.bat && install.bat # CI/CD
|
||||
REM curl -fsSL dev.core.help -o install.bat && install.bat # Full development
|
||||
REM curl -fsSL go.core.help -o install.bat && install.bat # Go variant
|
||||
REM curl -fsSL php.core.help -o install.bat && install.bat # PHP variant
|
||||
REM curl -fsSL agent.core.help -o install.bat && install.bat # Agent variant
|
||||
REM
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM === BunnyCDN Edge Variables (transformed at edge based on subdomain) ===
|
||||
set "MODE={{CORE_MODE}}"
|
||||
set "VARIANT={{CORE_VARIANT}}"
|
||||
|
||||
REM === Fallback for local testing ===
|
||||
if "!MODE!"=="{{CORE_MODE}}" (
|
||||
if defined CORE_MODE (set "MODE=!CORE_MODE!") else (set "MODE=setup")
|
||||
)
|
||||
if "!VARIANT!"=="{{CORE_VARIANT}}" (
|
||||
if defined CORE_VARIANT (set "VARIANT=!CORE_VARIANT!") else (set "VARIANT=")
|
||||
)
|
||||
|
||||
REM === Configuration ===
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\Programs\core"
|
||||
|
||||
REM === Resolve Version ===
|
||||
if "%VERSION%"=="latest" (
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo ERROR: Failed to fetch latest version
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo ERROR: Failed to resolve version
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
REM === Create install directory ===
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
REM === Mode dispatch ===
|
||||
if "%MODE%"=="ci" goto :install_ci
|
||||
if "%MODE%"=="dev" goto :install_dev
|
||||
if "%MODE%"=="variant" goto :install_variant
|
||||
goto :install_setup
|
||||
|
||||
:install_setup
|
||||
echo Installing %BINARY% !VERSION! for Windows...
|
||||
call :find_archive "" ARCHIVE
|
||||
call :download_and_extract
|
||||
call :install_binary
|
||||
call :verify_install
|
||||
goto :done
|
||||
|
||||
:install_ci
|
||||
echo Installing %BINARY% !VERSION! (CI)...
|
||||
call :find_archive "" ARCHIVE
|
||||
|
||||
REM Download
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/!ARCHIVE!" -o "%TEMP%\!ARCHIVE!"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download !ARCHIVE!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Extract - try System32 first (CI often has admin), else local
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\!ARCHIVE!' '%TEMP%\core-extract' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
move /y "%TEMP%\core-extract\%BINARY%.exe" "C:\Windows\System32\%BINARY%.exe" >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
move /y "%TEMP%\core-extract\%BINARY%.exe" "%INSTALL_DIR%\%BINARY%.exe"
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
)
|
||||
rmdir /s /q "%TEMP%\core-extract" 2>nul
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
|
||||
%BINARY% --version || exit /b 1
|
||||
goto :done
|
||||
|
||||
:install_dev
|
||||
echo Installing %BINARY% !VERSION! (full) for Windows...
|
||||
call :find_archive "" ARCHIVE
|
||||
call :download_and_extract
|
||||
call :install_binary
|
||||
call :verify_install
|
||||
echo.
|
||||
echo Full development variant installed. Available commands:
|
||||
echo core dev - Multi-repo workflows
|
||||
echo core build - Cross-platform builds
|
||||
echo core release - Build and publish releases
|
||||
goto :done
|
||||
|
||||
:install_variant
|
||||
echo Installing %BINARY% !VERSION! (%VARIANT% variant) for Windows...
|
||||
call :find_archive "%VARIANT%" ARCHIVE
|
||||
call :download_and_extract
|
||||
call :install_binary
|
||||
call :verify_install
|
||||
goto :done
|
||||
|
||||
REM === Helper Functions ===
|
||||
|
||||
:find_archive
|
||||
set "_variant=%~1"
|
||||
set "_result=%~2"
|
||||
|
||||
REM Try variant-specific first, then full
|
||||
if not "%_variant%"=="" (
|
||||
set "_try=%BINARY%-%_variant%-windows-amd64.zip"
|
||||
curl -fsSLI "https://github.com/%REPO%/releases/download/!VERSION!/!_try!" 2>nul | findstr /r "HTTP/.* [23]0[02]" >nul
|
||||
if not errorlevel 1 (
|
||||
set "%_result%=!_try!"
|
||||
exit /b 0
|
||||
)
|
||||
echo Using full variant ^(%_variant% variant not available^)
|
||||
)
|
||||
|
||||
set "%_result%=%BINARY%-windows-amd64.zip"
|
||||
exit /b 0
|
||||
|
||||
:download_and_extract
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/!ARCHIVE!" -o "%TEMP%\!ARCHIVE!"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download !ARCHIVE!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\!ARCHIVE!' '%INSTALL_DIR%' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
exit /b 0
|
||||
|
||||
:install_binary
|
||||
REM Add to PATH using PowerShell (avoids setx 1024 char limit)
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
:verify_install
|
||||
if not exist "%INSTALL_DIR%\%BINARY%.exe" (
|
||||
echo ERROR: Installation failed - binary not found
|
||||
exit /b 1
|
||||
)
|
||||
"%INSTALL_DIR%\%BINARY%.exe" --version
|
||||
if errorlevel 1 exit /b 1
|
||||
exit /b 0
|
||||
|
||||
:done
|
||||
endlocal
|
||||
222
install.sh
Normal file
222
install.sh
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
#!/bin/bash
|
||||
# Core CLI unified installer
|
||||
# Served via *.core.help with BunnyCDN edge transformation
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL setup.core.help | bash # Interactive setup (default)
|
||||
# curl -fsSL ci.core.help | bash # CI/CD (minimal, fast)
|
||||
# curl -fsSL dev.core.help | bash # Full development
|
||||
# curl -fsSL go.core.help | bash # Go development variant
|
||||
# curl -fsSL php.core.help | bash # PHP/Laravel variant
|
||||
# curl -fsSL agent.core.help | bash # AI agent variant
|
||||
#
|
||||
# Version override:
|
||||
# curl -fsSL setup.core.help | bash -s -- v1.0.0
|
||||
#
|
||||
set -eo pipefail
|
||||
|
||||
# === BunnyCDN Edge Variables (transformed at edge based on subdomain) ===
|
||||
MODE="{{CORE_MODE}}" # setup, ci, dev, variant
|
||||
VARIANT="{{CORE_VARIANT}}" # go, php, agent (when MODE=variant)
|
||||
|
||||
# === User overrides (fallback for local testing) ===
|
||||
[[ "$MODE" == "{{CORE_MODE}}" ]] && MODE="${CORE_MODE:-setup}"
|
||||
[[ "$VARIANT" == "{{CORE_VARIANT}}" ]] && VARIANT="${CORE_VARIANT:-}"
|
||||
|
||||
# === Configuration ===
|
||||
VERSION="${1:-latest}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
|
||||
# === Colours ===
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
DIM='\033[2m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${BLUE}>>>${NC} $1"; }
|
||||
success() { echo -e "${GREEN}>>>${NC} $1"; }
|
||||
error() { echo -e "${RED}>>>${NC} $1" >&2; exit 1; }
|
||||
dim() { echo -e "${DIM}$1${NC}"; }
|
||||
|
||||
# === Platform Detection ===
|
||||
detect_platform() {
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) error "Unsupported architecture: $ARCH" ;;
|
||||
esac
|
||||
|
||||
case "$OS" in
|
||||
darwin|linux) ;;
|
||||
*) error "Unsupported OS: $OS (use Windows installer for Windows)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# === Version Resolution ===
|
||||
resolve_version() {
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
info "Fetching latest version..."
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
error "Failed to fetch latest version from GitHub API"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# === Download Helpers ===
|
||||
url_exists() {
|
||||
curl -fsSLI "$1" 2>/dev/null | grep -qE "HTTP/.* [23][0-9][0-9]"
|
||||
}
|
||||
|
||||
find_archive() {
|
||||
local base="$1"
|
||||
local variant="$2"
|
||||
|
||||
# Build candidate list (prefer xz over gz, variant over full)
|
||||
local candidates=()
|
||||
if [ -n "$variant" ]; then
|
||||
candidates+=("${base}-${variant}-${OS}-${ARCH}.tar.xz")
|
||||
candidates+=("${base}-${variant}-${OS}-${ARCH}.tar.gz")
|
||||
fi
|
||||
candidates+=("${base}-${OS}-${ARCH}.tar.xz")
|
||||
candidates+=("${base}-${OS}-${ARCH}.tar.gz")
|
||||
|
||||
for archive in "${candidates[@]}"; do
|
||||
local url="https://github.com/${REPO}/releases/download/${VERSION}/${archive}"
|
||||
if url_exists "$url"; then
|
||||
ARCHIVE="$archive"
|
||||
DOWNLOAD_URL="$url"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
error "No compatible archive found for ${OS}/${ARCH}"
|
||||
}
|
||||
|
||||
download_and_extract() {
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
info "Downloading ${ARCHIVE}..."
|
||||
if ! curl -fsSL "$DOWNLOAD_URL" -o "$TMPDIR/$ARCHIVE"; then
|
||||
error "Failed to download ${DOWNLOAD_URL}"
|
||||
fi
|
||||
|
||||
info "Extracting..."
|
||||
case "$ARCHIVE" in
|
||||
*.tar.xz) tar -xJf "$TMPDIR/$ARCHIVE" -C "$TMPDIR" || error "Failed to extract archive" ;;
|
||||
*.tar.gz) tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR" || error "Failed to extract archive" ;;
|
||||
*) error "Unknown archive format: $ARCHIVE" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_binary() {
|
||||
local install_dir="${1:-/usr/local/bin}"
|
||||
|
||||
info "Installing to ${install_dir}..."
|
||||
if [ -w "$install_dir" ]; then
|
||||
mv "$TMPDIR/${BINARY}" "${install_dir}/${BINARY}"
|
||||
else
|
||||
sudo mv "$TMPDIR/${BINARY}" "${install_dir}/${BINARY}"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_install() {
|
||||
if command -v "$BINARY" &>/dev/null; then
|
||||
success "Installed successfully!"
|
||||
dim "$($BINARY --version)"
|
||||
else
|
||||
success "Installed to ${1:-/usr/local/bin}/${BINARY}"
|
||||
dim "Add the directory to your PATH if not already present"
|
||||
fi
|
||||
}
|
||||
|
||||
# === Installation Modes ===
|
||||
|
||||
install_setup() {
|
||||
echo -e "${BOLD}Core CLI Installer${NC}"
|
||||
echo ""
|
||||
|
||||
detect_platform
|
||||
resolve_version
|
||||
|
||||
local install_dir="/usr/local/bin"
|
||||
info "Installing ${BINARY} ${VERSION} for ${OS}/${ARCH}..."
|
||||
find_archive "$BINARY" ""
|
||||
download_and_extract
|
||||
install_binary "$install_dir"
|
||||
verify_install "$install_dir"
|
||||
}
|
||||
|
||||
install_ci() {
|
||||
detect_platform
|
||||
resolve_version
|
||||
|
||||
echo "Installing ${BINARY} ${VERSION} (${OS}/${ARCH})..."
|
||||
find_archive "$BINARY" ""
|
||||
download_and_extract
|
||||
|
||||
# CI: prefer /usr/local/bin, no sudo prompts
|
||||
if [ -w /usr/local/bin ]; then
|
||||
mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
else
|
||||
sudo mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
fi
|
||||
|
||||
${BINARY} --version
|
||||
}
|
||||
|
||||
install_dev() {
|
||||
detect_platform
|
||||
resolve_version
|
||||
|
||||
local install_dir="/usr/local/bin"
|
||||
info "Installing ${BINARY} ${VERSION} (full) for ${OS}/${ARCH}..."
|
||||
find_archive "$BINARY" ""
|
||||
download_and_extract
|
||||
install_binary "$install_dir"
|
||||
verify_install "$install_dir"
|
||||
|
||||
echo ""
|
||||
echo "Full development variant installed. Available commands:"
|
||||
echo " core dev - Multi-repo workflows"
|
||||
echo " core build - Cross-platform builds"
|
||||
echo " core release - Build and publish releases"
|
||||
}
|
||||
|
||||
install_variant() {
|
||||
local variant="$1"
|
||||
|
||||
detect_platform
|
||||
resolve_version
|
||||
|
||||
local install_dir="/usr/local/bin"
|
||||
info "Installing ${BINARY} ${VERSION} (${variant} variant) for ${OS}/${ARCH}..."
|
||||
find_archive "$BINARY" "$variant"
|
||||
|
||||
if [[ "$ARCHIVE" == "${BINARY}-${OS}-${ARCH}"* ]]; then
|
||||
dim "Using full variant (${variant} variant not available for ${VERSION})"
|
||||
fi
|
||||
|
||||
download_and_extract
|
||||
install_binary "$install_dir"
|
||||
verify_install "$install_dir"
|
||||
}
|
||||
|
||||
# === Main ===
|
||||
case "$MODE" in
|
||||
setup) install_setup ;;
|
||||
ci) install_ci ;;
|
||||
dev) install_dev ;;
|
||||
variant)
|
||||
[ -z "$VARIANT" ] && error "VARIANT must be specified when MODE=variant"
|
||||
install_variant "$VARIANT"
|
||||
;;
|
||||
*) error "Unknown mode: $MODE" ;;
|
||||
esac
|
||||
|
|
@ -4,19 +4,49 @@ package build
|
|||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Snider/Borg/pkg/compress"
|
||||
)
|
||||
|
||||
// Archive creates an archive for a single artifact.
|
||||
// ArchiveFormat specifies the compression format for archives.
|
||||
type ArchiveFormat string
|
||||
|
||||
const (
|
||||
// ArchiveFormatGzip uses tar.gz (gzip compression) - widely compatible.
|
||||
ArchiveFormatGzip ArchiveFormat = "gz"
|
||||
// ArchiveFormatXZ uses tar.xz (xz/LZMA2 compression) - better compression ratio.
|
||||
ArchiveFormatXZ ArchiveFormat = "xz"
|
||||
// ArchiveFormatZip uses zip - for Windows.
|
||||
ArchiveFormatZip ArchiveFormat = "zip"
|
||||
)
|
||||
|
||||
// Archive creates an archive for a single artifact using gzip compression.
|
||||
// Uses tar.gz for linux/darwin and zip for windows.
|
||||
// The archive is created alongside the binary (e.g., dist/myapp_linux_amd64.tar.gz).
|
||||
// Returns a new Artifact with Path pointing to the archive.
|
||||
func Archive(artifact Artifact) (Artifact, error) {
|
||||
return ArchiveWithFormat(artifact, ArchiveFormatGzip)
|
||||
}
|
||||
|
||||
// ArchiveXZ creates an archive for a single artifact using xz compression.
|
||||
// Uses tar.xz for linux/darwin and zip for windows.
|
||||
// Returns a new Artifact with Path pointing to the archive.
|
||||
func ArchiveXZ(artifact Artifact) (Artifact, error) {
|
||||
return ArchiveWithFormat(artifact, ArchiveFormatXZ)
|
||||
}
|
||||
|
||||
// ArchiveWithFormat creates an archive for a single artifact with the specified format.
|
||||
// Uses tar.gz or tar.xz for linux/darwin and zip for windows.
|
||||
// The archive is created alongside the binary (e.g., dist/myapp_linux_amd64.tar.xz).
|
||||
// Returns a new Artifact with Path pointing to the archive.
|
||||
func ArchiveWithFormat(artifact Artifact, format ArchiveFormat) (Artifact, error) {
|
||||
if artifact.Path == "" {
|
||||
return Artifact{}, fmt.Errorf("build.Archive: artifact path is empty")
|
||||
}
|
||||
|
|
@ -30,7 +60,7 @@ func Archive(artifact Artifact) (Artifact, error) {
|
|||
return Artifact{}, fmt.Errorf("build.Archive: source path is a directory, expected file")
|
||||
}
|
||||
|
||||
// Determine archive type based on OS
|
||||
// Determine archive type based on OS and format
|
||||
var archivePath string
|
||||
var archiveFunc func(src, dst string) error
|
||||
|
||||
|
|
@ -38,8 +68,14 @@ func Archive(artifact Artifact) (Artifact, error) {
|
|||
archivePath = archiveFilename(artifact, ".zip")
|
||||
archiveFunc = createZipArchive
|
||||
} else {
|
||||
archivePath = archiveFilename(artifact, ".tar.gz")
|
||||
archiveFunc = createTarGzArchive
|
||||
switch format {
|
||||
case ArchiveFormatXZ:
|
||||
archivePath = archiveFilename(artifact, ".tar.xz")
|
||||
archiveFunc = createTarXzArchive
|
||||
default:
|
||||
archivePath = archiveFilename(artifact, ".tar.gz")
|
||||
archiveFunc = createTarGzArchive
|
||||
}
|
||||
}
|
||||
|
||||
// Create the archive
|
||||
|
|
@ -55,16 +91,28 @@ func Archive(artifact Artifact) (Artifact, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// ArchiveAll archives all artifacts.
|
||||
// ArchiveAll archives all artifacts using gzip compression.
|
||||
// Returns a slice of new artifacts pointing to the archives.
|
||||
func ArchiveAll(artifacts []Artifact) ([]Artifact, error) {
|
||||
return ArchiveAllWithFormat(artifacts, ArchiveFormatGzip)
|
||||
}
|
||||
|
||||
// ArchiveAllXZ archives all artifacts using xz compression.
|
||||
// Returns a slice of new artifacts pointing to the archives.
|
||||
func ArchiveAllXZ(artifacts []Artifact) ([]Artifact, error) {
|
||||
return ArchiveAllWithFormat(artifacts, ArchiveFormatXZ)
|
||||
}
|
||||
|
||||
// ArchiveAllWithFormat archives all artifacts with the specified format.
|
||||
// Returns a slice of new artifacts pointing to the archives.
|
||||
func ArchiveAllWithFormat(artifacts []Artifact, format ArchiveFormat) ([]Artifact, error) {
|
||||
if len(artifacts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var archived []Artifact
|
||||
for _, artifact := range artifacts {
|
||||
arch, err := Archive(artifact)
|
||||
arch, err := ArchiveWithFormat(artifact, format)
|
||||
if err != nil {
|
||||
return archived, fmt.Errorf("build.ArchiveAll: failed to archive %s: %w", artifact.Path, err)
|
||||
}
|
||||
|
|
@ -92,6 +140,58 @@ func archiveFilename(artifact Artifact, ext string) string {
|
|||
return filepath.Join(outputDir, archiveName)
|
||||
}
|
||||
|
||||
// createTarXzArchive creates a tar.xz archive containing a single file.
|
||||
// Uses Borg's compress package for xz compression.
|
||||
func createTarXzArchive(src, dst string) error {
|
||||
// Open the source file
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open source file: %w", err)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
srcInfo, err := srcFile.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to stat source file: %w", err)
|
||||
}
|
||||
|
||||
// Create tar archive in memory
|
||||
var tarBuf bytes.Buffer
|
||||
tarWriter := tar.NewWriter(&tarBuf)
|
||||
|
||||
// Create tar header
|
||||
header, err := tar.FileInfoHeader(srcInfo, "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create tar header: %w", err)
|
||||
}
|
||||
header.Name = filepath.Base(src)
|
||||
|
||||
if err := tarWriter.WriteHeader(header); err != nil {
|
||||
return fmt.Errorf("failed to write tar header: %w", err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(tarWriter, srcFile); err != nil {
|
||||
return fmt.Errorf("failed to write file content to tar: %w", err)
|
||||
}
|
||||
|
||||
if err := tarWriter.Close(); err != nil {
|
||||
return fmt.Errorf("failed to close tar writer: %w", err)
|
||||
}
|
||||
|
||||
// Compress with xz using Borg
|
||||
xzData, err := compress.Compress(tarBuf.Bytes(), "xz")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compress with xz: %w", err)
|
||||
}
|
||||
|
||||
// Write to destination file
|
||||
if err := os.WriteFile(dst, xzData, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write archive file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createTarGzArchive creates a tar.gz archive containing a single file.
|
||||
func createTarGzArchive(src, dst string) error {
|
||||
// Open the source file
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package build
|
|||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/Snider/Borg/pkg/compress"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -113,6 +115,64 @@ func TestArchive_Good(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Equal(t, "abc123", result.Checksum)
|
||||
})
|
||||
|
||||
t.Run("creates tar.xz for linux with ArchiveXZ", func(t *testing.T) {
|
||||
binaryPath, outputDir := setupArchiveTestFile(t, "myapp", "linux", "amd64")
|
||||
|
||||
artifact := Artifact{
|
||||
Path: binaryPath,
|
||||
OS: "linux",
|
||||
Arch: "amd64",
|
||||
}
|
||||
|
||||
result, err := ArchiveXZ(artifact)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPath := filepath.Join(outputDir, "myapp_linux_amd64.tar.xz")
|
||||
assert.Equal(t, expectedPath, result.Path)
|
||||
assert.FileExists(t, result.Path)
|
||||
|
||||
verifyTarXzContent(t, result.Path, "myapp")
|
||||
})
|
||||
|
||||
t.Run("creates tar.xz for darwin with ArchiveWithFormat", func(t *testing.T) {
|
||||
binaryPath, outputDir := setupArchiveTestFile(t, "myapp", "darwin", "arm64")
|
||||
|
||||
artifact := Artifact{
|
||||
Path: binaryPath,
|
||||
OS: "darwin",
|
||||
Arch: "arm64",
|
||||
}
|
||||
|
||||
result, err := ArchiveWithFormat(artifact, ArchiveFormatXZ)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPath := filepath.Join(outputDir, "myapp_darwin_arm64.tar.xz")
|
||||
assert.Equal(t, expectedPath, result.Path)
|
||||
assert.FileExists(t, result.Path)
|
||||
|
||||
verifyTarXzContent(t, result.Path, "myapp")
|
||||
})
|
||||
|
||||
t.Run("windows still uses zip even with xz format", func(t *testing.T) {
|
||||
binaryPath, outputDir := setupArchiveTestFile(t, "myapp.exe", "windows", "amd64")
|
||||
|
||||
artifact := Artifact{
|
||||
Path: binaryPath,
|
||||
OS: "windows",
|
||||
Arch: "amd64",
|
||||
}
|
||||
|
||||
result, err := ArchiveWithFormat(artifact, ArchiveFormatXZ)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Windows should still get .zip regardless of format
|
||||
expectedPath := filepath.Join(outputDir, "myapp_windows_amd64.zip")
|
||||
assert.Equal(t, expectedPath, result.Path)
|
||||
assert.FileExists(t, result.Path)
|
||||
|
||||
verifyZipContent(t, result.Path, "myapp.exe")
|
||||
})
|
||||
}
|
||||
|
||||
func TestArchive_Bad(t *testing.T) {
|
||||
|
|
@ -306,3 +366,27 @@ func verifyZipContent(t *testing.T, archivePath, expectedName string) {
|
|||
require.Len(t, reader.File, 1)
|
||||
assert.Equal(t, expectedName, reader.File[0].Name)
|
||||
}
|
||||
|
||||
// verifyTarXzContent opens a tar.xz file and verifies it contains the expected file.
|
||||
func verifyTarXzContent(t *testing.T, archivePath, expectedName string) {
|
||||
t.Helper()
|
||||
|
||||
// Read the xz-compressed file
|
||||
xzData, err := os.ReadFile(archivePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Decompress with Borg
|
||||
tarData, err := compress.Decompress(xzData)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read tar archive
|
||||
tarReader := tar.NewReader(bytes.NewReader(tarData))
|
||||
|
||||
header, err := tarReader.Next()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedName, header.Name)
|
||||
|
||||
// Verify there's only one file
|
||||
_, err = tarReader.Next()
|
||||
assert.Equal(t, io.EOF, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
@echo off
|
||||
REM Core CLI installer - AI agent variant (Windows)
|
||||
REM Usage: curl -fsSL https://core.io.in/agent.bat -o agent.bat && agent.bat
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
set "VARIANT=agent"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\Programs\core"
|
||||
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
if "%VERSION%"=="latest" (
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo ERROR: Failed to fetch latest version
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo ERROR: Failed to resolve version
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo Installing %BINARY% !VERSION! (%VARIANT% variant)...
|
||||
|
||||
set "ARCHIVE=%BINARY%-%VARIANT%-windows-amd64.zip"
|
||||
set "URL=https://github.com/%REPO%/releases/download/!VERSION!/%ARCHIVE%"
|
||||
|
||||
curl -fsSLI "%URL%" 2>nul | findstr /r "HTTP/.* [23]0[02]" >nul
|
||||
if errorlevel 1 (
|
||||
set "ARCHIVE=%BINARY%-windows-amd64.zip"
|
||||
echo Using full variant (%VARIANT% variant not available^)
|
||||
)
|
||||
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/!ARCHIVE!" -o "%TEMP%\!ARCHIVE!"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download !ARCHIVE!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\!ARCHIVE!' '%INSTALL_DIR%' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
|
||||
REM Add to PATH using PowerShell (avoids setx 1024 char limit)
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
|
||||
if not exist "%INSTALL_DIR%\%BINARY%.exe" (
|
||||
echo ERROR: Installation failed - binary not found
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
"%INSTALL_DIR%\%BINARY%.exe" --version
|
||||
if errorlevel 1 exit /b 1
|
||||
|
||||
endlocal
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Core CLI installer - AI agent variant
|
||||
# Usage: curl -fsSL https://core.io.in/agent.sh | bash
|
||||
set -eo pipefail
|
||||
|
||||
VERSION="${VERSION:-${1:-latest}}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
VARIANT="agent"
|
||||
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Failed to fetch latest version from GitHub API" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing ${BINARY} ${VERSION} (${VARIANT} variant) for ${OS}/${ARCH}..."
|
||||
|
||||
# Download variant-specific archive if available, else fall back to full
|
||||
ARCHIVE="${BINARY}-${VARIANT}-${OS}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
|
||||
if ! curl -fsSLI "$URL" 2>/dev/null | grep -qE "^HTTP/.* (200|302)"; then
|
||||
ARCHIVE="${BINARY}-${OS}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
echo "Using full variant (${VARIANT} variant not available for ${VERSION})"
|
||||
fi
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
if ! curl -fsSL "$URL" -o "$TMPDIR/$ARCHIVE"; then
|
||||
echo "Failed to download ${ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
|
||||
|
||||
[ -w /usr/local/bin ] && mv "$TMPDIR/${BINARY}" /usr/local/bin/ || sudo mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
|
||||
${BINARY} --version
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
@echo off
|
||||
REM Core CLI installer for Windows CI environments
|
||||
REM Usage: curl -fsSL https://core.io.in/ci.bat -o ci.bat && ci.bat
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
|
||||
if "%VERSION%"=="latest" (
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo ERROR: Failed to fetch latest version from GitHub API
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo ERROR: Failed to fetch latest version from GitHub API
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo Installing %BINARY% !VERSION!...
|
||||
|
||||
set "ARCHIVE=%BINARY%-windows-amd64.zip"
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/%ARCHIVE%" -o "%TEMP%\%ARCHIVE%"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download %ARCHIVE%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\%ARCHIVE%' '%TEMP%\core-extract' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\%ARCHIVE%" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Try System32 first (CI runners often have admin), else use local programs
|
||||
move /y "%TEMP%\core-extract\%BINARY%.exe" "C:\Windows\System32\%BINARY%.exe" >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
if not exist "%LOCALAPPDATA%\Programs" mkdir "%LOCALAPPDATA%\Programs"
|
||||
move /y "%TEMP%\core-extract\%BINARY%.exe" "%LOCALAPPDATA%\Programs\%BINARY%.exe"
|
||||
set "PATH=%LOCALAPPDATA%\Programs;%PATH%"
|
||||
echo NOTE: Installed to %LOCALAPPDATA%\Programs
|
||||
)
|
||||
rmdir /s /q "%TEMP%\core-extract" 2>nul
|
||||
del "%TEMP%\%ARCHIVE%" 2>nul
|
||||
|
||||
%BINARY% --version || exit /b 1
|
||||
|
||||
endlocal
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Core CLI installer for CI environments
|
||||
# Minimal, fast, no interactive prompts
|
||||
# Usage: curl -fsSL https://core.io.in/ci.sh | bash
|
||||
# VERSION=v1.0.0 curl -fsSL https://core.io.in/ci.sh | bash
|
||||
set -eo pipefail
|
||||
|
||||
VERSION="${VERSION:-${1:-latest}}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
|
||||
# Detect platform
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Resolve latest
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Failed to fetch latest version from GitHub API" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing ${BINARY} ${VERSION} (${OS}/${ARCH})..."
|
||||
|
||||
# Download and extract to secure temp dir
|
||||
ARCHIVE="${BINARY}-${OS}-${ARCH}.tar.gz"
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
if ! curl -fsSL "https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}" -o "$TMPDIR/$ARCHIVE"; then
|
||||
echo "Failed to download ${ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
|
||||
|
||||
# Install (CI runners typically have write access to /usr/local/bin)
|
||||
if [ -w /usr/local/bin ]; then
|
||||
mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
else
|
||||
sudo mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
fi
|
||||
|
||||
${BINARY} --version
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
@echo off
|
||||
REM Core CLI installer - Multi-repo development variant (Windows)
|
||||
REM Usage: curl -fsSL https://core.io.in/dev.bat -o dev.bat && dev.bat
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\Programs\core"
|
||||
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
if "%VERSION%"=="latest" (
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo ERROR: Failed to fetch latest version
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo ERROR: Failed to resolve version
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo Installing %BINARY% !VERSION! (full) for Windows...
|
||||
|
||||
set "ARCHIVE=%BINARY%-windows-amd64.zip"
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/%ARCHIVE%" -o "%TEMP%\%ARCHIVE%"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download %ARCHIVE%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\%ARCHIVE%' '%INSTALL_DIR%' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\%ARCHIVE%" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
del "%TEMP%\%ARCHIVE%" 2>nul
|
||||
|
||||
REM Add to PATH using PowerShell (avoids setx 1024 char limit)
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
|
||||
if not exist "%INSTALL_DIR%\%BINARY%.exe" (
|
||||
echo ERROR: Installation failed - binary not found
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
"%INSTALL_DIR%\%BINARY%.exe" --version
|
||||
if errorlevel 1 exit /b 1
|
||||
|
||||
echo.
|
||||
echo Full development variant installed. Available commands:
|
||||
echo core dev - Multi-repo workflows
|
||||
echo core build - Cross-platform builds
|
||||
echo core release - Build and publish releases
|
||||
|
||||
endlocal
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Core CLI installer - Multi-repo development variant (full)
|
||||
# Usage: curl -fsSL https://core.io.in/dev.sh | bash
|
||||
set -eo pipefail
|
||||
|
||||
VERSION="${VERSION:-${1:-latest}}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Failed to fetch latest version from GitHub API" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing ${BINARY} ${VERSION} (full) for ${OS}/${ARCH}..."
|
||||
|
||||
ARCHIVE="${BINARY}-${OS}-${ARCH}.tar.gz"
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
if ! curl -fsSL "https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}" -o "$TMPDIR/$ARCHIVE"; then
|
||||
echo "Failed to download ${ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
|
||||
|
||||
[ -w /usr/local/bin ] && mv "$TMPDIR/${BINARY}" /usr/local/bin/ || sudo mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
|
||||
${BINARY} --version
|
||||
|
||||
echo ""
|
||||
echo "Full development variant installed. Available commands:"
|
||||
echo " core dev - Multi-repo workflows"
|
||||
echo " core build - Cross-platform builds"
|
||||
echo " core release - Build and publish releases"
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
@echo off
|
||||
REM Core CLI installer - Go development variant (Windows)
|
||||
REM Usage: curl -fsSL https://core.io.in/go.bat -o go.bat && go.bat
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
set "VARIANT=go"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\Programs\core"
|
||||
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
if "%VERSION%"=="latest" (
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo ERROR: Failed to fetch latest version
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo ERROR: Failed to resolve version
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo Installing %BINARY% !VERSION! (%VARIANT% variant)...
|
||||
|
||||
set "ARCHIVE=%BINARY%-%VARIANT%-windows-amd64.zip"
|
||||
set "URL=https://github.com/%REPO%/releases/download/!VERSION!/%ARCHIVE%"
|
||||
|
||||
curl -fsSLI "%URL%" 2>nul | findstr /r "HTTP/.* [23]0[02]" >nul
|
||||
if errorlevel 1 (
|
||||
set "ARCHIVE=%BINARY%-windows-amd64.zip"
|
||||
echo Using full variant (%VARIANT% variant not available^)
|
||||
)
|
||||
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/!ARCHIVE!" -o "%TEMP%\!ARCHIVE!"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download !ARCHIVE!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\!ARCHIVE!' '%INSTALL_DIR%' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
|
||||
REM Add to PATH using PowerShell (avoids setx 1024 char limit)
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
|
||||
if not exist "%INSTALL_DIR%\%BINARY%.exe" (
|
||||
echo ERROR: Installation failed - binary not found
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
"%INSTALL_DIR%\%BINARY%.exe" --version
|
||||
if errorlevel 1 exit /b 1
|
||||
|
||||
endlocal
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Core CLI installer - Go development variant
|
||||
# Usage: curl -fsSL https://core.io.in/go.sh | bash
|
||||
set -eo pipefail
|
||||
|
||||
VERSION="${VERSION:-${1:-latest}}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
VARIANT="go"
|
||||
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Failed to fetch latest version from GitHub API" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing ${BINARY} ${VERSION} (${VARIANT} variant) for ${OS}/${ARCH}..."
|
||||
|
||||
# Download variant-specific archive if available, else fall back to full
|
||||
ARCHIVE="${BINARY}-${VARIANT}-${OS}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
|
||||
if ! curl -fsSLI "$URL" 2>/dev/null | grep -qE "^HTTP/.* (200|302)"; then
|
||||
# Fall back to full variant
|
||||
ARCHIVE="${BINARY}-${OS}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
echo "Using full variant (${VARIANT} variant not available for ${VERSION})"
|
||||
fi
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
if ! curl -fsSL "$URL" -o "$TMPDIR/$ARCHIVE"; then
|
||||
echo "Failed to download ${ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
|
||||
|
||||
[ -w /usr/local/bin ] && mv "$TMPDIR/${BINARY}" /usr/local/bin/ || sudo mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
|
||||
${BINARY} --version
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
@echo off
|
||||
REM Core CLI installer - PHP/Laravel development variant (Windows)
|
||||
REM Usage: curl -fsSL https://core.io.in/php.bat -o php.bat && php.bat
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
set "VARIANT=php"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\Programs\core"
|
||||
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
if "%VERSION%"=="latest" (
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo ERROR: Failed to fetch latest version
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo ERROR: Failed to resolve version
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo Installing %BINARY% !VERSION! (%VARIANT% variant)...
|
||||
|
||||
set "ARCHIVE=%BINARY%-%VARIANT%-windows-amd64.zip"
|
||||
set "URL=https://github.com/%REPO%/releases/download/!VERSION!/%ARCHIVE%"
|
||||
|
||||
curl -fsSLI "%URL%" 2>nul | findstr /r "HTTP/.* [23]0[02]" >nul
|
||||
if errorlevel 1 (
|
||||
set "ARCHIVE=%BINARY%-windows-amd64.zip"
|
||||
echo Using full variant (%VARIANT% variant not available^)
|
||||
)
|
||||
|
||||
curl -fsSL "https://github.com/%REPO%/releases/download/!VERSION!/!ARCHIVE!" -o "%TEMP%\!ARCHIVE!"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to download !ARCHIVE!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
powershell -Command "try { Expand-Archive -Force '%TEMP%\!ARCHIVE!' '%INSTALL_DIR%' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to extract archive
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
del "%TEMP%\!ARCHIVE!" 2>nul
|
||||
|
||||
REM Add to PATH using PowerShell (avoids setx 1024 char limit)
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
|
||||
if not exist "%INSTALL_DIR%\%BINARY%.exe" (
|
||||
echo ERROR: Installation failed - binary not found
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
"%INSTALL_DIR%\%BINARY%.exe" --version
|
||||
if errorlevel 1 exit /b 1
|
||||
|
||||
endlocal
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Core CLI installer - PHP/Laravel development variant
|
||||
# Usage: curl -fsSL https://core.io.in/php.sh | bash
|
||||
set -eo pipefail
|
||||
|
||||
VERSION="${VERSION:-${1:-latest}}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
VARIANT="php"
|
||||
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Failed to fetch latest version from GitHub API" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing ${BINARY} ${VERSION} (${VARIANT} variant) for ${OS}/${ARCH}..."
|
||||
|
||||
# Download variant-specific archive if available, else fall back to full
|
||||
ARCHIVE="${BINARY}-${VARIANT}-${OS}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
|
||||
if ! curl -fsSLI "$URL" 2>/dev/null | grep -qE "^HTTP/.* (200|302)"; then
|
||||
ARCHIVE="${BINARY}-${OS}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
echo "Using full variant (${VARIANT} variant not available for ${VERSION})"
|
||||
fi
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
if ! curl -fsSL "$URL" -o "$TMPDIR/$ARCHIVE"; then
|
||||
echo "Failed to download ${ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
|
||||
|
||||
[ -w /usr/local/bin ] && mv "$TMPDIR/${BINARY}" /usr/local/bin/ || sudo mv "$TMPDIR/${BINARY}" /usr/local/bin/
|
||||
|
||||
${BINARY} --version
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
@echo off
|
||||
REM Core CLI installer for Windows
|
||||
REM Usage: curl -fsSL https://core.io.in/setup.bat -o setup.bat && setup.bat
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
if "%VERSION%"=="" set "VERSION=latest"
|
||||
set "REPO=host-uk/core"
|
||||
set "BINARY=core"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\Programs\core"
|
||||
|
||||
echo [94m>>>[0m Installing Core CLI for Windows...
|
||||
|
||||
REM Create install directory
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
REM Resolve latest version if needed
|
||||
if "%VERSION%"=="latest" (
|
||||
echo [94m>>>[0m Fetching latest version...
|
||||
for /f "tokens=2 delims=:" %%a in ('curl -fsSL "https://api.github.com/repos/%REPO%/releases/latest" ^| findstr "tag_name"') do (
|
||||
set "VERSION=%%a"
|
||||
set "VERSION=!VERSION:"=!"
|
||||
set "VERSION=!VERSION: =!"
|
||||
set "VERSION=!VERSION:,=!"
|
||||
)
|
||||
if "!VERSION!"=="" (
|
||||
echo [91m>>>[0m Failed to fetch latest version
|
||||
exit /b 1
|
||||
)
|
||||
if "!VERSION!"=="latest" (
|
||||
echo [91m>>>[0m Failed to resolve version
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo [94m>>>[0m Installing %BINARY% !VERSION!...
|
||||
|
||||
REM Download archive
|
||||
set "ARCHIVE=%BINARY%-windows-amd64.zip"
|
||||
set "DOWNLOAD_URL=https://github.com/%REPO%/releases/download/!VERSION!/%ARCHIVE%"
|
||||
set "TMP_FILE=%TEMP%\%ARCHIVE%"
|
||||
|
||||
echo [94m>>>[0m Downloading %ARCHIVE%...
|
||||
curl -fsSL "%DOWNLOAD_URL%" -o "%TMP_FILE%"
|
||||
if errorlevel 1 (
|
||||
echo [91m>>>[0m Failed to download %DOWNLOAD_URL%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Extract
|
||||
echo [94m>>>[0m Extracting...
|
||||
powershell -Command "try { Expand-Archive -Force '%TMP_FILE%' '%INSTALL_DIR%' } catch { exit 1 }"
|
||||
if errorlevel 1 (
|
||||
echo [91m>>>[0m Failed to extract archive
|
||||
del "%TMP_FILE%" 2>nul
|
||||
exit /b 1
|
||||
)
|
||||
del "%TMP_FILE%" 2>nul
|
||||
|
||||
REM Add to PATH using PowerShell (avoids setx 1024 char limit)
|
||||
echo %PATH% | findstr /i /c:"%INSTALL_DIR%" >nul
|
||||
if errorlevel 1 (
|
||||
echo [94m>>>[0m Adding to PATH...
|
||||
powershell -Command "[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ';%INSTALL_DIR%', 'User')"
|
||||
set "PATH=%PATH%;%INSTALL_DIR%"
|
||||
)
|
||||
|
||||
REM Verify
|
||||
if not exist "%INSTALL_DIR%\%BINARY%.exe" (
|
||||
echo [91m>>>[0m Installation failed - binary not found
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
"%INSTALL_DIR%\%BINARY%.exe" --version
|
||||
if errorlevel 1 (
|
||||
echo [91m>>>[0m Installation verification failed
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [92m>>>[0m Installed successfully!
|
||||
echo.
|
||||
echo [90mRestart your terminal to use '%BINARY%' command[0m
|
||||
|
||||
endlocal
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Core CLI installer for macOS and Linux
|
||||
# Usage: curl -fsSL https://core.io.in/setup.sh | bash
|
||||
# curl -fsSL https://core.io.in/setup.sh | bash -s -- v1.0.0
|
||||
set -eo pipefail
|
||||
|
||||
VERSION="${1:-latest}"
|
||||
REPO="host-uk/core"
|
||||
BINARY="core"
|
||||
INSTALL_DIR="${CORE_INSTALL_DIR:-/usr/local/bin}"
|
||||
|
||||
# Colours
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
DIM='\033[2m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${BLUE}>>>${NC} $1"; }
|
||||
success() { echo -e "${GREEN}>>>${NC} $1"; }
|
||||
error() { echo -e "${RED}>>>${NC} $1" >&2; exit 1; }
|
||||
|
||||
# Detect OS and architecture
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) ARCH="amd64" ;;
|
||||
arm64|aarch64) ARCH="arm64" ;;
|
||||
*) error "Unsupported architecture: $ARCH" ;;
|
||||
esac
|
||||
|
||||
case "$OS" in
|
||||
darwin|linux) ;;
|
||||
*) error "Unsupported OS: $OS (use setup.bat for Windows)" ;;
|
||||
esac
|
||||
|
||||
# Resolve latest version
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
info "Fetching latest version..."
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$VERSION" ]; then
|
||||
error "Failed to fetch latest version"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Installing ${BINARY} ${VERSION} for ${OS}/${ARCH}..."
|
||||
|
||||
# Download archive
|
||||
ARCHIVE="${BINARY}-${OS}-${ARCH}.tar.gz"
|
||||
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
info "Downloading ${ARCHIVE}..."
|
||||
if ! curl -fsSL "$DOWNLOAD_URL" -o "${TMP_DIR}/${ARCHIVE}"; then
|
||||
error "Failed to download ${DOWNLOAD_URL}"
|
||||
fi
|
||||
|
||||
# Extract
|
||||
info "Extracting..."
|
||||
tar -xzf "${TMP_DIR}/${ARCHIVE}" -C "$TMP_DIR"
|
||||
chmod +x "${TMP_DIR}/${BINARY}"
|
||||
|
||||
# Install
|
||||
info "Installing to ${INSTALL_DIR}..."
|
||||
if [ -w "$INSTALL_DIR" ]; then
|
||||
mv "${TMP_DIR}/${BINARY}" "${INSTALL_DIR}/${BINARY}"
|
||||
else
|
||||
sudo mv "${TMP_DIR}/${BINARY}" "${INSTALL_DIR}/${BINARY}"
|
||||
fi
|
||||
|
||||
# Verify
|
||||
if command -v "$BINARY" &>/dev/null; then
|
||||
success "Installed successfully!"
|
||||
echo -e "${DIM}$($BINARY --version)${NC}"
|
||||
else
|
||||
success "Installed to ${INSTALL_DIR}/${BINARY}"
|
||||
echo -e "${DIM}Add ${INSTALL_DIR} to your PATH if not already present${NC}"
|
||||
fi
|
||||
Loading…
Add table
Reference in a new issue