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/pretty v1.2.1 // indirect
|
||||||
github.com/tidwall/sjson v1.2.5 // indirect
|
github.com/tidwall/sjson v1.2.5 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.0 // 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/wI2L/jsondiff v0.7.0 // indirect
|
||||||
github.com/woodsbury/decimal128 v1.4.0 // indirect
|
github.com/woodsbury/decimal128 v1.4.0 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // 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/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 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
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 h1:1lH1G37GhBPqCfp/lrs91rf/2j3DktX6qYAKZkLuCQQ=
|
||||||
github.com/wI2L/jsondiff v0.7.0/go.mod h1:KAEIojdQq66oJiHhDyQez2x+sRit0vIzC9KeK0yizxM=
|
github.com/wI2L/jsondiff v0.7.0/go.mod h1:KAEIojdQq66oJiHhDyQez2x+sRit0vIzC9KeK0yizxM=
|
||||||
github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc=
|
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 (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"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.
|
// 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).
|
// 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.
|
// Returns a new Artifact with Path pointing to the archive.
|
||||||
func Archive(artifact Artifact) (Artifact, error) {
|
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 == "" {
|
if artifact.Path == "" {
|
||||||
return Artifact{}, fmt.Errorf("build.Archive: artifact path is empty")
|
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")
|
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 archivePath string
|
||||||
var archiveFunc func(src, dst string) error
|
var archiveFunc func(src, dst string) error
|
||||||
|
|
||||||
|
|
@ -38,8 +68,14 @@ func Archive(artifact Artifact) (Artifact, error) {
|
||||||
archivePath = archiveFilename(artifact, ".zip")
|
archivePath = archiveFilename(artifact, ".zip")
|
||||||
archiveFunc = createZipArchive
|
archiveFunc = createZipArchive
|
||||||
} else {
|
} else {
|
||||||
archivePath = archiveFilename(artifact, ".tar.gz")
|
switch format {
|
||||||
archiveFunc = createTarGzArchive
|
case ArchiveFormatXZ:
|
||||||
|
archivePath = archiveFilename(artifact, ".tar.xz")
|
||||||
|
archiveFunc = createTarXzArchive
|
||||||
|
default:
|
||||||
|
archivePath = archiveFilename(artifact, ".tar.gz")
|
||||||
|
archiveFunc = createTarGzArchive
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the archive
|
// Create the archive
|
||||||
|
|
@ -55,16 +91,28 @@ func Archive(artifact Artifact) (Artifact, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArchiveAll archives all artifacts.
|
// ArchiveAll archives all artifacts using gzip compression.
|
||||||
// Returns a slice of new artifacts pointing to the archives.
|
// Returns a slice of new artifacts pointing to the archives.
|
||||||
func ArchiveAll(artifacts []Artifact) ([]Artifact, error) {
|
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 {
|
if len(artifacts) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var archived []Artifact
|
var archived []Artifact
|
||||||
for _, artifact := range artifacts {
|
for _, artifact := range artifacts {
|
||||||
arch, err := Archive(artifact)
|
arch, err := ArchiveWithFormat(artifact, format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return archived, fmt.Errorf("build.ArchiveAll: failed to archive %s: %w", artifact.Path, err)
|
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)
|
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.
|
// createTarGzArchive creates a tar.gz archive containing a single file.
|
||||||
func createTarGzArchive(src, dst string) error {
|
func createTarGzArchive(src, dst string) error {
|
||||||
// Open the source file
|
// Open the source file
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@ package build
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Snider/Borg/pkg/compress"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
@ -113,6 +115,64 @@ func TestArchive_Good(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "abc123", result.Checksum)
|
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) {
|
func TestArchive_Bad(t *testing.T) {
|
||||||
|
|
@ -306,3 +366,27 @@ func verifyZipContent(t *testing.T, archivePath, expectedName string) {
|
||||||
require.Len(t, reader.File, 1)
|
require.Len(t, reader.File, 1)
|
||||||
assert.Equal(t, expectedName, reader.File[0].Name)
|
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