531 lines
18 KiB
Bash
Executable File
531 lines
18 KiB
Bash
Executable File
#!/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 - 游戏平台
|
||
"chiaki" # Chiaki - PlayStation 远程游戏
|
||
"moonlight" # Moonlight - NVIDIA GameStream 客户端
|
||
"hyperconnect" # HyperConnect - 小米互联服务
|
||
"font-fira-code-nerd-font" # Fira Code Nerd Font - 编程字体
|
||
"localsend" # LocalSend - 跨平台文件传输工具
|
||
"google-chrome@canary" # Google Chrome Canary - Chrome 开发版
|
||
"betterdisplay" # BetterDisplay - 显示器管理工具
|
||
"netnewswire" # NetNewsWire - RSS 阅读器
|
||
"plexamp" # Plexamp - Plex 音乐播放器
|
||
"fantastical" # Fantastical - 日历应用
|
||
"chatgpt" # ChatGPT - OpenAI 官方应用
|
||
"claude" # Claude - Anthropic 官方应用
|
||
)
|
||
|
||
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 |