mirror of
https://github.com/MetaCubeX/Clash.Meta.git
synced 2025-04-11 04:50:56 +00:00
fix: fix zero-value problem in config override
This commit is contained in:
parent
ddd0530902
commit
83279c3772
4 changed files with 52 additions and 45 deletions
|
@ -365,7 +365,7 @@ type RawOverride struct {
|
|||
Hostname string `yaml:"hostname" json:"hostname"`
|
||||
Username string `yaml:"username" json:"username"`
|
||||
ListStrategy ListMergeStrategy `yaml:"list-strategy" json:"list-strategy"`
|
||||
Content *RawConfig `yaml:"content" json:"content"`
|
||||
Content map[string]any `yaml:"content" json:"content"`
|
||||
}
|
||||
|
||||
type RawConfig struct {
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"dario.cat/mergo"
|
||||
"fmt"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
"os/user"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type ListMergeStrategy string
|
||||
|
||||
// insert-front: [old slice] -> [new slice, old slice]
|
||||
// append: [old slice] -> [old slice, new slice]
|
||||
// override: [old slice] -> [new slice] (Default)
|
||||
|
||||
const (
|
||||
InsertFront ListMergeStrategy = "insert-front"
|
||||
Append ListMergeStrategy = "append"
|
||||
|
@ -19,44 +21,9 @@ const (
|
|||
Default ListMergeStrategy = ""
|
||||
)
|
||||
|
||||
// overrideTransformer is to merge slices with give strategy instead of the default behavior
|
||||
// - insert-front: [old slice] -> [new slice, old slice]
|
||||
// - append: [old slice] -> [old slice, new slice]
|
||||
// - override: [old slice] -> [new slice] (Default)
|
||||
type overrideTransformer struct {
|
||||
listStrategy ListMergeStrategy
|
||||
}
|
||||
|
||||
func (t overrideTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
|
||||
if typ.Kind() == reflect.Slice {
|
||||
return func(dst, src reflect.Value) error {
|
||||
if src.IsNil() || !dst.CanSet() {
|
||||
return nil
|
||||
}
|
||||
if src.Kind() != reflect.Slice || dst.Kind() != reflect.Slice {
|
||||
return nil
|
||||
}
|
||||
// merge slice according to strategy
|
||||
switch t.listStrategy {
|
||||
case InsertFront:
|
||||
newSlice := reflect.AppendSlice(src, dst)
|
||||
dst.Set(newSlice)
|
||||
case Append:
|
||||
newSlice := reflect.AppendSlice(dst, src)
|
||||
dst.Set(newSlice)
|
||||
case Override, Default:
|
||||
dst.Set(src)
|
||||
default:
|
||||
return fmt.Errorf("unknown list override strategy: %s", t.listStrategy)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ApplyOverride(rawCfg *RawConfig, overrides []RawOverride) error {
|
||||
for id, override := range overrides {
|
||||
// check override conditions
|
||||
if override.OS != "" && override.OS != runtime.GOOS {
|
||||
continue
|
||||
}
|
||||
|
@ -84,12 +51,29 @@ func ApplyOverride(rawCfg *RawConfig, overrides []RawOverride) error {
|
|||
}
|
||||
}
|
||||
|
||||
// merge rawConfig override
|
||||
err := mergo.Merge(rawCfg, *override.Content, mergo.WithTransformers(overrideTransformer{
|
||||
listStrategy: override.ListStrategy,
|
||||
}), mergo.WithOverride)
|
||||
// marshal override content back to text
|
||||
overrideContent, err := yaml.Marshal(override.Content)
|
||||
if err != nil {
|
||||
log.Errorln("Error when applying override #%v: %v", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// unmarshal override content into rawConfig, with custom list merge strategy
|
||||
switch override.ListStrategy {
|
||||
case Append:
|
||||
options := yaml.NewDecodeOptions().ListDecodeOption(yaml.ListDecodeAppend)
|
||||
err = yaml.UnmarshalWith(options, overrideContent, rawCfg)
|
||||
case InsertFront:
|
||||
options := yaml.NewDecodeOptions().ListDecodeOption(yaml.ListDecodeInsertFront)
|
||||
err = yaml.UnmarshalWith(options, overrideContent, rawCfg)
|
||||
case Override, Default:
|
||||
err = yaml.Unmarshal(overrideContent, rawCfg)
|
||||
default:
|
||||
log.Errorln("Bad list strategy in override #%v: %v", id, override.ListStrategy)
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorln("Error when applying override #%v: %v", id, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -36,6 +36,30 @@ override:
|
|||
assert.Equal(t, "0.0.0.0:9090", cfg.Controller.ExternalController)
|
||||
})
|
||||
|
||||
t.Run("override_zero_value_test", func(t *testing.T) {
|
||||
config_file := `
|
||||
mixed-port: 7890
|
||||
ipv6: true
|
||||
log-level: debug
|
||||
allow-lan: true
|
||||
unified-delay: false
|
||||
tcp-concurrent: true
|
||||
external-controller: 127.0.0.1:9090
|
||||
default-nameserver:
|
||||
- "223.5.5.5"
|
||||
override:
|
||||
- content:
|
||||
external-controller: ""
|
||||
allow-lan: false`
|
||||
rawCfg, err := UnmarshalRawConfig([]byte(config_file))
|
||||
assert.NoError(t, err)
|
||||
cfg, err := ParseRawConfig(rawCfg)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, log.DEBUG, cfg.General.LogLevel)
|
||||
assert.Equal(t, false, cfg.General.AllowLan)
|
||||
assert.Equal(t, "", cfg.Controller.ExternalController)
|
||||
})
|
||||
|
||||
t.Run("add_new", func(t *testing.T) {
|
||||
config_file := `
|
||||
mixed-port: 7890
|
||||
|
|
1
go.mod
1
go.mod
|
@ -3,7 +3,6 @@ module github.com/metacubex/mihomo
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1
|
||||
github.com/3andne/restls-client-go v0.1.6
|
||||
github.com/bahlo/generic-list-go v0.2.0
|
||||
github.com/coreos/go-iptables v0.8.0
|
||||
|
|
Loading…
Add table
Reference in a new issue