Skip to content

Commit dc5cbdb

Browse files
committed
first
1 parent dc97543 commit dc5cbdb

File tree

6 files changed

+251
-12
lines changed

6 files changed

+251
-12
lines changed

.gitignore

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,2 @@
1-
# Binaries for programs and plugins
2-
*.exe
3-
*.exe~
4-
*.dll
5-
*.so
6-
*.dylib
7-
8-
# Test binary, build with `go test -c`
9-
*.test
10-
11-
# Output of the go coverage tool, specifically when used with LiteIDE
12-
*.out
1+
.*
2+
go.sum

Config.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package config
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"github.com/ssgo/log"
7+
"os"
8+
"os/user"
9+
"reflect"
10+
"strings"
11+
)
12+
13+
var envConfigs = map[string]string{}
14+
var envUpperConfigs = map[string]string{}
15+
var inited = false
16+
17+
func initConfig() {
18+
envConf := map[string]interface{}{}
19+
LoadConfig("env", &envConf)
20+
initEnvConfigFromFile("", reflect.ValueOf(envConf))
21+
for _, e := range os.Environ() {
22+
a := strings.SplitN(e, "=", 2)
23+
if len(a) == 2 {
24+
envConfigs[a[0]] = a[1]
25+
}
26+
}
27+
for k1, v1 := range envConfigs {
28+
envUpperConfigs[strings.ToUpper(k1)] = v1
29+
}
30+
}
31+
32+
func ResetConfigEnv() {
33+
envConfigs = map[string]string{}
34+
envUpperConfigs = map[string]string{}
35+
initConfig()
36+
}
37+
38+
func LoadConfig(name string, conf interface{}) error {
39+
if !inited {
40+
inited = true
41+
initConfig()
42+
}
43+
44+
var file *os.File
45+
var err error
46+
lenOsArgs := len(os.Args)
47+
if lenOsArgs >= 1 {
48+
execPath := os.Args[0][0:strings.LastIndex(os.Args[0], string(os.PathSeparator))]
49+
file, err = os.Open(execPath + "/" + name + ".json")
50+
}
51+
if err != nil || lenOsArgs < 1 {
52+
file, err = os.Open(name + ".json")
53+
if err != nil {
54+
file, err = os.Open("../" + name + ".json")
55+
if err != nil {
56+
u, _ := user.Current()
57+
if u != nil {
58+
file, err = os.Open(u.HomeDir + "/" + name + ".json")
59+
}
60+
}
61+
}
62+
}
63+
defer file.Close()
64+
65+
decoder := json.NewDecoder(file)
66+
err = decoder.Decode(conf)
67+
makeEnvConfig(name, reflect.ValueOf(conf))
68+
return err
69+
}
70+
71+
func makeEnvConfig(prefix string, v reflect.Value) {
72+
for v.Kind() == reflect.Ptr {
73+
v = v.Elem()
74+
}
75+
t := v.Type()
76+
ev := envConfigs[prefix]
77+
if ev == "" {
78+
ev = envUpperConfigs[strings.ToUpper(prefix)]
79+
}
80+
if ev != "" {
81+
if v.CanSet() {
82+
newValue := reflect.New(t)
83+
err := json.Unmarshal([]byte(ev), newValue.Interface())
84+
if err != nil && t.Kind() == reflect.String {
85+
v.SetString(ev)
86+
} else if err == nil {
87+
v.Set(newValue.Elem())
88+
} else {
89+
log.Error("LoadConfig", map[string]interface{}{
90+
"prefix": prefix,
91+
"event": ev,
92+
"error": err.Error(),
93+
})
94+
}
95+
} else {
96+
log.Error("LoadConfig", map[string]interface{}{
97+
"prefix": prefix,
98+
"event": ev,
99+
"error": "Can't set config because CanSet() == false",
100+
"varType": t.String(),
101+
"value": v.String(),
102+
})
103+
}
104+
}
105+
106+
if t.Kind() == reflect.Struct {
107+
for i := 0; i < v.NumField(); i++ {
108+
makeEnvConfig(prefix+"_"+v.Type().Field(i).Name, v.Field(i))
109+
}
110+
} else if t.Kind() == reflect.Map {
111+
// 查找 环境变量 或 env.json 中是否有配置项
112+
if t.Elem().Kind() != reflect.Interface {
113+
findPrefix := prefix + "_"
114+
for k1, _ := range envConfigs {
115+
if strings.HasPrefix(k1, findPrefix) || strings.HasPrefix(strings.ToUpper(k1), strings.ToUpper(findPrefix)) {
116+
findPostfix := k1[len(findPrefix):]
117+
a1 := strings.Split(findPostfix, "_")
118+
k2 := strings.ToLower(a1[0])
119+
if k2 != "" && v.MapIndex(reflect.ValueOf(k2)).Kind() == reflect.Invalid {
120+
var v1 reflect.Value
121+
if t.Elem().Kind() == reflect.Ptr {
122+
v1 = reflect.New(t.Elem().Elem())
123+
} else {
124+
v1 = reflect.New(t.Elem()).Elem()
125+
}
126+
if len(v.MapKeys()) == 0 {
127+
v.Set(reflect.MakeMap(t))
128+
}
129+
v.SetMapIndex(reflect.ValueOf(strings.ToLower(a1[0])), v1)
130+
}
131+
}
132+
}
133+
}
134+
for _, mk := range v.MapKeys() {
135+
//log.Println(" --- ", prefix, mk)
136+
makeEnvConfig(prefix+"_"+mk.String(), v.MapIndex(mk))
137+
}
138+
} else if t.Kind() == reflect.Slice {
139+
for i := 0; i < v.Len(); i++ {
140+
makeEnvConfig(fmt.Sprint(prefix, "_", i), v.Index(i))
141+
}
142+
}
143+
}
144+
145+
func initEnvConfigFromFile(prefix string, v reflect.Value) {
146+
for v.Kind() == reflect.Ptr {
147+
v = v.Elem()
148+
}
149+
t := v.Type()
150+
if t.Kind() == reflect.Interface {
151+
t = reflect.TypeOf(v.Interface())
152+
v = reflect.ValueOf(v.Interface())
153+
}
154+
if t.Kind() == reflect.Map {
155+
if prefix != "" {
156+
prefix += "_"
157+
}
158+
for _, mk := range v.MapKeys() {
159+
initEnvConfigFromFile(prefix+mk.String(), v.MapIndex(mk))
160+
}
161+
} else if t.Kind() == reflect.String {
162+
envConfigs[prefix] = v.String()
163+
} else {
164+
b, err := json.Marshal(v.Interface())
165+
if err == nil {
166+
envConfigs[prefix] = string(b)
167+
} else {
168+
envConfigs[prefix] = fmt.Sprint(v.Interface())
169+
}
170+
}
171+
}

