#!/bin/bash # 远程一键安装脚本模板 # 用法: curl -fsSL https://shopex.cn/install.sh | bash set -e REPO_URL="${REPO_URL:-https://gitee.com/ShopeX/ECShopX.git}" # 终端颜色(无 GUM 时使用,避免未定义变量) ERROR='\033[0;31m' SUCCESS='\033[0;32m' NC='\033[0m' # --------------------------------------------------------------------------- # UI 与通用辅助函数 # --------------------------------------------------------------------------- ui_error() { local msg="$*" if [[ -n "$GUM" ]]; then "$GUM" log --level error "$msg" else echo -e "${ERROR}✗${NC} ${msg}" fi } ui_success() { local msg="$*" if [[ -n "$GUM" ]]; then local mark mark="$("$GUM" style --foreground "#00e5cc" --bold "✓")" echo "${mark} ${msg}" else echo -e "${SUCCESS}✓${NC} ${msg}" fi } ui_info() { local msg="$*" if [[ -n "${GUM:-}" ]]; then "$GUM" log --level info "$msg" else echo "[install] ${msg}" fi } is_root() { [[ "$(id -u)" -eq 0 ]] } require_sudo() { if [[ "$OS" != "linux" ]]; then return 0 fi if is_root; then return 0 fi if command -v sudo &> /dev/null; then if ! sudo -n true >/dev/null 2>&1; then ui_info "需要管理员权限,请输入密码" sudo -v fi return 0 fi ui_error "Linux 下安装需要 sudo,当前系统未找到 sudo" echo " 请先安装 sudo 或使用 root 用户重新运行。" exit 1 } run_quiet_step() { local desc="$1" shift ui_info "$desc..." if "$@" >/dev/null 2>&1; then return 0 fi echo "[install] 步骤失败,输出如下:" >&2 if ! "$@"; then ui_error "步骤失败: $desc" exit 1 fi } # --------------------------------------------------------------------------- # 系统检测(结果写入全局 OS) # --------------------------------------------------------------------------- OS="unknown" detect_os_or_die() { if [[ "$OSTYPE" == "darwin"* ]]; then OS="macos" elif [[ "$OSTYPE" == "linux-gnu"* ]] || [[ -n "${WSL_DISTRO_NAME:-}" ]]; then OS="linux" fi if [[ "$OS" == "unknown" ]]; then ui_error "不支持的操作系统" echo "本安装脚本仅支持 macOS 与 Linux(含 WSL)。" echo "Windows 请使用: iwr -useb https://openclaw.ai/install.ps1 | iex" exit 1 fi ui_success "已检测系统: $OS" } # --------------------------------------------------------------------------- # Homebrew(仅 macOS,供 Git/Docker 使用,避免依赖 Xcode 命令行工具) # --------------------------------------------------------------------------- ensure_homebrew() { [[ "$OS" != "macos" ]] && return 0 if command -v brew &>/dev/null; then eval "$(brew shellenv)" 2>/dev/null || true return 0 fi echo "[install] 未检测到 Homebrew,正在自动安装(后续 Git/Docker 将由此安装,无需 Xcode)..." /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" if [[ -x /opt/homebrew/bin/brew ]]; then eval "$(/opt/homebrew/bin/brew shellenv)" elif [[ -x /usr/local/bin/brew ]]; then eval "$(/usr/local/bin/brew shellenv)" fi if ! command -v brew &>/dev/null; then ui_error "Homebrew 安装后未找到 brew 命令,请重新打开终端或执行: eval \"\$(/opt/homebrew/bin/brew shellenv)\" 后重试" exit 1 fi ui_success "Homebrew 已安装" } # --------------------------------------------------------------------------- # Git 安装(兼容 macos / linux 多包管理器;macOS 使用 Homebrew 安装以避开 Xcode) # --------------------------------------------------------------------------- install_git() { if [[ "$OS" == "macos" ]]; then ensure_homebrew run_quiet_step "正在安装 Git(通过 Homebrew,无需 Xcode)" brew install git eval "$(brew shellenv)" 2>/dev/null || true elif [[ "$OS" == "linux" ]]; then require_sudo if command -v apt-get &>/dev/null; then if is_root; then run_quiet_step "正在更新软件包索引" apt-get update -qq run_quiet_step "正在安装 Git" apt-get install -y -qq git else run_quiet_step "正在更新软件包索引" sudo apt-get update -qq run_quiet_step "正在安装 Git" sudo apt-get install -y -qq git fi elif command -v dnf &>/dev/null; then if is_root; then run_quiet_step "正在安装 Git" dnf install -y -q git else run_quiet_step "正在安装 Git" sudo dnf install -y -q git fi elif command -v yum &>/dev/null; then if is_root; then run_quiet_step "正在安装 Git" yum install -y -q git else run_quiet_step "正在安装 Git" sudo yum install -y -q git fi elif command -v zypper &>/dev/null; then if is_root; then run_quiet_step "正在安装 Git" zypper install -y git else run_quiet_step "正在安装 Git" sudo zypper install -y git fi else ui_error "未检测到可用包管理器,请手动安装 Git: https://git-scm.com/downloads" exit 1 fi else ui_error "无法识别操作系统,请手动安装 Git: https://git-scm.com/downloads" exit 1 fi ui_success "Git 已安装" } # --------------------------------------------------------------------------- # Docker 安装(兼容 macos / linux 多包管理器) # --------------------------------------------------------------------------- install_docker() { if [[ "$OS" == "macos" ]]; then ensure_homebrew run_quiet_step "正在安装 Docker Desktop" brew install --cask docker ui_success "Docker Desktop 已安装,请从应用程序中启动并完成初始化" return 0 fi if [[ "$OS" != "linux" ]]; then ui_error "无法在此系统自动安装 Docker,请参考: https://docs.docker.com/engine/install/" exit 1 fi require_sudo # 确保有 curl(get.docker.com 或后续步骤可能需要) if ! command -v curl &>/dev/null; then if command -v apt-get &>/dev/null; then if is_root; then run_quiet_step "正在更新软件包索引" apt-get update -qq run_quiet_step "正在安装 curl" apt-get install -y -qq curl else run_quiet_step "正在更新软件包索引" sudo apt-get update -qq run_quiet_step "正在安装 curl" sudo apt-get install -y -qq curl fi elif command -v dnf &>/dev/null; then if is_root; then run_quiet_step "正在安装 curl" dnf install -y -q curl else run_quiet_step "正在安装 curl" sudo dnf install -y -q curl fi elif command -v yum &>/dev/null; then if is_root; then run_quiet_step "正在安装 curl" yum install -y -q curl else run_quiet_step "正在安装 curl" sudo yum install -y -q curl fi else ui_error "需要 curl 来安装 Docker,请先安装 curl" exit 1 fi fi # Linux: 优先使用包管理器,否则使用官方安装脚本 if command -v apt-get &>/dev/null; then if is_root; then run_quiet_step "正在更新软件包索引" apt-get update -qq run_quiet_step "正在安装 Docker" apt-get install -y -qq docker.io else run_quiet_step "正在更新软件包索引" sudo apt-get update -qq run_quiet_step "正在安装 Docker" sudo apt-get install -y -qq docker.io fi elif command -v dnf &>/dev/null; then if is_root; then run_quiet_step "正在安装 Docker" dnf install -y -q docker else run_quiet_step "正在安装 Docker" sudo dnf install -y -q docker fi elif command -v yum &>/dev/null; then if is_root; then run_quiet_step "正在安装 Docker" yum install -y -q docker else run_quiet_step "正在安装 Docker" sudo yum install -y -q docker fi elif command -v zypper &>/dev/null; then if is_root; then run_quiet_step "正在安装 Docker" zypper install -y docker else run_quiet_step "正在安装 Docker" sudo zypper install -y docker fi else run_quiet_step "正在通过 get.docker.com 安装 Docker" sh -c "curl -fsSL https://get.docker.com | sh" fi # 将当前用户加入 docker 组(非 root 时) if ! is_root; then local who="${SUDO_USER:-$(whoami)}" if getent group docker &>/dev/null; then run_quiet_step "正在将用户加入 docker 组" sudo usermod -aG docker "$who" || true fi fi # 启动 Docker 服务(Linux) if command -v systemctl &>/dev/null; then if is_root; then systemctl start docker 2>/dev/null || true systemctl enable docker 2>/dev/null || true else sudo systemctl start docker 2>/dev/null || true sudo systemctl enable docker 2>/dev/null || true fi elif command -v service &>/dev/null; then if is_root; then service docker start 2>/dev/null || true else sudo service docker start 2>/dev/null || true fi fi ui_success "Docker 已安装。若当前用户需免 sudo 运行 docker,请重新登录或执行: newgrp docker" } # --------------------------------------------------------------------------- # Docker Compose 检测与安装(dev-setup.sh 依赖) # --------------------------------------------------------------------------- has_docker_compose() { command -v docker-compose &>/dev/null || docker compose version &>/dev/null 2>&1 } install_docker_compose() { if [[ "$OS" == "macos" ]]; then ensure_homebrew run_quiet_step "正在安装 Docker Compose" brew install docker-compose ui_success "Docker Compose 已安装" return 0 fi if [[ "$OS" != "linux" ]]; then return 0 fi require_sudo if command -v apt-get &>/dev/null; then if is_root; then run_quiet_step "正在安装 Docker Compose 插件" apt-get install -y -qq docker-compose-plugin else run_quiet_step "正在安装 Docker Compose 插件" sudo apt-get install -y -qq docker-compose-plugin fi elif command -v dnf &>/dev/null; then if is_root; then run_quiet_step "正在安装 Docker Compose" dnf install -y -q docker-compose-plugin else run_quiet_step "正在安装 Docker Compose" sudo dnf install -y -q docker-compose-plugin fi elif command -v yum &>/dev/null; then if is_root; then run_quiet_step "正在安装 Docker Compose" yum install -y -q docker-compose-plugin else run_quiet_step "正在安装 Docker Compose" sudo yum install -y -q docker-compose-plugin fi else if is_root; then run_quiet_step "正在安装 Docker Compose 独立版" sh -c 'curl -fsSL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose' else run_quiet_step "正在安装 Docker Compose 独立版" sudo sh -c 'curl -fsSL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose' fi fi ui_success "Docker Compose 已安装" } ensure_docker_compose() { if has_docker_compose; then ui_success "已检测到 Docker Compose" return 0 fi install_docker_compose } # macOS:/usr/bin/git 有时是 Xcode 占位,会弹窗或要求装 CLT;真正可用的 git 可直接跳过 brew install macos_git_usable() { command -v git &>/dev/null || return 1 local ver ver="$(git --version 2>&1)" || return 1 case "$ver" in *xcode-select*|*xcrun:*error*|*"command line tools"*|*"开发者工具"*) return 1 ;; esac [[ "$ver" == git\ version* ]] || return 1 return 0 } ensure_git() { if [[ "$OS" == "macos" ]]; then if macos_git_usable; then ui_success "已检测到 Git: $(git --version 2>&1 | head -n1)" return 0 fi if command -v brew &>/dev/null; then eval "$(brew shellenv)" 2>/dev/null || true if brew list git &>/dev/null 2>&1; then ui_success "已检测到 Git(Homebrew)" return 0 fi fi # 无可用 git 或 brew 下未安装 git:通过 Homebrew 安装(避免依赖 Xcode) install_git return 0 fi if command -v git &>/dev/null; then ui_success "已检测到 Git" return 0 fi install_git } ensure_docker() { if command -v docker &>/dev/null; then ui_success "已检测到 Docker: $(docker --version)" return 0 fi install_docker } # --------------------------------------------------------------------------- # 主流程 # --------------------------------------------------------------------------- detect_os_or_die echo "[install] 检查依赖: Git、Docker、Docker Compose (OS=$OS)..." [[ "$OS" == "macos" ]] && ensure_homebrew ensure_git ensure_docker ensure_docker_compose echo "" echo "[install] 当前目录: $(pwd)" confirm="n" if [ -e /dev/tty ]; then read -r -p "是否在当前目录安装?(y/n): " confirm