forked from fioepq9/helper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
viper.go
97 lines (89 loc) · 2.14 KB
/
viper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package helper
import (
"os"
"strings"
"sync"
"time"
"github.com/cockroachdb/errors"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
yaml "gopkg.in/yaml.v3"
)
var (
viperHelper *ViperHelper
viperHelperOnce sync.Once
)
type ViperHelper struct {
V *viper.Viper
ConfigFile string
TagName string
EnableEnv bool
IgnoreEnvFunc func(key string, val string) bool
DecodeHooks []mapstructure.DecodeHookFunc
}
func Viper(options ...func(*ViperHelper)) *ViperHelper {
viperHelperOnce.Do(func() {
viperHelper = &ViperHelper{
V: viper.New(),
ConfigFile: "etc/config.yaml",
TagName: "yaml",
EnableEnv: true,
IgnoreEnvFunc: func(key string, val string) bool {
if strings.HasPrefix(key, "_") {
return true
}
if strings.Contains(key, "__") {
return true
}
return false
},
DecodeHooks: []mapstructure.DecodeHookFunc{
mapstructure.StringToTimeDurationHookFunc(),
StringToSliceHookFunc(","),
mapstructure.OrComposeDecodeHookFunc(
mapstructure.StringToTimeHookFunc(time.RFC3339),
mapstructure.StringToTimeHookFunc(time.RFC3339Nano),
),
UnmarshalToStructHookFunc(yaml.Unmarshal),
UnmarshalToMapHookFunc(yaml.Unmarshal),
UnmarshalToSliceHookFunc(yaml.Unmarshal),
},
}
})
for _, opt := range options {
opt(viperHelper)
}
return viperHelper
}
func (h *ViperHelper) Unmarshal(conf any) error {
if h.ConfigFile != "" {
h.V.SetConfigFile(h.ConfigFile)
err := h.V.ReadInConfig()
if err != nil {
return errors.Wrap(err, "read config failed")
}
}
if h.EnableEnv {
for _, env := range os.Environ() {
key, val, ok := strings.Cut(env, "=")
if !ok {
return errors.New("cut env failed")
}
if h.IgnoreEnvFunc(key, val) {
continue
}
err := h.V.BindEnv(strings.ReplaceAll(key, "_", "."), key)
if err != nil {
return errors.Wrap(err, "bind env failed")
}
}
}
err := h.V.Unmarshal(
conf,
func(cfg *mapstructure.DecoderConfig) {
cfg.TagName = h.TagName
cfg.DecodeHook = mapstructure.ComposeDecodeHookFunc(h.DecodeHooks...)
},
)
return errors.Wrap(err, "unmarshal config failed")
}