Config_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package config
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestForMap(t *testing.T) {
8+
testConf := map[string]interface{}{}
9+
err := LoadConfig("test", &testConf)
10+
if err != nil {
11+
t.Error("read test.json failed", err)
12+
}
13+
if testConf["name"] != "test-config" {
14+
t.Error("name in test.json failed", testConf["name"])
15+
}
16+
}
17+
18+
type testConfType struct {
19+
Name string
20+
Sets []int
21+
List map[string]*struct {
22+
Name string
23+
}
24+
List2 map[string]string
25+
}
26+
27+
func TestForStruct(t *testing.T) {
28+
testConf := testConfType{}
29+
err := LoadConfig("test", &testConf)
30+
if err != nil {
31+
t.Error("read test.json failed", err)
32+
}
33+
if testConf.Name != "test-config" {
34+
t.Error("name in test.json failed", testConf.Name)
35+
}
36+
if len(testConf.Sets) != 3 || testConf.Sets[1] != 2 {
37+
t.Error("sets in test.json failed", testConf.Sets)
38+
}
39+
if testConf.List != nil && testConf.List["aaa"].Name != "222" {
40+
t.Error("map in test.json failed", testConf.List["aaa"])
41+
}
42+
if testConf.List != nil && (testConf.List["bbb"] == nil || testConf.List["bbb"].Name != "xxx") {
43+
t.Error("map in env.json failed", testConf.List)
44+
}
45+
}

env.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"test": {
3+
"list": {
4+
"aaa": {
5+
"name": "222"
6+
},
7+
"bbb": {
8+
"name": "xxx"
9+
}
10+
},
11+
"list2": {
12+
"aaa": "111"
13+
}
14+
},
15+
"TEST_SETS": [
16+
1,
17+
2,
18+
3
19+
]
20+
}

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/ssgo/config
2+
3+
go 1.12
4+
5+
require github.com/ssgo/log v0.0.2

test.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "test-config",
3+
"list": {
4+
"aaa" :{
5+
"name": "111"
6+
}
7+
}
8+
}

0 commit comments

Comments
 (0)