mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-10-10 20:23:04 +08:00
refactor(migration): auto-clean legacy subscription and env compat fields
This commit is contained in:
+73
-30
@@ -100,7 +100,7 @@ usage_advanced() {
|
||||
|
||||
💡 Notes:
|
||||
当前编译链固定为 active-only
|
||||
只处理当前主订阅,不再提供 merge / policy / select 编译集合
|
||||
只处理当前 active 主订阅
|
||||
Tun 模式属于高级能力,开启前建议先执行:clashctl tun doctor
|
||||
EOF
|
||||
}
|
||||
@@ -340,27 +340,33 @@ cmd_ui() {
|
||||
esac
|
||||
}
|
||||
|
||||
status_build_mode() {
|
||||
read_build_value "BUILD_MODE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
status_build_active_source() {
|
||||
read_build_value "BUILD_ACTIVE_SOURCE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
status_build_selected_sources() {
|
||||
read_build_value "BUILD_SELECTED_SOURCES" 2>/dev/null || true
|
||||
}
|
||||
status_build_active_sources() {
|
||||
local value
|
||||
|
||||
status_build_included_sources() {
|
||||
value="$(read_build_value "BUILD_ACTIVE_SOURCES" 2>/dev/null || true)"
|
||||
if [ -n "${value:-}" ]; then
|
||||
echo "$value"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 兼容历史 build.env
|
||||
read_build_value "BUILD_INCLUDED_SOURCES" 2>/dev/null || true
|
||||
}
|
||||
|
||||
status_build_min_success_sources() {
|
||||
read_build_value "BUILD_MIN_SUCCESS_SOURCES" 2>/dev/null || true
|
||||
}
|
||||
status_build_failed_active_sources() {
|
||||
local value
|
||||
|
||||
status_build_failed_sources() {
|
||||
value="$(read_build_value "BUILD_FAILED_ACTIVE_SOURCES" 2>/dev/null || true)"
|
||||
if [ -n "${value:-}" ]; then
|
||||
echo "$value"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 兼容历史 build.env
|
||||
read_build_value "BUILD_FAILED_SOURCES" 2>/dev/null || true
|
||||
}
|
||||
|
||||
@@ -1727,7 +1733,7 @@ print_status_summary_compact() {
|
||||
|
||||
print_status_summary_verbose() {
|
||||
local running_text profile mixed_port controller
|
||||
local build_mode current_active build_included build_failed build_status build_time
|
||||
local current_active build_active_sources build_failed_active_sources build_status build_time
|
||||
local build_block_reason build_block_time
|
||||
local last_switch_from last_switch_to last_switch_time
|
||||
local controller_ok current_proxy_lines
|
||||
@@ -1744,10 +1750,9 @@ print_status_summary_verbose() {
|
||||
controller="$(status_read_controller 2>/dev/null || true)"
|
||||
|
||||
|
||||
build_mode="$(status_build_mode)"
|
||||
current_active="$(active_subscription_name 2>/dev/null || true)"
|
||||
build_included="$(status_build_included_sources)"
|
||||
build_failed="$(status_build_failed_sources)"
|
||||
build_active_sources="$(status_build_active_sources)"
|
||||
build_failed_active_sources="$(status_build_failed_active_sources)"
|
||||
build_status="$(status_build_last_status)"
|
||||
build_time="$(status_build_last_time)"
|
||||
|
||||
@@ -1876,8 +1881,8 @@ print_status_summary_verbose() {
|
||||
echo "🧩 最近编译:未知"
|
||||
fi
|
||||
|
||||
[ -n "${build_included:-}" ] && echo "🟢 实际参与编译:$build_included"
|
||||
[ -n "${build_failed:-}" ] && echo "❌ 编译失败源:$build_failed"
|
||||
[ -n "${build_active_sources:-}" ] && echo "🟢 实际参与编译:$build_active_sources"
|
||||
[ -n "${build_failed_active_sources:-}" ] && echo "❌ 编译失败源:$build_failed_active_sources"
|
||||
echo
|
||||
|
||||
echo "【当前订阅健康】"
|
||||
@@ -2109,6 +2114,16 @@ doctor_fail() {
|
||||
echo " ✘ $1"
|
||||
}
|
||||
|
||||
doctor_yq_available() {
|
||||
local yq_path
|
||||
yq_path="$(yq_bin 2>/dev/null || true)"
|
||||
[ -n "${yq_path:-}" ] && [ -x "$yq_path" ]
|
||||
}
|
||||
|
||||
doctor_warn_skip_yq_parse() {
|
||||
doctor_warn "缺少 yq,跳过配置解析类检查"
|
||||
}
|
||||
|
||||
doctor_install_context() {
|
||||
doctor_print_title "安装环境检查"
|
||||
|
||||
@@ -2254,6 +2269,16 @@ doctor_config() {
|
||||
[ -n "${active_profile:-}" ] || active_profile="default"
|
||||
doctor_ok "当前 Profile:$active_profile"
|
||||
|
||||
if ! doctor_yq_available; then
|
||||
doctor_warn_skip_yq_parse
|
||||
if test_runtime_config "$config_file" >/dev/null 2>&1; then
|
||||
doctor_ok "配置校验通过"
|
||||
else
|
||||
doctor_fail "配置校验失败"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
mixed_port="$("$(yq_bin)" eval '.["mixed-port"] // .port // ""' "$config_file" 2>/dev/null | head -n 1)"
|
||||
controller="$("$(yq_bin)" eval '.["external-controller"] // ""' "$config_file" 2>/dev/null | head -n 1)"
|
||||
|
||||
@@ -2287,6 +2312,13 @@ doctor_subscription() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
doctor_ok "订阅策略:active-only"
|
||||
|
||||
if ! doctor_yq_available; then
|
||||
doctor_warn_skip_yq_parse
|
||||
return 0
|
||||
fi
|
||||
|
||||
active="$(active_subscription_name 2>/dev/null || true)"
|
||||
|
||||
total="$("$(yq_bin)" eval '.sources | keys | length' "$file" 2>/dev/null || echo 0)"
|
||||
@@ -2303,7 +2335,6 @@ doctor_subscription() {
|
||||
)"
|
||||
auto_disabled_count="$(printf '%s\n' "${auto_disabled_count:-}" | awk 'NF{c++} END{print c+0}')"
|
||||
|
||||
doctor_ok "订阅策略:active-only"
|
||||
[ -n "${active:-}" ] && doctor_ok "当前主订阅:$active" || doctor_warn "当前主订阅为空"
|
||||
|
||||
doctor_ok "订阅源总数:$total"
|
||||
@@ -2325,15 +2356,15 @@ doctor_subscription() {
|
||||
}
|
||||
|
||||
doctor_build() {
|
||||
local active included failed last_status last_time
|
||||
local active active_sources failed_active_sources last_status last_time
|
||||
local block_reason block_time
|
||||
local error_summary error_detail error_stage
|
||||
|
||||
doctor_print_title "编译状态检查"
|
||||
|
||||
active="$(read_build_value "BUILD_ACTIVE_SOURCE" 2>/dev/null || true)"
|
||||
included="$(read_build_value "BUILD_INCLUDED_SOURCES" 2>/dev/null || true)"
|
||||
failed="$(read_build_value "BUILD_FAILED_SOURCES" 2>/dev/null || true)"
|
||||
active_sources="$(status_build_active_sources 2>/dev/null || true)"
|
||||
failed_active_sources="$(status_build_failed_active_sources 2>/dev/null || true)"
|
||||
last_status="$(read_build_value "BUILD_LAST_STATUS" 2>/dev/null || true)"
|
||||
last_time="$(read_build_value "BUILD_LAST_TIME" 2>/dev/null || true)"
|
||||
error_summary="$(read_build_value "BUILD_LAST_ERROR_SUMMARY" 2>/dev/null || true)"
|
||||
@@ -2342,7 +2373,7 @@ doctor_build() {
|
||||
block_reason="$(read_runtime_event_value "RUNTIME_LAST_BUILD_BLOCK_REASON" 2>/dev/null || true)"
|
||||
block_time="$(read_runtime_event_value "RUNTIME_LAST_BUILD_BLOCK_TIME" 2>/dev/null || true)"
|
||||
|
||||
if [ -z "${active:-}${included:-}${failed:-}${last_status:-}${last_time:-}${error_summary:-}${error_stage:-}${block_reason:-}" ]; then
|
||||
if [ -z "${active:-}${active_sources:-}${failed_active_sources:-}${last_status:-}${last_time:-}${error_summary:-}${error_stage:-}${block_reason:-}" ]; then
|
||||
doctor_warn "未找到编译元数据(build.env)"
|
||||
return 0
|
||||
fi
|
||||
@@ -2355,14 +2386,14 @@ doctor_build() {
|
||||
doctor_warn "当前主订阅为空"
|
||||
fi
|
||||
|
||||
if [ -n "${included:-}" ]; then
|
||||
doctor_ok "实际参与编译:$included"
|
||||
if [ -n "${active_sources:-}" ]; then
|
||||
doctor_ok "实际参与编译:$active_sources"
|
||||
else
|
||||
doctor_warn "没有任何订阅参与编译"
|
||||
fi
|
||||
|
||||
if [ -n "${failed:-}" ]; then
|
||||
doctor_warn "失败订阅源:$failed"
|
||||
if [ -n "${failed_active_sources:-}" ]; then
|
||||
doctor_warn "失败订阅源:$failed_active_sources"
|
||||
else
|
||||
doctor_ok "失败订阅源:无"
|
||||
fi
|
||||
@@ -2462,6 +2493,18 @@ doctor_ports() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! doctor_yq_available; then
|
||||
doctor_warn_skip_yq_parse
|
||||
if [ -x "$(subconverter_bin)" ]; then
|
||||
if is_port_in_use "$(subconverter_port)"; then
|
||||
doctor_ok "subconverter 端口已监听:$(subconverter_port)"
|
||||
else
|
||||
doctor_warn "subconverter 端口未监听:$(subconverter_port)"
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
mixed_port="$("$(yq_bin)" eval '.["mixed-port"] // .port // ""' "$config_file" 2>/dev/null | head -n 1)"
|
||||
controller="$("$(yq_bin)" eval '.["external-controller"] // ""' "$config_file" 2>/dev/null | head -n 1)"
|
||||
controller_port="${controller##*:}"
|
||||
@@ -2798,7 +2841,7 @@ cmd_config() {
|
||||
echo
|
||||
echo "🧩 说明:"
|
||||
echo " 当前编译链固定为 active-only"
|
||||
echo " 只处理当前主订阅,不再提供 merge / policy / select 编译集合"
|
||||
echo " 只处理当前 active 主订阅"
|
||||
echo
|
||||
ui_next "clashctl config show"
|
||||
ui_blank
|
||||
@@ -4682,4 +4725,4 @@ case "$cmd" in
|
||||
esac
|
||||
;;
|
||||
*) die "未知命令:$cmd" ;;
|
||||
esac
|
||||
esac
|
||||
|
||||
+72
-23
@@ -136,7 +136,7 @@ install_arch_text() {
|
||||
}
|
||||
|
||||
install_state_text() {
|
||||
local has_subscription install_ready runtime_ready controller_ready
|
||||
local has_subscription install_ready runtime_ready controller_ready build_status
|
||||
|
||||
if install_has_subscription; then
|
||||
has_subscription="true"
|
||||
@@ -147,35 +147,43 @@ install_state_text() {
|
||||
install_ready="$(read_runtime_event_value "RUNTIME_LAST_INSTALL_READY" 2>/dev/null || true)"
|
||||
runtime_ready="$(install_verify_runtime_ready 2>/dev/null || true)"
|
||||
controller_ready="$(install_verify_controller_ready 2>/dev/null || true)"
|
||||
|
||||
if [ "${install_ready:-false}" = "true" ]; then
|
||||
echo "ready"
|
||||
return 0
|
||||
fi
|
||||
build_status="$(read_build_value "BUILD_LAST_STATUS" 2>/dev/null || true)"
|
||||
|
||||
if [ "${has_subscription:-false}" != "true" ]; then
|
||||
echo "stopped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${runtime_ready:-false}" = "true" ] || [ "${controller_ready:-false}" = "true" ]; then
|
||||
echo "degraded"
|
||||
if [ "${build_status:-}" = "failed" ]; then
|
||||
echo "broken"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "degraded"
|
||||
if [ "${install_ready:-false}" = "true" ] \
|
||||
|| { [ "${runtime_ready:-false}" = "true" ] && [ "${controller_ready:-false}" = "true" ]; }; then
|
||||
echo "ready"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "verifying"
|
||||
}
|
||||
|
||||
install_build_result_text() {
|
||||
local command_ready config_ready
|
||||
local command_ready config_ready build_status
|
||||
|
||||
command_ready="$(install_verify_command_ready 2>/dev/null || true)"
|
||||
config_ready="$(install_verify_config_ready 2>/dev/null || true)"
|
||||
build_status="$(read_build_value "BUILD_LAST_STATUS" 2>/dev/null || true)"
|
||||
|
||||
if [ "${command_ready:-false}" = "true" ] && [ "${config_ready:-false}" = "true" ]; then
|
||||
if [ "${build_status:-}" = "failed" ]; then
|
||||
echo "failed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${command_ready:-false}" = "true" ] && { [ "${config_ready:-false}" = "true" ] || ! install_has_subscription; }; then
|
||||
echo "success"
|
||||
else
|
||||
echo "failed"
|
||||
echo "pending"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -184,7 +192,14 @@ install_next_step_text() {
|
||||
ready)
|
||||
echo "clashctl select"
|
||||
;;
|
||||
degraded)
|
||||
verifying)
|
||||
if install_has_subscription; then
|
||||
echo "clashon"
|
||||
else
|
||||
echo "clashctl add <订阅链接>"
|
||||
fi
|
||||
;;
|
||||
broken)
|
||||
echo "clashctl doctor"
|
||||
;;
|
||||
stopped)
|
||||
@@ -219,6 +234,9 @@ init_project_context() {
|
||||
}
|
||||
|
||||
load_env_if_exists() {
|
||||
local env_file
|
||||
env_file="$PROJECT_DIR/.env"
|
||||
|
||||
if [ -f "$PROJECT_DIR/.env" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
@@ -227,6 +245,7 @@ load_env_if_exists() {
|
||||
fi
|
||||
|
||||
normalize_env_compat
|
||||
cleanup_env_legacy_compat_fields "$env_file"
|
||||
}
|
||||
|
||||
normalize_env_compat() {
|
||||
@@ -262,9 +281,24 @@ normalize_env_compat() {
|
||||
CLASH_SUBSCRIPTION_UA="$CLASH_SUB_UA"
|
||||
fi
|
||||
|
||||
# 已废弃:active-only 主链不再消费该字段
|
||||
unset BUILD_MIN_SUCCESS_SOURCES 2>/dev/null || true
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
cleanup_env_legacy_compat_fields() {
|
||||
local file="$1"
|
||||
|
||||
[ -n "${file:-}" ] || return 0
|
||||
[ -f "$file" ] || return 0
|
||||
|
||||
awk '
|
||||
$0 ~ /^[[:space:]]*(export[[:space:]]+)?BUILD_MIN_SUCCESS_SOURCES=/ { next }
|
||||
{ print }
|
||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||
}
|
||||
|
||||
github_proxy_prefix() {
|
||||
local prefix="${CLASH_GH_PROXY:-}"
|
||||
prefix="${prefix%/}"
|
||||
@@ -2175,7 +2209,7 @@ remove_alias_command_wrappers() {
|
||||
}
|
||||
|
||||
install_status_text() {
|
||||
local has_subscription install_ready runtime_ready controller_ready
|
||||
local has_subscription install_ready runtime_ready controller_ready build_status
|
||||
local live_runtime="false"
|
||||
local live_controller="false"
|
||||
|
||||
@@ -2188,6 +2222,7 @@ install_status_text() {
|
||||
install_ready="$(read_runtime_event_value "RUNTIME_LAST_INSTALL_READY" 2>/dev/null || true)"
|
||||
runtime_ready="$(install_verify_runtime_ready 2>/dev/null || true)"
|
||||
controller_ready="$(install_verify_controller_ready 2>/dev/null || true)"
|
||||
build_status="$(read_build_value "BUILD_LAST_STATUS" 2>/dev/null || true)"
|
||||
|
||||
if status_is_running 2>/dev/null; then
|
||||
live_runtime="true"
|
||||
@@ -2202,6 +2237,11 @@ install_status_text() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${build_status:-}" = "failed" ]; then
|
||||
echo "broken"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${live_runtime:-false}" = "true" ] && [ "${live_controller:-false}" = "true" ]; then
|
||||
echo "ready"
|
||||
return 0
|
||||
@@ -2216,18 +2256,18 @@ install_status_text() {
|
||||
if [ "${live_runtime:-false}" = "true" ] \
|
||||
|| [ "${runtime_ready:-false}" = "true" ] \
|
||||
|| [ "${controller_ready:-false}" = "true" ]; then
|
||||
echo "degraded"
|
||||
echo "verifying"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "degraded"
|
||||
echo "verifying"
|
||||
}
|
||||
|
||||
install_status_label() {
|
||||
case "$(install_status_text)" in
|
||||
ready) echo "ready" ;;
|
||||
stopped) echo "stopped" ;;
|
||||
degraded) echo "degraded" ;;
|
||||
verifying) echo "verifying" ;;
|
||||
broken) echo "broken" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
@@ -2245,7 +2285,14 @@ install_default_next_action() {
|
||||
echo "clashctl add <订阅链接>"
|
||||
fi
|
||||
;;
|
||||
degraded|broken)
|
||||
verifying)
|
||||
if status_is_running 2>/dev/null; then
|
||||
echo "clashctl status"
|
||||
else
|
||||
echo "clashon"
|
||||
fi
|
||||
;;
|
||||
broken)
|
||||
if install_has_subscription; then
|
||||
echo "clashctl doctor"
|
||||
else
|
||||
@@ -2277,8 +2324,9 @@ install_runtime_brief_line() {
|
||||
stopped)
|
||||
echo "🔴 当前状态:stopped"
|
||||
;;
|
||||
degraded)
|
||||
echo "🟡 当前状态:degraded"
|
||||
verifying)
|
||||
echo "🟡 当前状态:verifying"
|
||||
echo "🧭 正在确认运行状态,可继续观察或手动启动"
|
||||
if [ -n "${mixed_port:-}" ]; then
|
||||
echo "🌐 本地代理:http://127.0.0.1:${mixed_port}"
|
||||
fi
|
||||
@@ -2332,8 +2380,9 @@ print_install_summary() {
|
||||
stopped)
|
||||
echo "🚦 当前状态:⚪ stopped"
|
||||
;;
|
||||
degraded)
|
||||
echo "🚦 当前状态:🟡 degraded"
|
||||
verifying)
|
||||
echo "🚦 当前状态:🟡 verifying"
|
||||
echo "🧭 安装已完成,运行状态仍在确认中"
|
||||
if [ -n "${mixed_port:-}" ]; then
|
||||
echo "🌐 本地代理:http://127.0.0.1:${mixed_port}"
|
||||
fi
|
||||
@@ -2351,4 +2400,4 @@ print_install_summary() {
|
||||
|
||||
echo "👉 下一步:${next_action}"
|
||||
echo
|
||||
}
|
||||
}
|
||||
|
||||
+80
-144
@@ -60,18 +60,39 @@ subscriptions_file() {
|
||||
echo "$CONFIG_DIR/subscriptions.yaml"
|
||||
}
|
||||
|
||||
migrate_subscriptions_legacy_fields() {
|
||||
local file="$1"
|
||||
[ -f "$file" ] || return 0
|
||||
|
||||
if [ -x "$(yq_bin 2>/dev/null || true)" ]; then
|
||||
if "$(yq_bin)" eval '(.mode != null) or (.selected != null) or (.policy != null)' "$file" 2>/dev/null | grep -qx 'true'; then
|
||||
"$(yq_bin)" eval -i 'del(.mode) | del(.selected) | del(.policy)' "$file" 2>/dev/null || true
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 无 yq 时做最小兜底:仅移除顶层旧字段,避免旧语义继续扩散
|
||||
awk '
|
||||
$0 ~ /^[[:space:]]*mode:[[:space:]]*/ { next }
|
||||
$0 ~ /^[[:space:]]*selected:[[:space:]]*/ { next }
|
||||
$0 ~ /^[[:space:]]*policy:[[:space:]]*/ { next }
|
||||
{ print }
|
||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||
}
|
||||
|
||||
ensure_subscriptions_file() {
|
||||
local file
|
||||
file="$(subscriptions_file)"
|
||||
|
||||
[ -f "$file" ] && return 0
|
||||
if [ -f "$file" ]; then
|
||||
migrate_subscriptions_legacy_fields "$file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
|
||||
cat > "$file" <<'EOF'
|
||||
mode: single
|
||||
active: default
|
||||
selected: []
|
||||
|
||||
sources:
|
||||
default:
|
||||
@@ -79,10 +100,8 @@ sources:
|
||||
url: ""
|
||||
enabled: true
|
||||
EOF
|
||||
}
|
||||
|
||||
build_min_success_sources() {
|
||||
echo "1"
|
||||
migrate_subscriptions_legacy_fields "$file"
|
||||
}
|
||||
|
||||
csv_count() {
|
||||
@@ -490,19 +509,15 @@ record_build_failure() {
|
||||
local selected="$4"
|
||||
local included="$5"
|
||||
local failed="$6"
|
||||
local min_required
|
||||
|
||||
min_required="$(build_min_success_sources)"
|
||||
|
||||
write_build_value "BUILD_MODE" "$mode"
|
||||
write_build_value "BUILD_POLICY" "$policy"
|
||||
# active-only 元数据:只记录当前实际参与编译的 active 订阅集合
|
||||
# 为避免旧状态文件混淆,同时清空旧 key
|
||||
write_build_value "BUILD_ACTIVE_SOURCE" "$active"
|
||||
write_build_value "BUILD_SELECTED_SOURCES" "$selected"
|
||||
write_build_value "BUILD_INCLUDED_SOURCES" "$included"
|
||||
write_build_value "BUILD_FAILED_SOURCES" "$failed"
|
||||
write_build_value "BUILD_SOURCE_COUNT" "$(csv_count "$selected")"
|
||||
write_build_value "BUILD_INCLUDED_COUNT" "$(csv_count "$included")"
|
||||
write_build_value "BUILD_MIN_SUCCESS_SOURCES" "$min_required"
|
||||
write_build_value "BUILD_ACTIVE_SOURCES" "$included"
|
||||
write_build_value "BUILD_FAILED_ACTIVE_SOURCES" "$failed"
|
||||
write_build_value "BUILD_SELECTED_SOURCES" ""
|
||||
write_build_value "BUILD_INCLUDED_SOURCES" ""
|
||||
write_build_value "BUILD_FAILED_SOURCES" ""
|
||||
write_build_value "BUILD_LAST_STATUS" "failed"
|
||||
write_build_value "BUILD_LAST_TIME" "$(now_datetime)"
|
||||
}
|
||||
@@ -514,19 +529,13 @@ record_build_success() {
|
||||
local selected="$4"
|
||||
local included="$5"
|
||||
local failed="$6"
|
||||
local min_required
|
||||
|
||||
min_required="$(build_min_success_sources)"
|
||||
|
||||
write_build_value "BUILD_MODE" "$mode"
|
||||
write_build_value "BUILD_POLICY" "$policy"
|
||||
write_build_value "BUILD_ACTIVE_SOURCE" "$active"
|
||||
write_build_value "BUILD_SELECTED_SOURCES" "$selected"
|
||||
write_build_value "BUILD_INCLUDED_SOURCES" "$included"
|
||||
write_build_value "BUILD_FAILED_SOURCES" "$failed"
|
||||
write_build_value "BUILD_SOURCE_COUNT" "$(csv_count "$selected")"
|
||||
write_build_value "BUILD_INCLUDED_COUNT" "$(csv_count "$included")"
|
||||
write_build_value "BUILD_MIN_SUCCESS_SOURCES" "$min_required"
|
||||
write_build_value "BUILD_ACTIVE_SOURCES" "$included"
|
||||
write_build_value "BUILD_FAILED_ACTIVE_SOURCES" "$failed"
|
||||
write_build_value "BUILD_SELECTED_SOURCES" ""
|
||||
write_build_value "BUILD_INCLUDED_SOURCES" ""
|
||||
write_build_value "BUILD_FAILED_SOURCES" ""
|
||||
write_build_value "BUILD_LAST_STATUS" "success"
|
||||
write_build_value "BUILD_LAST_TIME" "$(now_datetime)"
|
||||
clear_build_error_detail
|
||||
@@ -937,7 +946,7 @@ print_build_explain() {
|
||||
error_detail="$(status_build_last_error_detail 2>/dev/null || true)"
|
||||
|
||||
ui_title "🧩 编译说明"
|
||||
echo "- 当前编译链只处理 active 主订阅,不再 merge 多订阅"
|
||||
echo "- 当前编译链只处理 active 主订阅"
|
||||
echo "- 当前主订阅:${active:-未设置}"
|
||||
|
||||
case "${last_status:-unknown}" in
|
||||
@@ -962,16 +971,30 @@ print_build_explain() {
|
||||
ui_blank
|
||||
}
|
||||
|
||||
build_selected_sources_csv() {
|
||||
read_build_value "BUILD_SELECTED_SOURCES" 2>/dev/null || true
|
||||
build_active_sources_csv() {
|
||||
local value
|
||||
value="$(read_build_value "BUILD_ACTIVE_SOURCES" 2>/dev/null || true)"
|
||||
if [ -n "${value:-}" ]; then
|
||||
echo "$value"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 兼容历史 build.env
|
||||
value="$(read_build_value "BUILD_INCLUDED_SOURCES" 2>/dev/null || true)"
|
||||
[ -n "${value:-}" ] && echo "$value"
|
||||
}
|
||||
|
||||
build_included_sources_csv() {
|
||||
read_build_value "BUILD_INCLUDED_SOURCES" 2>/dev/null || true
|
||||
}
|
||||
build_failed_active_sources_csv() {
|
||||
local value
|
||||
value="$(read_build_value "BUILD_FAILED_ACTIVE_SOURCES" 2>/dev/null || true)"
|
||||
if [ -n "${value:-}" ]; then
|
||||
echo "$value"
|
||||
return 0
|
||||
fi
|
||||
|
||||
build_failed_sources_csv() {
|
||||
read_build_value "BUILD_FAILED_SOURCES" 2>/dev/null || true
|
||||
# 兼容历史 build.env
|
||||
value="$(read_build_value "BUILD_FAILED_SOURCES" 2>/dev/null || true)"
|
||||
[ -n "${value:-}" ] && echo "$value"
|
||||
}
|
||||
|
||||
build_last_status() {
|
||||
@@ -995,66 +1018,36 @@ build_last_error_detail() {
|
||||
}
|
||||
|
||||
build_success_explanation_lines() {
|
||||
local mode policy included_csv failed_csv included_count min_required
|
||||
local included_csv included_count
|
||||
|
||||
mode="$(subscription_mode 2>/dev/null || true)"
|
||||
policy="$(subscription_policy 2>/dev/null || true)"
|
||||
included_csv="$(build_included_sources_csv)"
|
||||
failed_csv="$(build_failed_sources_csv)"
|
||||
included_csv="$(build_active_sources_csv)"
|
||||
included_count="$(csv_count "$included_csv")"
|
||||
min_required="$(build_min_success_sources)"
|
||||
|
||||
case "$mode" in
|
||||
single)
|
||||
echo "- single 模式下仅当前主订阅参与编译"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "- 实际成功源数量 ${included_count},达到最少成功源要求 ${min_required}"
|
||||
echo "- active-only 编译链仅处理当前主订阅"
|
||||
echo "- 当前成功源数量:${included_count}"
|
||||
}
|
||||
|
||||
build_failure_explanation_lines() {
|
||||
local mode policy included_csv failed_csv included_count min_required error_stage
|
||||
local included_csv included_count error_stage
|
||||
|
||||
mode="$(subscription_mode 2>/dev/null || true)"
|
||||
policy="$(subscription_policy 2>/dev/null || true)"
|
||||
included_csv="$(build_included_sources_csv)"
|
||||
failed_csv="$(build_failed_sources_csv)"
|
||||
included_csv="$(build_active_sources_csv)"
|
||||
failed_csv="$(build_failed_active_sources_csv)"
|
||||
included_count="$(csv_count "$included_csv")"
|
||||
min_required="$(build_min_success_sources)"
|
||||
error_stage="$(build_last_error_stage)"
|
||||
|
||||
case "$mode" in
|
||||
single)
|
||||
echo "- single 模式下仅当前主订阅参与编译"
|
||||
;;
|
||||
merge)
|
||||
echo "- merge 模式下 selected 集合参与编译"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$policy" in
|
||||
strict)
|
||||
if [ -n "${failed_csv:-}" ]; then
|
||||
echo "- strict 策略下任一订阅失败都会导致整体失败"
|
||||
fi
|
||||
;;
|
||||
tolerant)
|
||||
if [ "$error_stage" = "min-success-threshold" ]; then
|
||||
echo "- tolerant 虽允许跳过失败源,但仍必须满足最少成功源要求"
|
||||
elif [ -n "${failed_csv:-}" ]; then
|
||||
echo "- tolerant 已跳过失败源,但后续校验仍未通过"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "- 实际成功源数量 ${included_count},最少成功源要求 ${min_required}"
|
||||
echo "- active-only 编译链仅处理当前主订阅"
|
||||
if [ "$error_stage" = "resolve-active-source" ]; then
|
||||
echo "- 当前未找到可用的 active 主订阅"
|
||||
elif [ -n "${failed_csv:-}" ]; then
|
||||
echo "- 当前 active 主订阅拉取或校验失败"
|
||||
fi
|
||||
echo "- 当前成功源数量:${included_count}"
|
||||
}
|
||||
|
||||
print_build_failed_source_lines() {
|
||||
local failed_csv name last_error
|
||||
|
||||
failed_csv="$(build_failed_sources_csv)"
|
||||
failed_csv="$(build_failed_active_sources_csv)"
|
||||
[ -n "${failed_csv:-}" ] || return 0
|
||||
|
||||
IFS=',' read -r -a _failed_names <<< "$failed_csv"
|
||||
@@ -1073,7 +1066,7 @@ build_explain_next_steps() {
|
||||
local last_status failed_csv
|
||||
|
||||
last_status="$(build_last_status)"
|
||||
failed_csv="$(build_failed_sources_csv)"
|
||||
failed_csv="$(build_failed_active_sources_csv)"
|
||||
|
||||
if [ "${last_status:-}" = "success" ]; then
|
||||
echo "👉 clashctl health"
|
||||
@@ -1085,10 +1078,6 @@ build_explain_next_steps() {
|
||||
echo "👉 clashctl health"
|
||||
fi
|
||||
|
||||
if [ "$(subscription_mode 2>/dev/null || true)" = "merge" ]; then
|
||||
echo "👉 clashctl config select list"
|
||||
fi
|
||||
|
||||
echo "👉 clashctl doctor"
|
||||
}
|
||||
|
||||
@@ -1289,38 +1278,6 @@ subscription_format_by_name() {
|
||||
"$(yq_bin)" eval ".sources.${name}.type // \"clash\"" "$file" 2>/dev/null | head -n 1
|
||||
}
|
||||
|
||||
merge_subscription_sources() {
|
||||
local base_file="$1"
|
||||
local sub_file="$2"
|
||||
local out_file="$3"
|
||||
local tmp_file
|
||||
|
||||
[ -s "$base_file" ] || die "基础配置不存在:$base_file"
|
||||
[ -s "$sub_file" ] || die "订阅配置不存在:$sub_file"
|
||||
|
||||
tmp_file="$(mktemp)"
|
||||
cp -f "$base_file" "$tmp_file"
|
||||
|
||||
BASE_FILE="$base_file" \
|
||||
SUB_FILE="$sub_file" \
|
||||
"$(yq_bin)" eval -i '
|
||||
.proxies = (load(strenv(SUB_FILE)).proxies // []) |
|
||||
.["proxy-groups"] = (load(strenv(SUB_FILE)).["proxy-groups"] // (.["proxy-groups"] // [])) |
|
||||
.["rule-providers"] = ((.["rule-providers"] // {}) * (load(strenv(SUB_FILE)).["rule-providers"] // {})) |
|
||||
.rules = (load(strenv(SUB_FILE)).rules // (.rules // []))
|
||||
' "$tmp_file" || {
|
||||
rm -f "$tmp_file" 2>/dev/null || true
|
||||
die "合并订阅配置失败"
|
||||
}
|
||||
|
||||
[ -s "$tmp_file" ] || {
|
||||
rm -f "$tmp_file" 2>/dev/null || true
|
||||
die "合并订阅配置失败:输出为空"
|
||||
}
|
||||
|
||||
mv -f "$tmp_file" "$out_file"
|
||||
}
|
||||
|
||||
is_valid_port_number() {
|
||||
local port="$1"
|
||||
|
||||
@@ -1817,8 +1774,7 @@ remove_subscription() {
|
||||
active="$(active_subscription_name)"
|
||||
|
||||
NAME="$name" "$(yq_bin)" eval -i '
|
||||
del(.sources[env(NAME)]) |
|
||||
.selected = ((.selected // []) | map(select(. != env(NAME))))
|
||||
del(.sources[env(NAME)])
|
||||
' "$file"
|
||||
|
||||
if [ "$active" = "$name" ]; then
|
||||
@@ -1861,7 +1817,6 @@ rename_subscription() {
|
||||
OLD_NAME="$old_name" NEW_NAME="$new_name" "$(yq_bin)" eval -i '
|
||||
.sources[env(NEW_NAME)] = .sources[env(OLD_NAME)] |
|
||||
del(.sources[env(OLD_NAME)]) |
|
||||
.selected = ((.selected // []) | map(if . == env(OLD_NAME) then env(NEW_NAME) else . end)) |
|
||||
.active = (if .active == env(OLD_NAME) then env(NEW_NAME) else .active end)
|
||||
' "$file"
|
||||
|
||||
@@ -2356,11 +2311,10 @@ list_subscriptions_verbose() {
|
||||
}
|
||||
|
||||
subscription_list_overview_lines() {
|
||||
local active recommended mode
|
||||
local active recommended
|
||||
|
||||
active="$(active_subscription_name 2>/dev/null || true)"
|
||||
recommended="$(recommended_subscription_name 2>/dev/null || true)"
|
||||
mode="$(subscription_mode 2>/dev/null || true)"
|
||||
|
||||
if [ -n "${active:-}" ]; then
|
||||
echo "📡 当前主订阅:$active"
|
||||
@@ -2376,17 +2330,14 @@ subscription_list_overview_lines() {
|
||||
echo "💡 推荐订阅:暂无"
|
||||
fi
|
||||
|
||||
if [ -n "${mode:-}" ]; then
|
||||
echo "🧩 当前模式:$mode"
|
||||
fi
|
||||
echo "🧩 编译模式:active-only"
|
||||
}
|
||||
|
||||
subscription_list_recommendation_lines() {
|
||||
local active recommended mode
|
||||
local active recommended
|
||||
|
||||
active="$(active_subscription_name 2>/dev/null || true)"
|
||||
recommended="$(recommended_subscription_name 2>/dev/null || true)"
|
||||
mode="$(subscription_mode 2>/dev/null || true)"
|
||||
|
||||
if [ -n "${active:-}" ] && ! active_subscription_enabled 2>/dev/null; then
|
||||
echo "👉 clashctl use"
|
||||
@@ -2402,13 +2353,6 @@ subscription_list_recommendation_lines() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${mode:-}" = "merge" ]; then
|
||||
echo "👉 clashctl config show"
|
||||
echo "👉 clashctl health"
|
||||
echo "👉 clashctl ls --verbose"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "👉 clashctl use"
|
||||
echo "👉 clashctl health"
|
||||
echo "👉 clashctl ls --verbose"
|
||||
@@ -2964,14 +2908,6 @@ profile_set_value() {
|
||||
|
||||
# ===== FINAL OVERRIDE: active-only runtime pipeline =====
|
||||
|
||||
subscription_mode() {
|
||||
echo "single"
|
||||
}
|
||||
|
||||
subscription_policy() {
|
||||
echo "active-only"
|
||||
}
|
||||
|
||||
resolve_build_sources() {
|
||||
local active
|
||||
|
||||
@@ -3153,4 +3089,4 @@ generate_config() {
|
||||
|
||||
regenerate_config() {
|
||||
generate_config
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user