One-click convert between vanilla Omarchy and OmarchyCN

omarchy-cn-convert turns a package-based install into OmarchyCN in one
curl-able run: registry key + [omarchycn] repo, --ask=4 swap onto the
cn-built packages (Chinese menu/bindings and OMARCHY CN branding ride
the settings tree), [omarchy] mirror line, zh_CN locale, fcitx5-rime
seeding, CN Arch mirrors, and a plymouth rebrand, recording pre-state
in /var/lib/omarchycn/convert-state. omarchy-cn-revert restores that
state symmetrically and survives user-removed packages, self-deletion
mid-swap, and cosmetic plymouth failures after the state is cleared.
Checkout installs are refused toward the overlay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
This commit is contained in:
2026-08-27 18:20:51 -04:00
co-authored by Claude Fable 5
parent c51df9977b
commit f72a48f747
7 changed files with 251 additions and 4 deletions
+107
View File
@@ -0,0 +1,107 @@
#!/bin/bash
# omarchy:summary=Convert a vanilla package-based Omarchy install into OmarchyCN
# omarchy:examples=omarchy cn convert
# Curl-able bootstrap (like the overlay installer): everything before the
# package swap must run without the cn tree, so no $OMARCHY_PATH until then.
set -euo pipefail
GITEA=${GITEA:-https://git.zacharyzhang.com}
OWNER=${OWNER:-ZacharyZhang-NY}
REGISTRY="$GITEA/api/packages/$OWNER/arch"
REG_KEY_FPR=74DCF57ACD812B24D959F146BD386048867B33B4
STATE_DIR=/var/lib/omarchycn
STATE=$STATE_DIR/convert-state
# Bootstrap exception: curl|bash runs outside a session, so default the path
export OMARCHY_PATH=${OMARCHY_PATH:-/usr/share/omarchy}
main() {
command -v pacman > /dev/null || { echo "需要 Arch Linux(未找到 pacman" >&2; exit 1; }
if (( EUID == 0 )); then
echo "请以普通用户运行(脚本内部按需 sudo" >&2
exit 1
fi
local prev_omarchy prev_settings
prev_omarchy=$(pacman -Q omarchy 2> /dev/null || pacman -Q omarchy-dev 2> /dev/null || true)
prev_settings=$(pacman -Q omarchy-settings 2> /dev/null || pacman -Q omarchy-settings-dev 2> /dev/null || true)
if [[ -z $prev_omarchy || -z $prev_settings ]]; then
if [[ -d $HOME/.local/share/omarchy/.git ]]; then
echo "检测到 checkout 安装(非包安装):请改用 overlaybin/omarchycn-install-overlay" >&2
else
echo "未检测到 Omarchy 包安装(需要 omarchy 与 omarchy-settings" >&2
fi
exit 1
fi
[[ -f $STATE ]] && echo "已转换过($STATE 在案):本次仅同步更新,不覆盖回退状态"
echo "==> 信任 OmarchyCN registry 公钥并配置 [omarchycn] 仓库"
local tmpkey
tmpkey=$(mktemp)
curl -fsSL "$REGISTRY/repository.key" -o "$tmpkey"
sudo pacman-key --add "$tmpkey"
sudo pacman-key --lsign-key "$REG_KEY_FPR"
rm -f "$tmpkey"
if ! grep -q '^\[omarchycn\]' /etc/pacman.conf; then
printf '\n[omarchycn]\nSigLevel = Required DatabaseOptional\nServer = %s/omarchycn/x86_64\n' \
"$REGISTRY" | sudo tee -a /etc/pacman.conf > /dev/null
fi
if [[ ! -f $STATE ]]; then
echo "==> 记录转换前状态(供 omarchy cn revert 还原)"
sudo mkdir -p "$STATE_DIR"
if [[ -f /etc/locale.conf ]]; then
sudo cp /etc/locale.conf "$STATE_DIR/locale.conf.pre"
fi
sudo cp /etc/pacman.d/mirrorlist "$STATE_DIR/mirrorlist.pre"
local p new_pkgs=""
for p in fcitx5-rime fcitx5-chinese-addons fcitx5-configtool omarchycn-keyring; do
pacman -Q "$p" > /dev/null 2>&1 || new_pkgs+="$p "
done
# Values are quoted because revert sources this file; publish atomically
{
echo "prev_omarchy=\"${prev_omarchy%% *}\""
echo "prev_settings=\"${prev_settings%% *}\""
echo "new_pkgs=\"${new_pkgs% }\""
echo "converted_at=\"$(date +%s)\""
} | sudo tee "$STATE.new" > /dev/null
sudo mv "$STATE.new" "$STATE"
fi
echo "==> 系统更新并换装 OmarchyCN 软件包(替换 ${prev_omarchy%% *}/${prev_settings%% *}"
sudo pacman -Syu --noconfirm
sudo pacman -S --noconfirm omarchycn/omarchycn-keyring
# --ask=4 auto-confirms removing the conflicting upstream omarchy packages
sudo pacman -S --noconfirm --ask=4 omarchycn/omarchy-dev omarchycn/omarchy-settings-dev
sudo pacman -S --needed --noconfirm fcitx5-rime fcitx5-chinese-addons fcitx5-configtool
echo "==> [omarchy] 仓库启用自建镜像(Cloudflare 上游兜底)"
source /usr/share/omarchy/cn/lib/mirror.sh
cn_mirror_omarchy_repo_fix
echo "==> 系统语言 zh_CN.UTF-8"
grep -q '^zh_CN.UTF-8 UTF-8' /etc/locale.gen ||
echo 'zh_CN.UTF-8 UTF-8' | sudo tee -a /etc/locale.gen > /dev/null
sudo locale-gen > /dev/null
if grep -q '^LANG=' /etc/locale.conf 2> /dev/null; then
sudo sed -i 's/^LANG=.*/LANG=zh_CN.UTF-8/' /etc/locale.conf
else
echo 'LANG=zh_CN.UTF-8' | sudo tee -a /etc/locale.conf > /dev/null
fi
echo "==> 中文输入法与字体(用户级)"
OMARCHY_PATH=/usr/share/omarchy bash /usr/share/omarchy/install/user/cn-chinese.sh
systemctl --user restart omarchy-fcitx5.service 2> /dev/null || true
echo "==> Arch 官方仓库切换国内镜像(自动测速,失败则保留现状)"
omarchy-cn-mirror-apply china || echo "国内镜像不可达,保留当前 mirrorlist"
echo "==> OMARCHY CN 开机画面"
omarchy-refresh-plymouth
omarchy-notification-send "OmarchyCN" "转换完成:重新登录后菜单/键位/输入法全中文" 2> /dev/null || true
echo
echo "转换完成(重新登录生效)。回退: omarchy cn revert"
}
main "$@"
+89
View File
@@ -0,0 +1,89 @@
#!/bin/bash
# omarchy:summary=Revert an OmarchyCN conversion back to vanilla Omarchy
# omarchy:examples=omarchy cn revert
# Curl-able and self-deleting-safe: main() is fully parsed before the package
# swap removes this file from the cn tree it may be running from.
set -euo pipefail
STATE_DIR=/var/lib/omarchycn
STATE=$STATE_DIR/convert-state
MIRROR_LINE="Server = https://git.zacharyzhang.com/api/packages/ZacharyZhang-NY/arch/omarchy/x86_64"
REG_KEY_FPR=74DCF57ACD812B24D959F146BD386048867B33B4
# Bootstrap exception: curl|bash runs outside a session, so default the path
export OMARCHY_PATH=${OMARCHY_PATH:-/usr/share/omarchy}
main() {
if [[ ! -f $STATE ]]; then
echo "未发现转换状态($STATE):本机不是由 omarchy cn convert 转换而来" >&2
exit 1
fi
if (( EUID == 0 )); then
echo "请以普通用户运行(脚本内部按需 sudo" >&2
exit 1
fi
local prev_omarchy="" prev_settings="" new_pkgs=""
# State is trusted root-owned key=value lines written by convert
source "$STATE"
[[ -n $prev_omarchy && -n $prev_settings ]] || { echo "转换状态损坏: $STATE" >&2; exit 1; }
echo "==> 清理转换时播种的用户配置(与 cn 层原件一致才删除)"
local seeded
for seeded in \
"$HOME/.config/fcitx5/profile:/usr/share/omarchy/cn/fcitx5/profile" \
"$HOME/.config/fontconfig/conf.d/64-omarchycn-cjk.conf:/usr/share/omarchy/cn/fontconfig/64-omarchycn-cjk.conf"; do
if cmp -s "${seeded%%:*}" "${seeded#*:}" 2> /dev/null; then
rm -f "${seeded%%:*}"
fi
done
echo "==> 还原 mirrorlist 与系统语言"
sudo cp "$STATE_DIR/mirrorlist.pre" /etc/pacman.d/mirrorlist
if [[ -f $STATE_DIR/locale.conf.pre ]]; then
sudo cp "$STATE_DIR/locale.conf.pre" /etc/locale.conf
fi
echo "==> pacman.conf 移除 [omarchycn] 与 [omarchy] 镜像行"
sudo sed -i "\|^$MIRROR_LINE\$|d" /etc/pacman.conf
# Delete the section header and body, but keep any section that follows
sudo sed -i '/^\[omarchycn\]$/,/^\[/{ /^\[omarchycn\]$/d; /^\[/!d; }' /etc/pacman.conf
echo "==> 换回上游软件包($prev_omarchy/$prev_settings"
sudo pacman -Sy
# --ask=4 auto-confirms removing the conflicting cn packages
sudo pacman -S --noconfirm --ask=4 "omarchy/$prev_omarchy" "omarchy/$prev_settings"
if [[ -n $new_pkgs ]]; then
# Only what is still installed: a user may have removed some already,
# and a -R failure here would strand the swap-completed system
local p still=""
for p in $new_pkgs; do
# grep without -q consumes the whole list: -q's early exit would
# SIGPIPE pacman and read as "not installed" under pipefail
pacman -Qq | grep -xF "$p" > /dev/null && still+="$p "
done
if [[ -n $still ]]; then
echo "==> 移除转换时新装的包: ${still% }"
# shellcheck disable=SC2086
sudo pacman -R --noconfirm ${still% }
fi
fi
echo "==> 移除 registry 公钥信任"
sudo pacman-key --delete "$REG_KEY_FPR" > /dev/null 2>&1 || true
# The system is vanilla again: clear state before the cosmetic tail so a
# plymouth failure cannot strand a reverted machine in "converted" state
systemctl --user restart omarchy-fcitx5.service 2> /dev/null || true
sudo rm -rf "$STATE_DIR"
echo "==> 还原上游开机画面"
if ! omarchy-refresh-plymouth; then
echo "开机画面还原失败:手动执行 omarchy-refresh-plymouth 即可" >&2
exit 1
fi
echo
echo "已回退为原版 Omarchy(重新登录生效)。再次转换: omarchy cn convert"
}
main "$@"