summaryrefslogtreecommitdiff
path: root/cmd/util/config.go
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2019-01-05 15:51:15 +0300
committerWolfy-J <[email protected]>2019-01-05 15:51:15 +0300
commit6f1a668f5d67bc81d1ac26be84620dc5c87e1581 (patch)
tree2208fb4c411f200e666694e35ef6eb48b3c5abc8 /cmd/util/config.go
parent94f4083b1d85d0a45b48cbf80d83e3049c30096e (diff)
override config flags
Diffstat (limited to 'cmd/util/config.go')
-rw-r--r--cmd/util/config.go114
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
+}