Update clashctl

This commit is contained in:
Arvin
2026-03-21 18:07:16 +08:00
parent 16a13b4bef
commit 04d16bca7f

147
clashctl
View File

@ -273,7 +273,7 @@ cmd_stop() {
}
cmd_update() {
local branch remote_name dirty
local branch remote_name dirty pull_ok=1
if ! has_git_repo; then
err "当前目录不是 Git 仓库: $PROJECT_DIR"
@ -288,17 +288,55 @@ cmd_update() {
remote_name="origin"
dirty="$(git -C "$PROJECT_DIR" status --porcelain --untracked-files=no)"
if [ -n "${dirty:-}" ]; then
err "检测到本地已修改但未提交的文件,已停止更新"
echo "请先提交、stash 或恢复后再执行 clashctl update" >&2
exit 1
# 保护本地 .env如果你已经把 .env 忽略掉,这段也保留,兜底更稳)
if [ -f "$PROJECT_DIR/.env" ]; then
cp -f "$PROJECT_DIR/.env" "$PROJECT_DIR/.env.bak" 2>/dev/null || true
fi
echo "[INFO] pulling latest code from ${remote_name}/${branch} ..."
if ! git -C "$PROJECT_DIR" pull --ff-only "$remote_name" "$branch"; then
err "git pull 失败"
exit 1
dirty="$(git -C "$PROJECT_DIR" status --porcelain --untracked-files=no)"
if [ -n "${dirty:-}" ]; then
echo "[WARN] 检测到本地已修改但未提交的文件,自动切换到安全强制更新模式"
pull_ok=0
fi
if [ "$pull_ok" -eq 1 ]; then
echo "[INFO] pulling latest code from ${remote_name}/${branch} ..."
if ! git -C "$PROJECT_DIR" pull --ff-only "$remote_name" "$branch"; then
echo "[WARN] git pull 失败,自动切换到强制更新模式"
pull_ok=0
fi
fi
if [ "$pull_ok" -eq 0 ]; then
echo "[INFO] fetching latest code from ${remote_name}/${branch} ..."
if ! git -C "$PROJECT_DIR" fetch "$remote_name" "$branch"; then
err "git fetch 失败"
exit 1
fi
echo "[WARN] resetting local code to ${remote_name}/${branch}"
if ! git -C "$PROJECT_DIR" reset --hard "${remote_name}/${branch}"; then
err "git reset --hard 失败"
exit 1
fi
fi
# 恢复 .env
if [ -f "$PROJECT_DIR/.env.bak" ]; then
mv -f "$PROJECT_DIR/.env.bak" "$PROJECT_DIR/.env" 2>/dev/null || true
fi
# 修复脚本权限,避免 203/EXEC
echo "[INFO] fixing executable permissions ..."
chmod +x "$PROJECT_DIR"/scripts/*.sh 2>/dev/null || true
chmod +x "$PROJECT_DIR"/bin/* 2>/dev/null || true
sed -i 's/\r$//' "$PROJECT_DIR"/scripts/*.sh 2>/dev/null || true
# 先停服务,避免 generate 时误判端口占用导致漂移
echo "[INFO] stopping service before regenerate ..."
if has_systemd; then
systemctl stop clash-for-linux.service 2>/dev/null || true
sleep 1
fi
echo "[INFO] regenerating config ..."
@ -309,19 +347,35 @@ cmd_update() {
echo "[INFO] restarting service ..."
if has_systemd; then
if ! systemctl restart clash-for-linux.service; then
err "systemd 启失败"
if ! systemctl start clash-for-linux.service; then
err "systemd 启失败"
exit 1
fi
echo "[INFO] waiting for service to be active ..."
local i state
for i in 1 2 3 4 5 6 7 8 9 10; do
state="$(systemctl is-active clash-for-linux.service 2>/dev/null || true)"
if [ "$state" = "active" ]; then
ok "更新完成"
cmd_status
return 0
fi
sleep 1
done
err "服务启动未就绪"
systemctl status clash-for-linux.service -l --no-pager || true
exit 1
else
if ! "$PROJECT_DIR/scripts/run_clash.sh" --daemon; then
err "脚本模式启动失败"
exit 1
fi
fi
ok "更新完成"
cmd_status
ok "更新完成"
cmd_status
fi
}
cmd_update_force() {
@ -389,18 +443,53 @@ cmd_update_force() {
cmd_status
}
# === 修复执行权限 ===
fix_exec_permissions() {
local dir="${PROJECT_DIR:-$(pwd)}"
chmod +x "$dir"/scripts/*.sh 2>/dev/null || true
chmod +x "$dir"/bin/* 2>/dev/null || true
# 可选:修复 CRLF防止 Windows 换行)
sed -i 's/\r$//' "$dir"/scripts/*.sh 2>/dev/null || true
}
# === 等待 service 进入 active ===
wait_for_service_active() {
local svc="${1:-clash-for-linux.service}"
local timeout="${2:-10}"
for ((i=0; i<timeout; i++)); do
state=$(systemctl is-active "$svc" 2>/dev/null || true)
if [ "$state" = "active" ]; then
return 0
fi
sleep 1
done
return 1
}
# === 获取实际端口(从 runtime/config.yaml 解析)===
get_actual_ports() {
local cfg="$PROJECT_DIR/runtime/config.yaml"
if [ ! -f "$cfg" ]; then
return
fi
ACTUAL_HTTP_PORT=$(grep -E '^mixed-port:' "$cfg" | awk '{print $2}' | tr -d '\r')
ACTUAL_CTRL_PORT=$(grep -E '^external-controller:' "$cfg" | awk -F':' '{print $NF}' | tr -d '\r')
export ACTUAL_HTTP_PORT ACTUAL_CTRL_PORT
}
cmd_restart() {
cmd_generate
cmd_stop "${1:-false}" || true
cmd_start
}
cmd_update() {
git -C "$PROJECT_DIR" pull
cmd_restart
ok "Project updated"
}
cmd_ui() {
local raw="${1:-}"
local controller host port secret base_url
@ -1039,7 +1128,12 @@ main() {
cmd_status
;;
update)
cmd_update
shift
cmd_update "$@"
;;
update-force)
shift
cmd_update_force "$@"
;;
generate)
cmd_generate
@ -1058,14 +1152,7 @@ main() {
shift || true
cmd_sub "${1:-show}"
;;
update)
shift
cmd_update "$@"
;;
update-force)
shift
cmd_update_force "$@"
;;
tun)
shift || true
cmd_tun "${1:-status}"