1
0
Эх сурвалжийг харах

fix: problem on name overlaping in config (#2820)

Kevin Wan 2 жил өмнө
parent
commit
ab9eeff500

+ 10 - 6
core/conf/config.go

@@ -22,7 +22,6 @@ var loaders = map[string]func([]byte, any) error{
 
 type fieldInfo struct {
 	name     string
-	kind     reflect.Kind
 	children map[string]fieldInfo
 }
 
@@ -140,7 +139,6 @@ func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo {
 			} else {
 				info[lowerCaseName] = fieldInfo{
 					name: name,
-					kind: ft.Kind(),
 				}
 			}
 			continue
@@ -156,10 +154,16 @@ func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo {
 			fields = buildFieldsInfo(ft.Elem())
 		}
 
-		info[lowerCaseName] = fieldInfo{
-			name:     name,
-			kind:     ft.Kind(),
-			children: fields,
+		if prev, ok := info[lowerCaseName]; ok {
+			// merge fields
+			for k, v := range fields {
+				prev.children[k] = v
+			}
+		} else {
+			info[lowerCaseName] = fieldInfo{
+				name:     name,
+				children: fields,
+			}
 		}
 	}
 

+ 72 - 0
core/conf/config_test.go

@@ -384,6 +384,78 @@ func TestLoadFromYamlBytesLayers(t *testing.T) {
 	assert.Equal(t, "foo", val.Value)
 }
 
+func TestLoadFromYamlItemOverlay(t *testing.T) {
+	type (
+		Redis struct {
+			Host string
+			Port int
+		}
+
+		RedisKey struct {
+			Redis
+			Key string
+		}
+
+		Server struct {
+			Redis RedisKey
+		}
+
+		TestConfig struct {
+			Server
+			Redis Redis
+		}
+	)
+
+	input := []byte(`Redis:
+  Host: localhost
+  Port: 6379
+  Key: test
+`)
+
+	var c TestConfig
+	if assert.NoError(t, LoadFromYamlBytes(input, &c)) {
+		assert.Equal(t, "localhost", c.Redis.Host)
+		assert.Equal(t, 6379, c.Redis.Port)
+		assert.Equal(t, "test", c.Server.Redis.Key)
+	}
+}
+
+func TestLoadFromYamlItemOverlayWithMap(t *testing.T) {
+	type (
+		Redis struct {
+			Host string
+			Port int
+		}
+
+		RedisKey struct {
+			Redis
+			Key string
+		}
+
+		Server struct {
+			Redis RedisKey
+		}
+
+		TestConfig struct {
+			Server
+			Redis map[string]interface{}
+		}
+	)
+
+	input := []byte(`Redis:
+  Host: localhost
+  Port: 6379
+  Key: test
+`)
+
+	var c TestConfig
+	if assert.NoError(t, LoadFromYamlBytes(input, &c)) {
+		assert.Equal(t, "localhost", c.Server.Redis.Host)
+		assert.Equal(t, 6379, c.Server.Redis.Port)
+		assert.Equal(t, "test", c.Server.Redis.Key)
+	}
+}
+
 func TestUnmarshalJsonBytesMap(t *testing.T) {
 	input := []byte(`{"foo":{"/mtproto.RPCTos": "bff.bff","bar":"baz"}}`)
 

+ 7 - 6
core/conf/readme.md

@@ -4,6 +4,7 @@
 
 ```go
 type RestfulConf struct {
+  ServiceName  string        `json:",env=SERVICE_NAME"`  // read from env automatically
 	Host         string        `json:",default=0.0.0.0"`
 	Port         int
 	LogMode      string        `json:",options=[file,console]"`
@@ -21,20 +22,20 @@ type RestfulConf struct {
 
 ```yaml
 # most fields are optional or have default values
-Port: 8080
-LogMode: console
+port: 8080
+logMode: console
 # you can use env settings
-MaxBytes: ${MAX_BYTES}
+maxBytes: ${MAX_BYTES}
 ```
 
 - toml example
 
 ```toml
 # most fields are optional or have default values
-Port = 8_080
-LogMode = "console"
+port = 8_080
+logMode = "console"
 # you can use env settings
-MaxBytes = "${MAX_BYTES}"
+maxBytes = "${MAX_BYTES}"
 ```
 
 3. Load the config from a file: