diff --git a/scripts/starts/clash_modify.sh b/scripts/starts/clash_modify.sh index 493c0e20..39f9a293 100644 --- a/scripts/starts/clash_modify.sh +++ b/scripts/starts/clash_modify.sh @@ -201,6 +201,25 @@ add_custom_inbounds_and_rules() { } } +preserve_geodata_yaml() { + #保留订阅规则依赖的Geo数据设置,本地自定义同名配置优先 + : >"$TMPDIR"/geodata_base.yaml + : >"$TMPDIR"/geodata.yaml + for char in geodata-mode geodata-loader geosite-matcher geo-auto-update geo-update-interval geox-url; do + awk -v key="$char" ' + /^[^[:space:]#]/ { emit = ($0 ~ ("^" key ":")) } + emit { print } + ' "$core_config" >>"$TMPDIR"/geodata_base.yaml + done + for char in geodata-mode geodata-loader geosite-matcher geo-auto-update geo-update-interval geox-url; do + grep -qE "^$char:" "$CRASHDIR"/yamls/user.yaml "$CRASHDIR"/yamls/others.yaml 2>/dev/null && continue + awk -v key="$char" ' + /^[^[:space:]#]/ { emit = ($0 ~ ("^" key ":")) } + emit { print } + ' "$TMPDIR"/geodata_base.yaml >>"$TMPDIR"/geodata.yaml + done +} + merger_yaml() { #mix和route模式生成rule-providers [ "$dns_mod" = "mix" ] || [ "$dns_mod" = "route" ] && ! grep -Eq '^[[:space:]]*cn:' "$TMPDIR"/rule-providers.yaml && ! grep -q '^rule-providers' "$CRASHDIR"/yamls/others.yaml 2>/dev/null && { @@ -229,8 +248,9 @@ merger_yaml() { yaml_add="$yaml_add $TMPDIR/${char}.yaml" } done + preserve_geodata_yaml #合并完整配置文件 - cut -c 1- "$TMPDIR"/set.yaml $yaml_dns $yaml_hosts $yaml_user $yaml_others $yaml_add >"$TMPDIR"/config.yaml + cut -c 1- "$TMPDIR"/set.yaml "$TMPDIR"/geodata.yaml $yaml_dns $yaml_hosts $yaml_user $yaml_others $yaml_add >"$TMPDIR"/config.yaml } test_yaml() { @@ -244,7 +264,7 @@ test_yaml() { sed -i "/#自定义策略组开始/,/#自定义策略组结束/d" "$TMPDIR"/proxy-groups.yaml mv -f "$TMPDIR"/set_bak.yaml "$TMPDIR"/set.yaml >/dev/null 2>&1 #合并基础配置文件 - cut -c 1- "$TMPDIR"/set.yaml $yaml_dns $yaml_add >"$TMPDIR"/config.yaml + cut -c 1- "$TMPDIR"/set.yaml "$TMPDIR"/geodata_base.yaml $yaml_dns $yaml_add >"$TMPDIR"/config.yaml sed -i "/#自定义/d" "$TMPDIR"/config.yaml fi } @@ -253,7 +273,7 @@ finalize_clash_yaml() { #建立软连接 [ ""$TMPDIR"" = ""$BINDIR"" ] || ln -sf "$TMPDIR"/config.yaml "$BINDIR"/config.yaml 2>/dev/null || cp -f "$TMPDIR"/config.yaml "$BINDIR"/config.yaml #清理缓存 - for char in $yaml_char set set_bak dns hosts; do + for char in $yaml_char set set_bak dns hosts geodata geodata_base; do rm -f "$TMPDIR"/${char}.yaml done } diff --git a/tests/clash_geodata.sh b/tests/clash_geodata.sh new file mode 100644 index 00000000..98ddda98 --- /dev/null +++ b/tests/clash_geodata.sh @@ -0,0 +1,93 @@ +#!/bin/sh +# Run with sh tests/clash_geodata.sh [path/to/clash_modify.sh]. +set -e +script=${1:-$(dirname "$0")/../scripts/starts/clash_modify.sh} +. "$script" +test_dir=$(mktemp -d) +trap 'rm -rf "$test_dir"' EXIT HUP INT TERM + +setup() { + CRASHDIR="$test_dir/$1" + TMPDIR="$CRASHDIR/tmp" + BINDIR="$CRASHDIR/bin" + mkdir -p "$CRASHDIR/yamls" "$TMPDIR" "$BINDIR" + core_config="$CRASHDIR/yamls/config.yaml" + dns_mod=redir_host + yaml_char='rules proxy-groups' + yaml_user= yaml_others= yaml_dns= yaml_hosts= + printf 'mode: Rule\n' >"$TMPDIR/set.yaml" + printf ' - GEOSITE,GOOGLE,DIRECT\n' >"$TMPDIR/rules.yaml" + : >"$TMPDIR/proxy-groups.yaml" + cat >"$core_config" <<'EOF' +geodata-mode: true +geodata-loader: memconservative +geosite-matcher: succinct +geo-auto-update: true +geo-update-interval: 24 +geox-url: + geoip: https://example.invalid/geoip.dat + geosite: >- + https://example.invalid/geosite.dat + mmdb: https://example.invalid/Country.mmdb +rules: + - GEOSITE,GOOGLE,DIRECT +mixed-port: 1234 +EOF +} + +assert_line() { + grep -qFx -- "$1" "$TMPDIR/config.yaml" || { + echo "Missing expected line: $1" >&2 + exit 1 + } +} + +setup inherited +merger_yaml +assert_line 'geodata-mode: true' +assert_line 'geodata-loader: memconservative' +assert_line 'geosite-matcher: succinct' +assert_line 'geo-auto-update: true' +assert_line 'geo-update-interval: 24' +assert_line ' https://example.invalid/geosite.dat' +[ "$(grep -c '^rules:' "$TMPDIR/config.yaml")" = 1 ] +! grep -q '^mixed-port: 1234' "$TMPDIR/config.yaml" +finalize_clash_yaml +[ ! -e "$TMPDIR/geodata.yaml" ] +[ ! -e "$TMPDIR/geodata_base.yaml" ] + +setup overrides +printf 'geodata-mode: false\n' >"$CRASHDIR/yamls/user.yaml" +printf 'geox-url: {geosite: https://override.invalid/geosite.dat}\n' >"$CRASHDIR/yamls/others.yaml" +merger_yaml +assert_line 'geodata-mode: false' +assert_line 'geox-url: {geosite: https://override.invalid/geosite.dat}' +[ "$(grep -c '^geodata-mode:' "$TMPDIR/config.yaml")" = 1 ] +[ "$(grep -c '^geox-url:' "$TMPDIR/config.yaml")" = 1 ] +! grep -q 'example.invalid' "$TMPDIR/config.yaml" + +# A rejected custom configuration must fall back to the subscription settings. +printf '#!/bin/sh\nexit 1\n' >"$TMPDIR/CrashCore" +chmod +x "$TMPDIR/CrashCore" +logger() { :; } +set +e +test_yaml +set -e +assert_line 'geodata-mode: true' +assert_line ' https://example.invalid/geosite.dat' +[ "$(grep -c '^geox-url:' "$TMPDIR/config.yaml")" = 1 ] +! grep -q 'override.invalid' "$TMPDIR/config.yaml" + +setup inline +printf 'geox-url: {geosite: https://inline.invalid/geosite.dat}\ngeo-auto-update: false\n---\nmixed-port: 1234\n' >"$core_config" +merger_yaml +assert_line 'geox-url: {geosite: https://inline.invalid/geosite.dat}' +assert_line 'geo-auto-update: false' +! grep -qE '^---|^mixed-port: 1234' "$TMPDIR/config.yaml" + +setup absent +printf 'rules:\n - MATCH,DIRECT\n' >"$core_config" +merger_yaml +! grep -qE '^geo(data|site|x|-)' "$TMPDIR/config.yaml" +assert_line 'mode: Rule' +echo 'PASS: inherited geodata, overrides, fallback, inline maps, cleanup and absent settings'