-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmanager.go
156 lines (143 loc) · 3.72 KB
/
manager.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package props
import (
"fmt"
"gopkg.in/yaml.v3"
"strings"
)
type Properties struct {
set setMap
obj mapping
ref interface{}
}
func New(reference interface{}) Properties {
m := mapFieldData(reference)
p := Properties{
set: make(setMap),
obj: m,
ref: reference,
}
return p
}
// InitDefaults
// Initialize values in the default section of configuration
func (p Properties) InitDefaults() error {
for key, mapElem := range p.obj {
// If already set by another pass, then mark as skip
if _, alreadySet := p.set[mapElem.name]; alreadySet {
mapElem.skip = true
continue
}
// Apply default value
err := valApply(p.obj, key, mapElem.def)
if err != nil {
return fmt.Errorf("init defaults fail, error: %w", err)
}
}
return nil
}
// FromEnv
// Read environmental variables and match them to provided configuration
func (p Properties) FromEnv() error {
for key, mapElem := range p.obj {
val, kind := getEnvOrDefault(mapElem.key, mapElem.def)
// Check if env was not present, and it's a default value we try to reset
if _, alreadySet := p.set[mapElem.name]; alreadySet && kind == prop_default {
mapElem.skip = true
continue
}
// Apply default value
err := valApply(p.obj, key, val)
if err != nil {
return fmt.Errorf("from env fail, error: %w", err)
}
}
return nil
}
// FromYamlFile
// Read Yaml File configuration top level properties
func (p Properties) FromYamlFile(fileName string) error {
// Pull yaml file information
if len(fileName) == 0 {
return fmt.Errorf("no file name was provided")
}
yamlMap := make(map[string]interface{})
file, err := getOpenFile(fileName)
if err != nil {
return fmt.Errorf("from yaml fail, error %w", err)
}
err = yaml.Unmarshal(file, yamlMap)
if err != nil {
return fmt.Errorf("cannot unmarshal yaml file, error %w", err)
}
// Reassure those will be searchable
for k, v := range yamlMap {
yamlMap[strings.ToLower(k)] = v
}
// Apply values to the mapping
for key, mapElem := range p.obj {
// Check if value from the properties presented in yaml
if val, found := yamlMap[strings.ToLower(mapElem.key)]; found {
// Apply default value
err := interfaceValApply(p.obj, key, val)
if err != nil {
return fmt.Errorf("from yaml fail, error: %w", err)
}
}
}
return nil
}
// FromArgs
// Will take presented os.Args and try to match and fill them to properties reference
func (p Properties) FromArgs() error {
var err error
args := getOsArgs()
argMap := make(map[string]string)
for _, arg := range args {
kval := strings.Split(arg, "=")
if len(kval) == 2 {
argMap[strings.ToLower(kval[0])] = kval[1]
} else if len(kval) == 1 {
argMap[strings.ToLower(kval[0])] = ""
}
}
for key, mapElem := range p.obj {
if val, exists := argMap[strings.ToLower(mapElem.key)]; exists {
err = valApply(p.obj, key, val)
if err != nil {
return fmt.Errorf("from args fail, error: %w", err)
}
}
}
return err
}
// FromCallback
// Should try to form properties from some callback,
// underlying function can retrieve data from any API
// @param fn func()(map[string]string, error, bool)
func (p Properties) FromCallback(fn func() (map[string]string, error)) error {
if fn == nil {
return fmt.Errorf("no func provided")
}
// Get map of parameters
props, err := fn()
if err != nil {
return fmt.Errorf("from callback fail, error %w", err)
}
// Reassure those will be searchable
for k, v := range props {
props[strings.ToLower(k)] = v
}
// Match
for key, mapElem := range p.obj {
if val, exists := props[strings.ToLower(mapElem.key)]; exists {
err = valApply(p.obj, key, val)
if err != nil {
return fmt.Errorf("from args fail, error: %w", err)
}
}
}
return nil
}
func (p Properties) Commit() {
refApply(p.ref, p.obj, p.set)
}