From 73d2bc0993777711144f6adc78099d94e3e11fb6 Mon Sep 17 00:00:00 2001 From: Arvin <62139570+wnlen@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:57:37 +0800 Subject: [PATCH] migrate mixin to runtime path with legacy compatibility --- README.md | 8 ++-- scripts/core/clashctl.sh | 5 ++- scripts/core/config.sh | 94 +++++++++++++++++++++++++++++++++------- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index cef2c2a..7e143dc 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ Control 层负责把常用动作收口成可理解的命令和反馈。 - 单 active 主订阅 - active-only 编译链 - 订阅下载 / 转换 / 校验 -- `config/mixin.yaml` 运行补丁 +- `runtime/mixin.yaml` 运行补丁(兼容读取 `config/mixin.yaml`) - 输出 `runtime/config.yaml` 当前规则很明确:`generate_config` 只处理当前 active 主订阅。 @@ -307,7 +307,7 @@ resources/geo/Country.mmdb 也可以设置 `CLASH_BUNDLED_ASSET_ENABLED=false` 强制跳过内置文件,或用 `CLASH_BUNDLED_ASSET_DIR=/path/to/assets` 指向项目外的资源目录。Mihomo、yq、subconverter 兼容旧路径 `resources/bin///`。 -### `config/mixin.yaml` +### `runtime/mixin.yaml`(兼容 `config/mixin.yaml`) 用于对最终运行配置做补丁: @@ -359,7 +359,7 @@ clashctl mixin raw clashctl mixin runtime ``` -Mixin 是运行配置补丁,不是订阅管理。它通过 `config/mixin.yaml` 对当前 active 订阅生成的运行配置执行: +Mixin 是运行配置补丁,不是订阅管理。它优先通过 `runtime/mixin.yaml`(兼容读取 `config/mixin.yaml`)对当前 active 订阅生成的运行配置执行: - `override` - `prepend` @@ -395,7 +395,7 @@ clashctl mixin edit ### 多跳节点 -多跳节点会写入 `config/mixin.yaml`,通过 Mihomo/Clash 的 `relay` 策略组串联已有订阅节点。节点名称必须与订阅生成的节点名完全一致,可先通过 Web 控制台确认: +多跳节点会写入 `runtime/mixin.yaml`(兼容读取 `config/mixin.yaml`),通过 Mihomo/Clash 的 `relay` 策略组串联已有订阅节点。节点名称必须与订阅生成的节点名完全一致,可先通过 Web 控制台确认: ```bash clashon diff --git a/scripts/core/clashctl.sh b/scripts/core/clashctl.sh index aeeb991..b447f2f 100644 --- a/scripts/core/clashctl.sh +++ b/scripts/core/clashctl.sh @@ -3829,7 +3829,8 @@ cmd_profile() { } mixin_config_file() { - echo "$CONFIG_DIR/mixin.yaml" + ensure_mixin_file + echo "$(mixin_file)" } active_subscription_runtime_raw_file() { @@ -4284,7 +4285,7 @@ cmd_relay() { echo " clashctl relay add 全局多跳 节点A 节点B --match" echo echo "说明:" - echo " add 会写入 config/mixin.yaml,并重新生成运行配置" + echo " add 会写入 runtime/mixin.yaml(兼容读取 config/mixin.yaml),并重新生成运行配置" echo " --domain 用于小范围测试,--match 会让所有未提前命中的流量走多跳" echo " 节点名称必须与订阅生成的节点名完全一致" ;; diff --git a/scripts/core/config.sh b/scripts/core/config.sh index bb51187..4cf9339 100644 --- a/scripts/core/config.sh +++ b/scripts/core/config.sh @@ -297,18 +297,6 @@ proxy-groups: [] rules: [] EOF - [ -f "$CONFIG_DIR/mixin.yaml" ] || cat > "$CONFIG_DIR/mixin.yaml" <<'EOF' -override: {} -prepend: - proxies: [] - proxy-groups: [] - rules: [] -append: - proxies: [] - proxy-groups: [] - rules: [] -EOF - [ -f "$CONFIG_DIR/profiles.yaml" ] || cat > "$CONFIG_DIR/profiles.yaml" <<'EOF' active: default profiles: @@ -1974,17 +1962,93 @@ mark_install_port_plan() { } mixin_file() { + echo "$RUNTIME_DIR/mixin.yaml" +} + +mixin_legacy_file() { echo "$CONFIG_DIR/mixin.yaml" } +write_default_mixin_template() { + local file="$1" + cat > "$file" <<'EOF' +override: {} +prepend: + proxies: [] + proxy-groups: [] + rules: [] +append: + proxies: [] + proxy-groups: [] + rules: [] +EOF +} + +mixin_conflict_notice_file() { + echo "$RUNTIME_DIR/.mixin-conflict-noticed" +} + +warn_mixin_path_conflict_once() { + local notice_file + notice_file="$(mixin_conflict_notice_file)" + if [ -f "$notice_file" ]; then + return 0 + fi + + warn "检测到新旧 mixin 配置同时存在且内容不一致。将优先使用 $(mixin_file),旧文件 $(mixin_legacy_file) 仅保留兼容读取。" + warn "迁移建议:请将 $(mixin_legacy_file) 的自定义内容合并到 $(mixin_file),并停止修改旧路径。" + + mkdir -p "$RUNTIME_DIR" + : > "$notice_file" +} + +mixin_read_file() { + local new_file legacy_file + new_file="$(mixin_file)" + legacy_file="$(mixin_legacy_file)" + + if [ -f "$new_file" ]; then + if [ -f "$legacy_file" ] && ! cmp -s "$new_file" "$legacy_file" 2>/dev/null; then + warn_mixin_path_conflict_once + fi + echo "$new_file" + return 0 + fi + + if [ -f "$legacy_file" ]; then + echo "$legacy_file" + return 0 + fi + + echo "$new_file" +} + +migrate_legacy_mixin_to_runtime_if_needed() { + local new_file legacy_file + new_file="$(mixin_file)" + legacy_file="$(mixin_legacy_file)" + + [ -f "$new_file" ] && return 0 + [ -f "$legacy_file" ] || return 0 + + mkdir -p "$RUNTIME_DIR" + cp -f "$legacy_file" "$new_file" 2>/dev/null || true +} + ensure_mixin_file() { ensure_config_files + migrate_legacy_mixin_to_runtime_if_needed + + if [ ! -f "$(mixin_file)" ]; then + mkdir -p "$RUNTIME_DIR" + write_default_mixin_template "$(mixin_file)" + fi } apply_mixin_override() { local runtime_file="$1" local mixin_file_path - mixin_file_path="$(mixin_file)" + mixin_file_path="$(mixin_read_file)" [ -s "$runtime_file" ] || die "运行配置不存在:$runtime_file" [ -f "$mixin_file_path" ] || return 0 @@ -1998,7 +2062,7 @@ apply_mixin_override() { apply_mixin_prepend_arrays() { local runtime_file="$1" local mixin_file_path - mixin_file_path="$(mixin_file)" + mixin_file_path="$(mixin_read_file)" [ -s "$runtime_file" ] || die "运行配置不存在:$runtime_file" [ -f "$mixin_file_path" ] || return 0 @@ -2014,7 +2078,7 @@ apply_mixin_prepend_arrays() { apply_mixin_append_arrays() { local runtime_file="$1" local mixin_file_path - mixin_file_path="$(mixin_file)" + mixin_file_path="$(mixin_read_file)" [ -s "$runtime_file" ] || die "运行配置不存在:$runtime_file" [ -f "$mixin_file_path" ] || return 0