Files
my-pi/update.sh
T

349 lines
12 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/sh
set -u
SCRIPT_DIR=$(CDPATH=; cd "$(dirname "$0")" && pwd) || exit 1
MANAGED_CONFIG_HELPERS=$SCRIPT_DIR/scripts/managed-config.sh
if [ ! -f "$MANAGED_CONFIG_HELPERS" ]; then
printf '错误: 找不到受管配置辅助脚本:%s\n' "$MANAGED_CONFIG_HELPERS" >&2
exit 1
fi
# shellcheck source=scripts/managed-config.sh
. "$MANAGED_CONFIG_HELPERS"
PACKAGE_SOURCE=${PI_PACKAGE_SOURCE:-git:git@bitbucket.org:siakitem/my-pi.git}
POWERLEVEL10K_PRESET_FILE=$SCRIPT_DIR/config/p10k.zsh
CODEGRAPH_INSTALL_URL=https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh
CODEGRAPH_LATEST_RELEASE_URL=https://github.com/colbymchenry/codegraph/releases/latest
KITTY_INSTALL_URL=https://sw.kovidgoyal.net/kitty/installer.sh
KITTY_VERSION_URL=https://sw.kovidgoyal.net/kitty/current-version.txt
update_failed=0
brew_metadata_refreshed=0
say() {
printf '%s\n' "$*"
}
warn() {
printf '警告: %s\n' "$*" >&2
}
record_update_failure() {
warn "$1 升级或配置同步失败;其余已安装组件仍会继续处理。"
update_failed=1
}
select_updated_bundle_config() {
updated_bundle_dir=
case $PACKAGE_SOURCE in
/*)
updated_bundle_dir=$PACKAGE_SOURCE
;;
./*|../*)
updated_bundle_dir=$(CDPATH=; cd "$PACKAGE_SOURCE" 2>/dev/null && pwd) || updated_bundle_dir=
;;
git:git@bitbucket.org:siakitem/my-pi.git)
updated_bundle_dir=${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/git/bitbucket.org/siakitem/my-pi
;;
esac
if [ -n "$updated_bundle_dir" ] && [ -f "$updated_bundle_dir/config/p10k.zsh" ]; then
POWERLEVEL10K_PRESET_FILE=$updated_bundle_dir/config/p10k.zsh
elif [ ! -f "$POWERLEVEL10K_PRESET_FILE" ]; then
warn "无法定位升级后的组合包配置,找不到 ${POWERLEVEL10K_PRESET_FILE}。"
return 1
else
warn "无法从当前 PI_PACKAGE_SOURCE 推导升级后的包目录,将使用脚本目录中的配置。"
fi
}
resolve_zsh_paths() {
oh_my_zsh_dir=${ZSH:-$HOME/.oh-my-zsh}
zsh_custom_dir=${ZSH_CUSTOM:-$oh_my_zsh_dir/custom}
zshrc_file=${ZDOTDIR:-$HOME}/.zshrc
my_pi_config_dir=${XDG_CONFIG_HOME:-$HOME/.config}/my-pi
p10k_managed_config_file=$my_pi_config_dir/p10k.zsh
}
replace_zsh_managed_block() {
managed_id=$1
managed_placement=$2
managed_anchor=$3
shift 3
managed_content=$(mktemp "${TMPDIR:-/tmp}/my-pi-zsh-block.XXXXXX") || return 1
printf '%s\n' "$@" > "$managed_content"
my_pi_replace_managed_block "$zshrc_file" "$managed_id" "$managed_content" \
"$managed_placement" "$managed_anchor"
managed_status=$?
rm -f "$managed_content"
return "$managed_status"
}
update_git_checkout() {
component=$1
checkout=$2
if [ ! -d "$checkout/.git" ]; then
warn "$component 已安装,但不是脚本可安全升级的 Git checkout,已跳过版本升级。"
return 0
fi
if ! command -v git >/dev/null 2>&1; then
warn "升级 $component 需要 git。"
return 1
fi
upstream=$(git -C "$checkout" rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null) || {
warn "$component 的 Git checkout 没有可识别的上游分支,已跳过版本升级。"
return 1
}
git -C "$checkout" fetch --quiet || return 1
local_revision=$(git -C "$checkout" rev-parse HEAD) || return 1
remote_revision=$(git -C "$checkout" rev-parse "$upstream") || return 1
if [ "$local_revision" = "$remote_revision" ]; then
say "✓ $component 已是最新版本。"
return 0
fi
say "发现 $component 有新版本,正在快进升级。"
git -C "$checkout" merge --ff-only "$upstream"
}
refresh_brew_metadata() {
if [ "$brew_metadata_refreshed" -eq 1 ]; then
return 0
fi
say "正在刷新 Homebrew 版本信息。"
brew update || return 1
brew_metadata_refreshed=1
}
update_brew_formula_if_installed() {
formula=$1
description=$2
command_name=$3
if command -v brew >/dev/null 2>&1 && brew list --formula "$formula" >/dev/null 2>&1; then
refresh_brew_metadata || {
record_update_failure "$description"
return 0
}
outdated_formula=$(brew outdated --formula --quiet "$formula") || {
record_update_failure "$description"
return 0
}
if [ -z "$outdated_formula" ]; then
say "✓ $description 已是最新版本。"
else
say "发现 $description 有新版本,正在升级。"
brew upgrade "$formula" || record_update_failure "$description"
fi
elif command -v "$command_name" >/dev/null 2>&1; then
say "- $description 已安装,但不由 Homebrew 管理,已保留现有安装。"
else
say "- $description 未安装,升级流程跳过。"
fi
}
detect_kitty() {
kitty_bin=
if command -v kitty >/dev/null 2>&1; then
kitty_bin=$(command -v kitty)
return 0
fi
case $(uname -s) in
Darwin) kitty_candidates="/Applications/kitty.app/Contents/MacOS/kitty" ;;
*) kitty_candidates="$HOME/.local/kitty.app/bin/kitty" ;;
esac
for candidate in $kitty_candidates; do
if [ -x "$candidate" ]; then
kitty_bin=$candidate
return 0
fi
done
return 1
}
resolve_kitty_config_dir() {
kitty_config_dir=${KITTY_CONFIG_DIRECTORY:-${XDG_CONFIG_HOME:-$HOME/.config}/kitty}
}
kitty_uses_solarized_dark() {
resolve_kitty_config_dir
[ -f "$kitty_config_dir/current-theme.conf" ] &&
grep -F "Solarized Dark" "$kitty_config_dir/current-theme.conf" >/dev/null 2>&1
}
update_kitty() {
if ! detect_kitty; then
say "- Kitty 未安装,升级流程跳过。"
return 0
fi
if command -v brew >/dev/null 2>&1 && brew list --cask kitty >/dev/null 2>&1; then
if refresh_brew_metadata; then
if outdated_kitty=$(brew outdated --cask --quiet kitty); then
if [ -z "$outdated_kitty" ]; then
say "✓ Kitty 已是最新版本。"
else
say "发现 Kitty 有新版本,正在升级。"
brew upgrade --cask kitty || record_update_failure "Kitty"
fi
else
record_update_failure "Kitty"
fi
else
record_update_failure "Kitty"
fi
elif [ "$kitty_bin" = "$HOME/.local/kitty.app/bin/kitty" ] || \
[ "$kitty_bin" = "/Applications/kitty.app/Contents/MacOS/kitty" ]; then
if ! command -v curl >/dev/null 2>&1; then
record_update_failure "Kitty(检查版本需要 curl"
else
kitty_version_output=$("$kitty_bin" --version 2>/dev/null) || kitty_version_output=
case $kitty_version_output in
kitty\ *)
installed_kitty_version=${kitty_version_output#kitty }
installed_kitty_version=${installed_kitty_version%% *}
;;
*) installed_kitty_version= ;;
esac
latest_kitty_version=$(curl -fsSL "$KITTY_VERSION_URL") || latest_kitty_version=
if [ -z "$installed_kitty_version" ] || [ -z "$latest_kitty_version" ]; then
record_update_failure "Kitty 版本检查"
elif [ "$installed_kitty_version" = "$latest_kitty_version" ]; then
say "✓ Kitty $installed_kitty_version 已是最新版本。"
else
say "发现 Kitty ${latest_kitty_version}(当前 ${installed_kitty_version}),正在升级。"
installer_file=$(mktemp "${TMPDIR:-/tmp}/my-pi-kitty.XXXXXX") || return 1
if ! curl -fsSL "$KITTY_INSTALL_URL" -o "$installer_file" || \
! sh "$installer_file" launch=n "installer=version-$latest_kitty_version"; then
record_update_failure "Kitty"
fi
rm -f "$installer_file"
fi
fi
else
say "- Kitty 已安装,但不由 Homebrew 或官方 ~/.local 安装管理,已保留现有安装。"
fi
if kitty_uses_solarized_dark; then
"$kitty_bin" +kitten themes --reload-in=none "Solarized Dark" || \
record_update_failure "Kitty Solarized Dark 主题"
fi
}
update_codegraph() {
if ! command -v codegraph >/dev/null 2>&1; then
say "- CodeGraph 未安装,升级流程跳过。"
return 0
fi
if ! command -v curl >/dev/null 2>&1; then
warn "检查 CodeGraph 版本需要 curl。"
return 1
fi
installed_codegraph_version=$(codegraph --version 2>/dev/null) || installed_codegraph_version=
latest_release_url=$(curl -fsSLI -o /dev/null -w '%{url_effective}' \
"$CODEGRAPH_LATEST_RELEASE_URL") || latest_release_url=
case $latest_release_url in
*/releases/tag/*) latest_codegraph_tag=${latest_release_url##*/} ;;
*) latest_codegraph_tag= ;;
esac
latest_codegraph_version=${latest_codegraph_tag#v}
installed_codegraph_version=${installed_codegraph_version#v}
if [ -z "$installed_codegraph_version" ] || [ -z "$latest_codegraph_version" ]; then
warn "无法比较 CodeGraph 的本地版本与最新发布版本,已跳过替换。"
return 1
fi
if [ "$installed_codegraph_version" = "$latest_codegraph_version" ]; then
say "✓ CodeGraph $installed_codegraph_version 已是最新版本。"
return 0
fi
say "发现 CodeGraph ${latest_codegraph_version}(当前 ${installed_codegraph_version}),正在升级。"
installer_file=$(mktemp "${TMPDIR:-/tmp}/my-pi-codegraph.XXXXXX") || return 1
if ! curl -fsSL "$CODEGRAPH_INSTALL_URL" -o "$installer_file" || \
! CODEGRAPH_VERSION="$latest_codegraph_tag" sh "$installer_file"; then
rm -f "$installer_file"
return 1
fi
rm -f "$installer_file"
}
update_zsh_environment() {
resolve_zsh_paths
if [ ! -f "$oh_my_zsh_dir/oh-my-zsh.sh" ]; then
say "- Oh My Zsh 未安装,Powerlevel10k 和 Zsh 插件升级均跳过。"
return 0
fi
if [ -f "$oh_my_zsh_dir/tools/upgrade.sh" ] && command -v zsh >/dev/null 2>&1; then
ZSH="$oh_my_zsh_dir" zsh "$oh_my_zsh_dir/tools/upgrade.sh" || record_update_failure "Oh My Zsh"
else
update_git_checkout "Oh My Zsh" "$oh_my_zsh_dir" || record_update_failure "Oh My Zsh"
fi
powerlevel10k_dir=$zsh_custom_dir/themes/powerlevel10k
if [ -f "$powerlevel10k_dir/powerlevel10k.zsh-theme" ]; then
update_git_checkout "Powerlevel10k" "$powerlevel10k_dir" || record_update_failure "Powerlevel10k"
else
say "- Powerlevel10k 未安装,升级流程跳过。"
fi
for plugin in zsh-autosuggestions zsh-syntax-highlighting; do
plugin_dir=$zsh_custom_dir/plugins/$plugin
if [ -d "$plugin_dir" ]; then
update_git_checkout "$plugin" "$plugin_dir" || record_update_failure "$plugin"
else
say "- $plugin 未安装,升级流程跳过。"
fi
done
[ -f "$zshrc_file" ] || return 0
if my_pi_managed_block_exists "$zshrc_file" "oh-my-zsh-loader"; then
replace_zsh_managed_block "oh-my-zsh-loader" "append" "" \
"export ZSH=\"$oh_my_zsh_dir\"" \
"source \"\$ZSH/oh-my-zsh.sh\"" || record_update_failure ".zshrc Oh My Zsh 受管块"
fi
if my_pi_managed_block_exists "$zshrc_file" "powerlevel10k-theme"; then
replace_zsh_managed_block "powerlevel10k-theme" "before" \
'^(# >>> my-pi:oh-my-zsh-loader >>>|[[:space:]]*(source|\.)[[:space:]].*oh-my-zsh\.sh)' \
'ZSH_THEME="powerlevel10k/powerlevel10k"' || record_update_failure ".zshrc Powerlevel10k 主题受管块"
fi
for plugin in git zsh-autosuggestions zsh-syntax-highlighting; do
if my_pi_managed_block_exists "$zshrc_file" "zsh-plugin-$plugin"; then
replace_zsh_managed_block "zsh-plugin-$plugin" "before" \
'^(# >>> my-pi:oh-my-zsh-loader >>>|[[:space:]]*(source|\.)[[:space:]].*oh-my-zsh\.sh)' \
"plugins+=($plugin)" || record_update_failure ".zshrc $plugin 受管块"
fi
done
if [ -f "$p10k_managed_config_file" ] || \
my_pi_managed_block_exists "$zshrc_file" "powerlevel10k-config"; then
if my_pi_sync_managed_file "$POWERLEVEL10K_PRESET_FILE" "$p10k_managed_config_file"; then
replace_zsh_managed_block "powerlevel10k-config" "append" "" \
"[[ ! -f \"$p10k_managed_config_file\" ]] || source \"$p10k_managed_config_file\"" || \
record_update_failure ".zshrc Powerlevel10k 配置受管块"
else
record_update_failure "Powerlevel10k 受管配置"
fi
fi
}
if ! command -v pi >/dev/null 2>&1; then
warn "找不到 pi,无法升级组合包。请确保 pi 位于 PATH。"
exit 127
fi
say "正在升级 Pi 组合包:$PACKAGE_SOURCE"
if ! pi update "$PACKAGE_SOURCE"; then
warn "pi update 执行失败,已停止后续升级。"
exit 1
fi
select_updated_bundle_config || exit 1
say "组合包升级完成,开始升级已安装的终端环境和机器级 CLI;未安装项将直接跳过。"
update_kitty || record_update_failure "Kitty"
update_zsh_environment || record_update_failure "Zsh 环境"
update_codegraph || record_update_failure "CodeGraph"
update_brew_formula_if_installed "kotlin-lsp" "kotlin-lsp" "kotlin-lsp"
update_brew_formula_if_installed "openjdk@21" "Java 21" "java"
update_brew_formula_if_installed "jdtls" "jdtls" "jdtls"
say "已安装组件的升级与受管配置同步完成。"
exit "$update_failed"