-
Notifications
You must be signed in to change notification settings - Fork 7
/
config.go
113 lines (97 loc) · 2.76 KB
/
config.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
package goconf
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"reflect"
"strings"
)
var (
errPassInPtr = fmt.Errorf("unsupported type, pass in as ptr")
globalLogger = func(s string) { log.Print(s) }
)
//SetGlobalLogger set the global logger func, if nil, lib will keep silent
func SetGlobalLogger(lf func(string)) {
globalLogger = lf
}
// Config represents a configuration loader
type Config struct {
flagSet *flag.FlagSet
fileLoader *fileLoader
}
// New Config with name and option struct
func New(name string) *Config {
c := &Config{}
c.flagSet = flag.CommandLine //flag.NewFlagSet(name, flag.ContinueOnError)
// c.flagSet.SetOutput(ioutil.Discard)
c.fileLoader = &fileLoader{log: c.log}
return c
}
func (c *Config) log(msg string) {
msg = fmt.Sprintf("goconf : %s", msg)
if globalLogger != nil {
globalLogger(msg)
}
}
// GenTemplate Gen template conf file base on the given struct and save the conf to file.
func (c *Config) GenTemplate(opts interface{}, fn string) error {
tm := make(map[string]interface{})
innerResolve(opts, nil, nil, tm, false, c.log)
return genTemplate(tm, fn)
}
// Resolve given files, return error if fail
func (c *Config) Resolve(opts interface{}, files []string) error {
return c.resolve(opts, files)
}
// MustResolve given files, panic if fail
func (c *Config) MustResolve(opts interface{}, files []string) {
if err := c.resolve(opts, files); err != nil {
c.log(fmt.Sprintf("Failed in must model err: %s", err.Error()))
panic(err)
}
}
// read configuration automatically based on the given struct's field name,
// load configs from struct field's default value, muitiple files and cmdline flags.
func (c *Config) resolve(opts interface{}, files []string) error {
if reflect.ValueOf(opts).Kind() != reflect.Ptr {
return errPassInPtr
}
// auto flag with default value
innerResolve(opts, c.flagSet, nil, nil, true, c.log)
if err := c.flagSet.Parse(os.Args[1:]); err != nil {
if err != flag.ErrHelp {
_, _ = fmt.Fprintf(os.Stderr, "flag: %v\n", err)
c.flagSet.Usage()
}
}
flagInst := c.flagSet.Lookup("_auto_conf_files_")
if flagInst != nil {
tmp := strings.Trim(flagInst.Value.String(), " ")
if tmp != "" {
filesFlag := strings.Split(tmp, ",")
if len(filesFlag) != 0 {
files = filesFlag
}
}
}
c.log(fmt.Sprintf("file: %v", files))
errs := errArray{ErrorFormat: errArrayDotFormatFunc}
if len(files) > 0 {
if err := c.fileLoader.Load(files); err != nil {
c.log(fmt.Sprintf("Error with %s", err.Error()))
errs.Push(err)
}
}
innerResolve(opts, c.flagSet, c.fileLoader.Data(), nil, false, c.log)
if b, err := json.MarshalIndent(opts, "", " "); err != nil {
errs.Push(err)
} else {
c.log(fmt.Sprintf("Contents:\n%v", string(b)))
}
if errs.Err() != nil {
return errs
}
return nil
}