gitlink-cli/install.sh

436 lines
13 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# GitLink CLI 一键安装脚本(改进版)
# 自动检测平台,下载预编译二进制,安装 skills
# 用法: curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
# 支持: VERSION=0.1.0 INSTALL_DIR=$HOME/.local/bin bash install.sh
set -e
REPO_OWNER="Gitlink"
REPO_NAME="gitlink-cli"
BINARY_NAME="gitlink-cli"
API_BASE="https://www.gitlink.org.cn"
INSTALL_DIR="${INSTALL_DIR:-auto}"
SKILLS_DIR="${HOME}/.gitlink/skills"
VERSION="${VERSION:-latest}"
MAX_ATTEMPTS=3
DEBUG="${DEBUG:-false}"
# ---------- 颜色输出 ----------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BLUE='\033[0;34m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; }
step() { echo -e "${CYAN}[STEP]${NC} $*"; }
debug() { [[ "${DEBUG}" == "true" ]] && echo -e "${BLUE}[DEBUG]${NC} $*"; }
# ---------- 环境检测 ----------
check_environment() {
step "检查安装环境..."
# 检查必需命令
local required_commands=("curl" "tar")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
error "缺少必需命令: $cmd"
error "请安装后再试:"
error " Ubuntu/Debian: sudo apt-get install $cmd"
error " CentOS/RHEL: sudo yum install $cmd"
error " macOS: brew install $cmd"
exit 1
fi
done
debug "必需命令检查通过"
# 检查磁盘空间至少50MB
local available_space
available_space=$(df -m "$HOME" | tail -1 | awk '{print $4}')
if [ "$available_space" -lt 50 ]; then
error "磁盘空间不足需要至少50MB可用: ${available_space}MB"
exit 1
fi
debug "磁盘空间检查通过: ${available_space}MB"
# 检查网络连接
if ! curl -sSL --connect-timeout 5 "${API_BASE}" >/dev/null 2>&1; then
error "无法连接到 GitLink 服务器: ${API_BASE}"
error "请检查网络连接"
exit 1
fi
debug "网络连接检查通过"
info "环境检查通过"
}
# ---------- 智能权限处理 ----------
select_install_dir() {
local dirs=("$HOME/.local/bin" "$HOME/bin" "/usr/local/bin")
local selected_dir=""
if [ "${INSTALL_DIR}" != "auto" ]; then
echo "${INSTALL_DIR}"
return
fi
step "选择安装目录..."
# 优先级:用户目录 > 系统目录
for dir in "${dirs[@]}"; do
if [ -w "$dir" ] 2>/dev/null || mkdir -p "$dir" 2>/dev/null; then
selected_dir="$dir"
info "选择用户目录: $selected_dir"
break
fi
done
# 如果用户目录都不可写,尝试系统目录
if [ -z "$selected_dir" ]; then
warn "无法写入用户目录将使用系统目录需要sudo权限"
selected_dir="/usr/local/bin"
fi
echo "$selected_dir"
}
# ---------- 下载重试机制 ----------
download_with_retry() {
local url="$1"
local output="$2"
local attempt=1
while [ $attempt -le $MAX_ATTEMPTS ]; do
step "下载 (尝试 $attempt/$MAX_ATTEMPTS): $(basename "$url")"
if curl -sSL --connect-timeout 10 --max-time 120 --progress-bar "$url" -o "$output" 2>&1; then
if [ -s "$output" ]; then
info "下载成功: $(basename "$output") ($(du -h "$output" | cut -f1))"
return 0
else
warn "下载文件为空"
fi
else
warn "下载失败"
fi
if [ $attempt -lt $MAX_ATTEMPTS ]; then
local wait_time=$((attempt * 2))
warn "等待 ${wait_time}s 后重试..."
sleep $wait_time
fi
attempt=$((attempt + 1))
done
error "下载失败,已尝试 $MAX_ATTEMPTS"
error "URL: $url"
error "请检查网络连接或手动下载"
return 1
}
# ---------- 平台检测 ----------
detect_platform() {
local os arch
case "$(uname -s)" in
Linux) os="linux" ;;
Darwin) os="darwin" ;;
MINGW*|MSYS*|CYGWIN*) os="windows" ;;
*) error "不支持的操作系统: $(uname -s)"; exit 1 ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch="amd64" ;;
aarch64|arm64) arch="arm64" ;;
*) error "不支持的架构: $(uname -m)"; exit 1 ;;
esac
echo "${os}/${arch}"
}
# ---------- 获取最新版本 ----------
fetch_latest_version() {
local releases_url="${API_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases.json"
info "获取最新版本..."
local releases
releases=$(curl -sSL --connect-timeout 10 --max-time 30 "${releases_url}" 2>/dev/null || true)
if [ -z "$releases" ]; then
error "无法获取发布列表: ${releases_url}"
exit 1
fi
# 尝试解析第一个 release 的 tag_name
local tag
tag=$(echo "$releases" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
if [ -z "$tag" ]; then
# 备选:尝试直接匹配数组第一个元素的 tag_name
tag=$(echo "$releases" | grep -oP '"tag_name"\s*:\s*"\K[^"]+' | head -1)
fi
echo "${tag:-v0.1.0}"
}
# ---------- 显示已安装版本 ----------
show_installed_version() {
if command -v "${BINARY_NAME}" >/dev/null 2>&1; then
"${BINARY_NAME}" version 2>/dev/null || echo "未知版本"
elif [ -x "${INSTALL_DIR}/${BINARY_NAME}" ]; then
"${INSTALL_DIR}/${BINARY_NAME}" version 2>/dev/null || echo "未知版本"
else
echo "未安装"
fi
}
# ---------- 列出可用版本 ----------
list_versions() {
step "查询可用版本..."
local releases_url="${API_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases.json"
curl -sSL "$releases_url" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/' | head -10
}
# ---------- 回滚功能 ----------
rollback_version() {
local target_version="$1"
if [ -z "$target_version" ]; then
error "请指定要回滚到的版本"
exit 1
fi
step "回滚到版本: ${target_version}"
# 重新安装指定版本
VERSION="$target_version"
main
}
# ---------- 卸载功能 ----------
uninstall() {
step "卸载 ${BINARY_NAME}..."
# 删除二进制
if [ -f "${INSTALL_DIR}/${BINARY_NAME}" ]; then
if [ -w "${INSTALL_DIR}" ]; then
rm -f "${INSTALL_DIR}/${BINARY_NAME}"
info "已删除: ${INSTALL_DIR}/${BINARY_NAME}"
else
sudo rm -f "${INSTALL_DIR}/${BINARY_NAME}"
info "已删除: ${INSTALL_DIR}/${BINARY_NAME} (使用sudo)"
fi
fi
# 删除skills
if [ -d "${SKILLS_DIR}" ]; then
rm -rf "${SKILLS_DIR}"
info "已删除: ${SKILLS_DIR}"
fi
# 删除配置(可选)
echo -n "是否删除配置文件? [y/N] "
read -r response
if [[ "$response" =~ ^[Yy]$ ]]; then
rm -rf "$HOME/.config/gitlink-cli"
rm -rf "$HOME/.gitlink"
info "已删除配置文件"
fi
info "卸载完成"
exit 0
}
# ---------- 下载二进制 ----------
download_binary() {
local platform="$1"
local version="$2"
local os="${platform%/*}"
local arch="${platform#*/}"
local archive_name="${BINARY_NAME}_${version}_${os}_${arch}.tar.gz"
local download_url="${API_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases/${version}/assets/${archive_name}"
info "下载: ${archive_name}"
debug "URL: ${download_url}"
local tmpdir
tmpdir="$(mktemp -d)"
trap "rm -rf ${tmpdir}" EXIT
if ! download_with_retry "${download_url}" "${tmpdir}/${archive_name}"; then
error "请确认以下版本已发布: ${version}"
error "发布页: ${API_BASE}/${REPO_OWNER}/${REPO_NAME}/releases"
exit 1
fi
step "解压..."
tar -xzf "${tmpdir}/${archive_name}" -C "${tmpdir}"
local binary_path="${tmpdir}/${BINARY_NAME}"
if [ ! -f "${binary_path}" ]; then
# 可能在子目录中
binary_path=$(find "${tmpdir}" -name "${BINARY_NAME}" -type f 2>/dev/null | head -1)
fi
if [ ! -f "${binary_path}" ]; then
error "解压后未找到二进制文件"
exit 1
fi
chmod +x "${binary_path}"
# ---------- 安装 ----------
step "安装到 ${INSTALL_DIR}/${BINARY_NAME}"
if [ ! -w "${INSTALL_DIR}" ]; then
warn "需要管理员权限写入 ${INSTALL_DIR}"
sudo mkdir -p "${INSTALL_DIR}"
sudo mv "${binary_path}" "${INSTALL_DIR}/${BINARY_NAME}"
sudo chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
else
mkdir -p "${INSTALL_DIR}"
mv "${binary_path}" "${INSTALL_DIR}/${BINARY_NAME}"
fi
info "二进制: ${INSTALL_DIR}/${BINARY_NAME}"
}
# ---------- 安装 skills ----------
install_skills() {
local version="$1"
step "安装 skills..."
mkdir -p "${SKILLS_DIR}"
local skills_url="${API_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases/${version}/assets/${BINARY_NAME}_${version}_skills.tar.gz"
local tmpdir
tmpdir="$(mktemp -d)"
if download_with_retry "${skills_url}" "${tmpdir}/skills.tar.gz" 2>/dev/null; then
tar -xzf "${tmpdir}/skills.tar.gz" -C "${SKILLS_DIR}" 2>/dev/null || true
info "Skills 安装到: ${SKILLS_DIR}"
else
warn "Skills 包不可用(可稍后通过 gitlink-cli-install-skills 安装)"
fi
rm -rf "${tmpdir}"
}
# ---------- 验证安装 ----------
verify() {
step "验证安装..."
if command -v "${BINARY_NAME}" >/dev/null 2>&1; then
info "安装成功! $("${BINARY_NAME}" version 2>/dev/null || echo "${BINARY_NAME}")"
elif [ -x "${INSTALL_DIR}/${BINARY_NAME}" ]; then
info "安装成功! $("${INSTALL_DIR}/${BINARY_NAME}" version 2>/dev/null || echo "${INSTALL_DIR}/${BINARY_NAME}")"
warn "请将 ${INSTALL_DIR} 添加到 PATH: export PATH=${INSTALL_DIR}:\$PATH"
else
error "安装验证失败"
exit 1
fi
}
# ---------- 显示帮助 ----------
show_help() {
cat << EOF
GitLink CLI 安装脚本
用法:
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash [选项]
选项:
VERSION=0.1.0 指定版本
INSTALL_DIR=/path 指定安装目录
DEBUG=true 显示调试信息
环境变量:
INSTALL_DIR 安装目录(默认: auto自动选择
VERSION 版本(默认: latest
命令:
list 列出可用版本
uninstall 卸载
rollback VERSION 回滚到指定版本
示例:
# 安装最新版本
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
# 安装指定版本
VERSION=0.1.0 curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
# 安装到用户目录
INSTALL_DIR=$HOME/.local/bin curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash
# 列出可用版本
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- list
# 卸载
curl -sSL https://www.gitlink.org.cn/Gitlink/gitlink-cli/raw/master/install.sh | bash -s -- uninstall
EOF
}
# ---------- main ----------
main() {
echo ""
echo " ╔══════════════════════════════════════╗"
echo " ║ GitLink CLI 一键安装 ║"
echo " ╚══════════════════════════════════════╝"
echo ""
# 处理命令行参数
case "${1:-}" in
list)
list_versions
exit 0
;;
uninstall)
INSTALL_DIR="${INSTALL_DIR:-$(select_install_dir)}"
uninstall
;;
rollback)
rollback_version "$2"
;;
help|--help|-h)
show_help
exit 0
;;
esac
# 环境检测
check_environment
# 选择安装目录
INSTALL_DIR=$(select_install_dir)
export INSTALL_DIR
local platform
platform=$(detect_platform)
info "检测到平台: ${platform}"
local version
if [ "${VERSION}" = "latest" ]; then
version=$(fetch_latest_version)
info "最新版本: ${version}"
else
version="${VERSION}"
info "指定版本: ${version}"
fi
download_binary "${platform}" "${version}"
install_skills "${version}"
verify
echo ""
info "快速开始:"
info " gitlink-cli auth login # 登录账号"
info " gitlink-cli --help # 查看所有命令"
info " gitlink-cli version # 查看版本信息"
echo ""
}
main "$@"