github.com/micro/go-micro/v2@v2.9.1/config/source/flag/flag.go (about) 1 package flag 2 3 import ( 4 "errors" 5 "flag" 6 "github.com/imdario/mergo" 7 "github.com/micro/go-micro/v2/config/source" 8 "strings" 9 "time" 10 ) 11 12 type flagsrc struct { 13 opts source.Options 14 } 15 16 func (fs *flagsrc) Read() (*source.ChangeSet, error) { 17 if !flag.Parsed() { 18 return nil, errors.New("flags not parsed") 19 } 20 21 var changes map[string]interface{} 22 23 visitFn := func(f *flag.Flag) { 24 n := strings.ToLower(f.Name) 25 keys := strings.FieldsFunc(n, split) 26 reverse(keys) 27 28 tmp := make(map[string]interface{}) 29 for i, k := range keys { 30 if i == 0 { 31 tmp[k] = f.Value 32 continue 33 } 34 35 tmp = map[string]interface{}{k: tmp} 36 } 37 38 mergo.Map(&changes, tmp) // need to sort error handling 39 return 40 } 41 42 unset, ok := fs.opts.Context.Value(includeUnsetKey{}).(bool) 43 if ok && unset { 44 flag.VisitAll(visitFn) 45 } else { 46 flag.Visit(visitFn) 47 } 48 49 b, err := fs.opts.Encoder.Encode(changes) 50 if err != nil { 51 return nil, err 52 } 53 54 cs := &source.ChangeSet{ 55 Format: fs.opts.Encoder.String(), 56 Data: b, 57 Timestamp: time.Now(), 58 Source: fs.String(), 59 } 60 cs.Checksum = cs.Sum() 61 62 return cs, nil 63 } 64 65 func split(r rune) bool { 66 return r == '-' || r == '_' 67 } 68 69 func reverse(ss []string) { 70 for i := len(ss)/2 - 1; i >= 0; i-- { 71 opp := len(ss) - 1 - i 72 ss[i], ss[opp] = ss[opp], ss[i] 73 } 74 } 75 76 func (fs *flagsrc) Watch() (source.Watcher, error) { 77 return source.NewNoopWatcher() 78 } 79 80 func (fs *flagsrc) Write(cs *source.ChangeSet) error { 81 return nil 82 } 83 84 func (fs *flagsrc) String() string { 85 return "flag" 86 } 87 88 // NewSource returns a config source for integrating parsed flags. 89 // Hyphens are delimiters for nesting, and all keys are lowercased. 90 // 91 // Example: 92 // dbhost := flag.String("database-host", "localhost", "the db host name") 93 // 94 // { 95 // "database": { 96 // "host": "localhost" 97 // } 98 // } 99 func NewSource(opts ...source.Option) source.Source { 100 return &flagsrc{opts: source.NewOptions(opts...)} 101 }