#!/bin/bash # macOS 快速设置 - 完整安装脚本 # 用法: bash -c "$(curl -fsSL https://raw.githubusercontent.com/Astrian/mac-setup/main/install.sh)" # 本地: bash ~/.mac-setup/install.sh set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # 打印带颜色的消息 print_message() { echo -e "${2}${1}${NC}" } print_message "🍎 macOS 快速设置工具" "$CYAN" print_message "=====================" "$CYAN" echo "" # 检查网络连接 check_network() { if ! ping -c 1 github.com &> /dev/null; then print_message "❌ 网络连接失败,请检查网络设置" "$RED" exit 1 fi } # 预先获取 sudo 权限 get_sudo() { print_message "🔐 需要管理员权限..." "$YELLOW" sudo -v # 保持 sudo 权限活跃 while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null & } # 配置 sudo Touch ID setup_sudo_touchid() { print_message "👆 配置 sudo Touch ID..." "$BLUE" if grep -q "auth.*sufficient.*pam_tid.so" /etc/pam.d/sudo_local 2>/dev/null; then print_message "✅ Touch ID 已配置" "$GREEN" else sudo sed -i '' 's/^#auth.*sufficient.*pam_tid.so/auth sufficient pam_tid.so/' /etc/pam.d/sudo_local 2>/dev/null || true print_message "✅ Touch ID 配置完成" "$GREEN" fi } # 安装 Xcode Command Line Tools install_xcode_tools() { print_message "🛠️ 检查 Xcode Command Line Tools..." "$BLUE" if xcode-select -p &>/dev/null; then print_message "✅ Xcode Command Line Tools 已安装" "$GREEN" else print_message "📥 安装 Xcode Command Line Tools..." "$YELLOW" xcode-select --install # 检测是否为交互式执行 if [[ -t 0 ]]; then # 交互式执行 - 等待用户确认 print_message "⏳ Xcode Command Line Tools 安装进行中..." "$YELLOW" print_message " 1. 请在弹出的对话框中点击 '安装'" "$YELLOW" print_message " 2. 等待安装完成(通常需要几分钟)" "$YELLOW" print_message " 3. 安装完成后按回车键继续..." "$YELLOW" echo "" # 等待用户确认安装完成 read -p "⚡ 安装完成后请按回车键继续..." -r echo "" else # 非交互式执行 - 自动等待 print_message "⏳ 等待 Xcode Command Line Tools 安装完成..." "$YELLOW" print_message " 正在自动检测安装状态..." "$YELLOW" # 自动等待安装完成(最多等待10分钟) local wait_count=0 while [[ $wait_count -lt 120 ]]; do if xcode-select -p &>/dev/null; then print_message "✅ Xcode Command Line Tools 安装完成!" "$GREEN" return 0 fi sleep 5 ((wait_count++)) if [[ $((wait_count % 12)) -eq 0 ]]; then print_message " 仍在等待安装完成... ($((wait_count * 5 / 60))分钟)" "$YELLOW" fi done print_message "❌ Xcode Command Line Tools 安装超时" "$RED" print_message " 请手动完成安装后重新运行脚本" "$RED" exit 1 fi # 再次验证安装是否成功 local retry_count=0 while [[ $retry_count -lt 3 ]]; do if xcode-select -p &>/dev/null; then print_message "✅ Xcode Command Line Tools 安装成功!" "$GREEN" return 0 else print_message "⚠️ 检测到 Xcode Command Line Tools 尚未安装完成" "$YELLOW" read -p " 请等待安装完成后按回车键重试... " -r echo "" ((retry_count++)) fi done # 如果多次重试仍未成功,提示用户 print_message "❌ Xcode Command Line Tools 安装验证失败" "$RED" print_message " 请确保安装已完成,或手动验证:xcode-select -p" "$RED" exit 1 fi } # 安装 Homebrew install_homebrew() { if ! command -v brew &> /dev/null; then print_message "📦 安装 Homebrew..." "$BLUE" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 检测系统架构并添加 Homebrew 到 PATH if [[ $(uname -m) == "arm64" ]]; then echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile eval "$(/opt/homebrew/bin/brew shellenv)" else echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile eval "$(/usr/local/bin/brew shellenv)" fi print_message "✅ Homebrew 安装成功!" "$GREEN" else print_message "✅ Homebrew 已安装" "$GREEN" fi } # 安装 xcodes install_xcodes() { print_message "📱 安装 xcodes (Xcode 版本管理工具)..." "$BLUE" if command -v xcodes &> /dev/null; then print_message "✅ xcodes 已安装" "$GREEN" else brew install xcodesorg/made/xcodes brew install aria2 print_message "✅ xcodes 安装成功!" "$GREEN" fi } # 安装应用列表 install_apps() { print_message "📱 安装应用程序..." "$BLUE" # 应用程序列表 apps=( "wechat" # 微信 "qq" # QQ "discord" # Discord "setapp" # Setapp "jordanbaird-ice" # Ice - macOS 菜单栏管理工具 "alfred" # Alfred - 效率启动器 "1password" # 1Password - 密码管理器 "iterm2" # iTerm2 - 终端仿真器 "synology-drive" # Synology Drive Client - 文件同步工具 "thebrowsercompany-dia" # Dia - AI 浏览器 "docker-desktop" # Docker Desktop - 容器管理平台 "gpg-suite" # GPG Suite - PGP 加密工具包 "mailmate" # MailMate - 专业邮件客户端 "mumuplayer" # MuMu Player Pro - Android 模拟器 "maa" # MAA - 明日方舟助手 "tailscale-app" # Tailscale - 零配置 VPN "private-internet-access" # Private Internet Access - VPN 服务 "parallels" # Parallels Desktop - 虚拟机软件 "telegram" # Telegram Swift - 官方 macOS 版本 "steam" # Steam - 游戏平台 "font-fira-code-nerd-font" # Fira Code Nerd Font - 编程字体 ) total=${#apps[@]} installed=0 failed=0 for app in "${apps[@]}"; do print_message "📦 正在安装: $app" "$YELLOW" if brew install --cask "$app" 2>/dev/null; then print_message "✅ $app 安装成功!" "$GREEN" ((installed++)) else print_message "❌ $app 安装失败或已存在" "$RED" ((failed++)) fi done print_message "=========================================" "$CYAN" print_message "📊 应用安装完成!" "$CYAN" print_message " 总计: $total 个应用" "$CYAN" print_message " 成功: $installed 个" "$GREEN" print_message " 失败/已存在: $failed 个" "$RED" print_message "=========================================" "$CYAN" } # 安装命令行工具 install_cli_tools() { print_message "🛠️ 安装命令行工具..." "$BLUE" # Neovim if command -v nvim &> /dev/null; then print_message "✅ Neovim 已安装" "$GREEN" else brew install neovim print_message "✅ Neovim 安装成功!" "$GREEN" fi # prettyping if command -v prettyping &> /dev/null; then print_message "✅ prettyping 已安装" "$GREEN" else brew install prettyping print_message "✅ prettyping 安装成功!" "$GREEN" fi } # 配置 SSH setup_ssh() { print_message "🔐 配置 SSH..." "$BLUE" mkdir -p ~/.ssh chmod 700 ~/.ssh # 配置 1Password SSH Agent if ! grep -q "IdentityAgent" ~/.ssh/config 2>/dev/null; then print_message " 配置 1Password SSH Agent..." "$YELLOW" cat >> ~/.ssh/config << 'EOF' Host * IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" EOF chmod 600 ~/.ssh/config print_message "✅ SSH Agent 配置完成" "$GREEN" else print_message "✅ SSH Agent 已配置" "$GREEN" fi # 添加常用 Git 服务器指纹 print_message " 添加 Git 服务器指纹..." "$YELLOW" ssh-keyscan -H git.nas.astrian.moe >> ~/.ssh/known_hosts 2>/dev/null ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2>/dev/null ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts 2>/dev/null } # 安装 Oh My Zsh install_oh_my_zsh() { print_message "🌈 安装 Oh My Zsh..." "$PURPLE" if [ -d "$HOME/.oh-my-zsh" ]; then print_message "✅ Oh My Zsh 已安装" "$GREEN" else sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended print_message "✅ Oh My Zsh 安装成功!" "$GREEN" fi } # 安装 nvm 和 Node.js install_node() { print_message "🔧 安装 nvm 和 Node.js..." "$BLUE" if [ -s "$HOME/.nvm/nvm.sh" ]; then print_message "✅ nvm 已安装" "$GREEN" else curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" print_message "✅ nvm 安装成功!" "$GREEN" fi # 确保 nvm 已加载 export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" print_message "📦 安装 Node.js LTS..." "$YELLOW" nvm install --lts nvm use --lts nvm alias default lts/* print_message "✅ Node.js LTS 安装成功!" "$GREEN" } # 安装 Claude Code CLI install_claude_code() { print_message "🤖 安装 Claude Code CLI..." "$BLUE" npm install -g @anthropic-ai/claude-code print_message "✅ Claude Code CLI 安装成功!" "$GREEN" } # 配置 zsh 别名 setup_aliases() { print_message "⚙️ 配置 zsh 别名..." "$BLUE" # Claude Code 别名 if ! grep -q 'alias cc=' "$HOME/.zshrc" 2>/dev/null; then echo '' >> "$HOME/.zshrc" echo '# Claude Code CLI alias' >> "$HOME/.zshrc" echo 'alias cc="claude --dangerously-skip-permissions"' >> "$HOME/.zshrc" fi # vi/vim 别名 if ! grep -q 'alias vi=' "$HOME/.zshrc" 2>/dev/null; then echo '# Neovim alias' >> "$HOME/.zshrc" echo 'alias vi="nvim"' >> "$HOME/.zshrc" echo 'alias vim="nvim"' >> "$HOME/.zshrc" fi # ping 别名 if ! grep -q 'alias ping=' "$HOME/.zshrc" 2>/dev/null; then echo '# prettyping alias' >> "$HOME/.zshrc" echo 'alias ping="prettyping --nolegend"' >> "$HOME/.zshrc" fi print_message "✅ 别名配置完成" "$GREEN" } # 提示配置 1Password SSH Agent prompt_1password_setup() { print_message "🔐 配置 1Password SSH Agent..." "$BLUE" # 检查 1Password 是否已安装 if [[ -d "/Applications/1Password 7 - Password Manager.app" ]] || [[ -d "/Applications/1Password.app" ]]; then print_message "📱 检测到 1Password 已安装" "$GREEN" # 检测是否为交互式执行 if [[ -t 0 ]]; then # 交互式执行 - 提示用户配置 print_message "⚠️ 为了克隆 nvim 配置,需要先设置 1Password SSH Agent" "$YELLOW" print_message "" "$NC" print_message "📋 请按以下步骤配置:" "$YELLOW" print_message " 1. 打开 1Password 应用并登录" "$YELLOW" print_message " 2. 进入 Settings > Developer" "$YELLOW" print_message " 3. 启用 'Use the SSH agent'" "$YELLOW" print_message " 4. 将你的 SSH 私钥添加到 1Password" "$YELLOW" print_message " 5. 确保 SSH 密钥可以访问 git.nas.astrian.moe" "$YELLOW" print_message "" "$NC" # 等待用户确认配置完成 read -p "⚡ 1Password SSH Agent 配置完成后请按回车键继续..." -r echo "" # 测试 SSH 连接 print_message "🔍 测试 SSH 连接..." "$BLUE" if ssh -T git@git.nas.astrian.moe -o ConnectTimeout=10 -o BatchMode=yes 2>/dev/null; then print_message "✅ SSH 连接测试成功!" "$GREEN" return 0 else print_message "⚠️ SSH 连接测试失败,但将继续执行" "$YELLOW" print_message " 如果 nvim 配置克隆失败,请检查 SSH 配置" "$YELLOW" fi else # 非交互式执行 - 自动尝试 print_message "🔍 自动检测 SSH 连接状态..." "$YELLOW" if ssh -T git@git.nas.astrian.moe -o ConnectTimeout=10 -o BatchMode=yes 2>/dev/null; then print_message "✅ SSH 连接可用" "$GREEN" else print_message "⚠️ SSH 连接不可用,nvim 配置可能无法克隆" "$YELLOW" fi fi else print_message "⚠️ 未检测到 1Password,跳过 SSH Agent 配置" "$YELLOW" fi } # 配置 Neovim setup_neovim() { print_message "⚙️ 配置 Neovim..." "$BLUE" if command -v nvim &> /dev/null; then mkdir -p ~/.config if [ -d ~/.config/nvim ]; then print_message "⚠️ 备份现有 nvim 配置..." "$YELLOW" mv ~/.config/nvim ~/.config/nvim.backup.$(date +%Y%m%d_%H%M%S) fi print_message "📥 克隆 nvim 配置..." "$YELLOW" if git clone git@git.nas.astrian.moe:Astrian/nvim-config.git ~/.config/nvim 2>/dev/null; then print_message "✅ Neovim 配置已应用!" "$GREEN" else print_message "⚠️ 无法克隆 nvim 配置" "$YELLOW" print_message " 请确保已正确配置 1Password SSH Agent" "$YELLOW" print_message " 或手动执行:git clone git@git.nas.astrian.moe:Astrian/nvim-config.git ~/.config/nvim" "$YELLOW" fi fi } # 显示菜单 show_menu() { echo "" print_message "请选择安装选项:" "$CYAN" echo "1) 完整安装(推荐)" echo "2) 仅安装 Homebrew 和应用" echo "3) 仅配置开发环境" echo "4) 仅配置 SSH 和别名" echo "0) 退出" echo "" read -p "请输入选项 [0-4]: " choice } # 完整安装 full_install() { print_message "🚀 开始完整安装..." "$CYAN" echo "" check_network get_sudo setup_sudo_touchid install_xcode_tools install_homebrew install_xcodes install_apps install_cli_tools setup_ssh install_oh_my_zsh install_node install_claude_code setup_aliases prompt_1password_setup setup_neovim echo "" print_message "=========================================" "$CYAN" print_message "🎉 完整安装完成!" "$GREEN" print_message "=========================================" "$CYAN" echo "" print_message "💡 提示:" "$YELLOW" print_message " 1. 重启终端或运行 'source ~/.zshrc' 激活配置" "$YELLOW" print_message " 2. 使用 'cc' 命令启动 Claude Code" "$YELLOW" print_message " 3. 使用 'vi' 命令启动 Neovim" "$YELLOW" print_message " 4. 首次启动 nvim 时会自动安装插件" "$YELLOW" } # 仅安装应用 apps_only() { print_message "📱 仅安装应用..." "$CYAN" check_network get_sudo install_xcode_tools install_homebrew install_xcodes install_apps print_message "✅ 应用安装完成!" "$GREEN" } # 仅开发环境 dev_only() { print_message "🛠️ 仅配置开发环境..." "$CYAN" install_cli_tools install_oh_my_zsh install_node install_claude_code prompt_1password_setup setup_neovim print_message "✅ 开发环境配置完成!" "$GREEN" } # 仅配置 config_only() { print_message "⚙️ 仅配置 SSH 和别名..." "$CYAN" setup_ssh setup_aliases print_message "✅ 配置完成!" "$GREEN" } # 主执行逻辑 main() { # 如果有参数,直接运行完整安装 if [[ $# -gt 0 && $1 == "--full" ]]; then full_install exit 0 fi # 如果是通过 curl 管道执行(非交互式),默认运行完整安装 if [[ ! -t 0 ]]; then print_message "🔍 检测到非交互式执行,运行完整安装..." "$YELLOW" full_install exit 0 fi # 交互式菜单 while true; do show_menu case $choice in 1) full_install break ;; 2) apps_only break ;; 3) dev_only break ;; 4) config_only break ;; 0) print_message "👋 再见!" "$CYAN" exit 0 ;; *) print_message "❌ 无效选项,请重试" "$RED" ;; esac done } # 只有在脚本被直接执行时才运行主函数 if [[ "${BASH_SOURCE[0]}" == "${0}" ]] || [[ -z "${BASH_SOURCE[0]}" ]]; then main "$@" fi