fix: use yaml.v2 as yaml parser (#37423)

issue: #34298 
Viper uses yaml.v2 as the parser. This PR will adopt the parsing logic
from Viper to handle YAML files, ensuring maximum consistency in
parsing.

Signed-off-by: xianliang.li <xianliang.li@zilliz.com>
This commit is contained in:
foxspy 2024-11-11 21:26:27 +08:00 committed by GitHub
parent 1b6edd0b4b
commit 81141bd18d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 61 deletions

View File

@ -17,10 +17,11 @@
package config package config
import ( import (
"fmt"
"strings" "strings"
"github.com/cockroachdb/errors" "github.com/cockroachdb/errors"
"gopkg.in/yaml.v3" "github.com/spf13/cast"
"github.com/milvus-io/milvus/pkg/util/typeutil" "github.com/milvus-io/milvus/pkg/util/typeutil"
) )
@ -80,48 +81,41 @@ func formatKey(key string) string {
return result return result
} }
func flattenNode(node *yaml.Node, parentKey string, result map[string]string) { func flattenAndMergeMap(prefix string, m map[string]interface{}, result map[string]string) {
// The content of the node should contain key-value pairs in a MappingNode for k, v := range m {
if node.Kind == yaml.MappingNode { fullKey := k
for i := 0; i < len(node.Content); i += 2 { if prefix != "" {
keyNode := node.Content[i] fullKey = prefix + "." + k
valueNode := node.Content[i+1]
key := keyNode.Value
// Construct the full key with parent hierarchy
fullKey := key
if parentKey != "" {
fullKey = parentKey + "." + key
} }
switch valueNode.Kind { switch val := v.(type) {
case yaml.ScalarNode: case map[string]interface{}:
// handle null value flattenAndMergeMap(fullKey, val, result)
if valueNode.Tag == "!!null" { case map[interface{}]interface{}:
result[lowerKey(fullKey)] = "" flattenAndMergeMap(fullKey, cast.ToStringMap(val), result)
result[formatKey(fullKey)] = "" case []interface{}:
str := ""
for i, item := range val {
itemStr, err := cast.ToStringE(item)
if err != nil {
continue
}
if i == 0 {
str = itemStr
} else { } else {
// Scalar value, store it as a string str = str + "," + itemStr
result[lowerKey(fullKey)] = valueNode.Value
result[formatKey(fullKey)] = valueNode.Value
}
case yaml.MappingNode:
// Nested map, process recursively
flattenNode(valueNode, fullKey, result)
case yaml.SequenceNode:
// List (sequence), process elements
var listStr string
for j, item := range valueNode.Content {
if j > 0 {
listStr += ","
}
if item.Kind == yaml.ScalarNode {
listStr += item.Value
} }
} }
result[lowerKey(fullKey)] = listStr result[lowerKey(fullKey)] = str
result[formatKey(fullKey)] = listStr result[formatKey(fullKey)] = str
} default:
str, err := cast.ToStringE(val)
if err != nil {
fmt.Printf("cast to string failed %s, error = %s\n", fullKey, err.Error())
continue
}
result[lowerKey(fullKey)] = str
result[formatKey(fullKey)] = str
} }
} }
} }

View File

@ -17,9 +17,7 @@
package config package config
import ( import (
"bytes"
"fmt" "fmt"
"io"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
@ -27,7 +25,7 @@ import (
"github.com/cockroachdb/errors" "github.com/cockroachdb/errors"
"github.com/samber/lo" "github.com/samber/lo"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v2"
"github.com/milvus-io/milvus/pkg/log" "github.com/milvus-io/milvus/pkg/log"
) )
@ -131,7 +129,7 @@ func (fs *FileSource) loadFromFile() error {
} }
ext := filepath.Ext(configFile) ext := filepath.Ext(configFile)
if len(ext) == 0 || ext[1:] != "yaml" { if len(ext) == 0 || (ext[1:] != "yaml" && ext[1:] != "yml") {
return fmt.Errorf("Unsupported Config Type: " + ext) return fmt.Errorf("Unsupported Config Type: " + ext)
} }
@ -140,26 +138,13 @@ func (fs *FileSource) loadFromFile() error {
return errors.Wrap(err, "Read config failed: "+configFile) return errors.Wrap(err, "Read config failed: "+configFile)
} }
// handle empty file var config map[string]interface{}
if len(data) == 0 { err = yaml.Unmarshal(data, &config)
continue if err != nil {
return errors.Wrap(err, "unmarshal yaml file "+configFile+" failed")
} }
var node yaml.Node flattenAndMergeMap("", config, newConfig)
decoder := yaml.NewDecoder(bytes.NewReader(data))
if err := decoder.Decode(&node); err != nil && !errors.Is(err, io.EOF) {
return errors.Wrap(err, "YAML unmarshal failed: "+configFile)
}
if node.Kind == yaml.DocumentNode && len(node.Content) > 0 {
// Get the content of the Document Node
contentNode := node.Content[0]
// Recursively process the content of the Document Node
flattenNode(contentNode, "", newConfig)
} else if node.Kind == yaml.MappingNode {
flattenNode(&node, "", newConfig)
}
} }
return fs.update(newConfig) return fs.update(newConfig)