diff options
author | Wolfy-J <[email protected]> | 2019-01-05 15:51:15 +0300 |
---|---|---|
committer | Wolfy-J <[email protected]> | 2019-01-05 15:51:15 +0300 |
commit | 6f1a668f5d67bc81d1ac26be84620dc5c87e1581 (patch) | |
tree | 2208fb4c411f200e666694e35ef6eb48b3c5abc8 /cmd/util | |
parent | 94f4083b1d85d0a45b48cbf80d83e3049c30096e (diff) |
override config flags
Diffstat (limited to 'cmd/util')
-rw-r--r-- | cmd/util/config.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/cmd/util/config.go b/cmd/util/config.go new file mode 100644 index 00000000..a829f44c --- /dev/null +++ b/cmd/util/config.go @@ -0,0 +1,114 @@ +package util + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/spiral/roadrunner/service" + "os" + "path/filepath" + "strings" +) + +// configWrapper provides interface bridge between v configs and service.Config. +type configWrapper struct { + v *viper.Viper +} + +// Get nested config section (sub-map), returns nil if section not found. +func (w *configWrapper) Get(key string) service.Config { + sub := w.v.Sub(key) + if sub == nil { + return nil + } + + return &configWrapper{sub} +} + +// Unmarshal unmarshal config data into given struct. +func (w *configWrapper) Unmarshal(out interface{}) error { + return w.v.Unmarshal(out) +} + +// LoadConfig config and merge it's values with set of flags. +func LoadConfig(cfgFile string, path []string, name string, flags []string) (*configWrapper, error) { + cfg := viper.New() + + if cfgFile != "" { + if absPath, err := filepath.Abs(cfgFile); err == nil { + cfgFile = absPath + + // force working absPath related to config file + if err := os.Chdir(filepath.Dir(absPath)); err != nil { + return nil, err + } + } + + // Use cfg file from the flag. + cfg.SetConfigFile(cfgFile) + + if dir, err := filepath.Abs(cfgFile); err == nil { + // force working absPath related to config file + if err := os.Chdir(filepath.Dir(dir)); err != nil { + return nil, err + } + } + } else { + // automatic location + for _, p := range path { + cfg.AddConfigPath(p) + } + + cfg.SetConfigName(name) + } + + // read in environment variables that match + cfg.AutomaticEnv() + + // If a cfg file is found, read it in. + if err := cfg.ReadInConfig(); err != nil { + return nil, err + } + + if len(flags) != 0 { + for _, f := range flags { + k, v, err := parseFlag(f) + if err != nil { + return nil, err + } + + cfg.Set(k, v) + } + + merged := viper.New() + + // we have to copy all the merged values into new config in order normalize it (viper bug?) + if err := merged.MergeConfigMap(cfg.AllSettings()); err != nil { + return nil, err + } + + return &configWrapper{merged}, nil + } + + return &configWrapper{cfg}, nil +} + +func parseFlag(flag string) (string, string, error) { + if !strings.Contains(flag, "=") { + return "", "", fmt.Errorf("invalid flag `%s`", flag) + } + + parts := strings.SplitN(strings.TrimLeft(flag, " \"'`"), "=", 2) + + return strings.Trim(parts[0], " \n\t"), parseValue(strings.Trim(parts[1], " \n\t")), nil +} + +func parseValue(value string) string { + escape := []rune(value)[0] + + if escape == '"' || escape == '\'' || escape == '`' { + value = strings.Trim(value, string(escape)) + value = strings.Replace(value, fmt.Sprintf("\\%s", string(escape)), string(escape), -1) + } + + return value +} |