From 5eda08e9b8556626e6f1b4e593f5c762db9af3aa Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Doumenjou Date: Tue, 26 Jun 2018 16:18:05 +0200 Subject: [PATCH] Better support on same prefix at the same level in the KV --- Gopkg.lock | 6 +- Gopkg.toml | 2 +- vendor/github.com/containous/staert/kv.go | 51 ++++-- vendor/github.com/containous/staert/staert.go | 164 +++--------------- vendor/github.com/containous/staert/toml.go | 121 +++++++++++++ 5 files changed, 191 insertions(+), 153 deletions(-) create mode 100644 vendor/github.com/containous/staert/toml.go diff --git a/Gopkg.lock b/Gopkg.lock index bd75db1db..3cfee2ff8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -257,8 +257,8 @@ [[projects]] name = "github.com/containous/staert" packages = ["."] - revision = "cc00c303ccbd2491ddc1dccc9eb7ccadd807557e" - version = "v3.1.0" + revision = "66717a0e0ca950c4b6dc8c87b46da0b8495c6e41" + version = "v3.1.1" [[projects]] name = "github.com/containous/traefik-extra-service-fabric" @@ -1679,6 +1679,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "ac06fad81167510635546d4e5500b938d61f2eb999bf04d5520d7967b9621f0d" + inputs-digest = "ad34e6336e6f19b82c52e991d22c5b43b9144ed7dc83d7b17197583ace43f346" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index bf27e331d..788430460 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -62,7 +62,7 @@ [[constraint]] name = "github.com/containous/staert" - version = "3.1.0" + version = "3.1.1" [[constraint]] name = "github.com/containous/traefik-extra-service-fabric" diff --git a/vendor/github.com/containous/staert/kv.go b/vendor/github.com/containous/staert/kv.go index bec34d173..60ad3c2d6 100644 --- a/vendor/github.com/containous/staert/kv.go +++ b/vendor/github.com/containous/staert/kv.go @@ -46,16 +46,16 @@ func (kv *KvSource) Parse(cmd *flaeg.Command) (*flaeg.Command, error) { // LoadConfig loads data from the KV Store into the config structure (given by reference) func (kv *KvSource) LoadConfig(config interface{}) error { - pairs := map[string][]byte{} - if err := kv.ListRecursive(kv.Prefix, pairs); err != nil { + pairs, err := kv.ListValuedPairWithPrefix(kv.Prefix) + if err != nil { return err } - // fmt.Printf("pairs : %#v\n", pairs) + mapStruct, err := generateMapstructure(convertPairs(pairs), kv.Prefix) if err != nil { return err } - // fmt.Printf("mapStruct : %#v\n", mapStruct) + configDecoder := &mapstructure.DecoderConfig{ Metadata: nil, Result: config, @@ -77,11 +77,11 @@ func generateMapstructure(pairs []*store.KVPair, prefix string) (map[string]inte for _, p := range pairs { // Trim the prefix off our key first key := strings.TrimPrefix(strings.Trim(p.Key, "/"), strings.Trim(prefix, "/")+"/") - raw, err := processKV(key, p.Value, raw) + var err error + raw, err = processKV(key, p.Value, raw) if err != nil { return raw, err } - } return raw, nil } @@ -313,15 +313,23 @@ func collateKvRecursive(objValue reflect.Value, kv map[string]string, key string func writeCompressedData(data []byte) (string, error) { var buffer bytes.Buffer gzipWriter := gzip.NewWriter(&buffer) + _, err := gzipWriter.Write(data) if err != nil { return "", err } - gzipWriter.Close() + + err = gzipWriter.Close() + if err != nil { + return "", err + } + return buffer.String(), nil } // ListRecursive lists all key value children under key +// Replaced by ListValuedPairWithPrefix +// Deprecated func (kv *KvSource) ListRecursive(key string, pairs map[string][]byte) error { pairsN1, err := kv.List(key, nil) if err == store.ErrKeyNotFound { @@ -342,14 +350,37 @@ func (kv *KvSource) ListRecursive(key string, pairs map[string][]byte) error { return nil } for _, p := range pairsN1 { - err := kv.ListRecursive(p.Key, pairs) - if err != nil { - return err + if p.Key != key { + err := kv.ListRecursive(p.Key, pairs) + if err != nil { + return err + } } } return nil } +// ListValuedPairWithPrefix lists all key value children under key +func (kv *KvSource) ListValuedPairWithPrefix(key string) (map[string][]byte, error) { + pairs := make(map[string][]byte) + + pairsN1, err := kv.List(key, nil) + if err == store.ErrKeyNotFound { + return pairs, nil + } + if err != nil { + return pairs, err + } + + for _, p := range pairsN1 { + if len(p.Value) > 0 { + pairs[p.Key] = p.Value + } + } + + return pairs, nil +} + func convertPairs(pairs map[string][]byte) []*store.KVPair { slicePairs := make([]*store.KVPair, len(pairs)) i := 0 diff --git a/vendor/github.com/containous/staert/staert.go b/vendor/github.com/containous/staert/staert.go index cf56d39ee..fa2fa6f14 100644 --- a/vendor/github.com/containous/staert/staert.go +++ b/vendor/github.com/containous/staert/staert.go @@ -2,12 +2,8 @@ package staert import ( "fmt" - "os" - "path/filepath" "reflect" - "strings" - "github.com/BurntSushi/toml" "github.com/containous/flaeg" ) @@ -24,10 +20,7 @@ type Staert struct { // NewStaert creates and return a pointer on Staert. Need defaultConfig and defaultPointersConfig given by references func NewStaert(rootCommand *flaeg.Command) *Staert { - s := Staert{ - command: rootCommand, - } - return &s + return &Staert{command: rootCommand} } // AddSource adds new Source to Staert, give it by reference @@ -35,40 +28,31 @@ func (s *Staert) AddSource(src Source) { s.sources = append(s.sources, src) } -// getConfig for a flaeg.Command run sources Parse func in the raw -func (s *Staert) parseConfigAllSources(cmd *flaeg.Command) error { - for _, src := range s.sources { - var err error - _, err = src.Parse(cmd) - if err != nil { - return err - } - } - return nil -} - // LoadConfig check which command is called and parses config // It returns the the parsed config or an error if it fails func (s *Staert) LoadConfig() (interface{}, error) { for _, src := range s.sources { - //Type assertion - f, ok := src.(*flaeg.Flaeg) - if ok { - if fCmd, err := f.GetCommand(); err != nil { + // Type assertion + if flg, ok := src.(*flaeg.Flaeg); ok { + fCmd, err := flg.GetCommand() + if err != nil { return nil, err - } else if s.command != fCmd { - //IF fleag sub-command + } + + // if fleag sub-command + if s.command != fCmd { + // if parseAllSources if fCmd.Metadata["parseAllSources"] == "true" { - //IF parseAllSources fCmdConfigType := reflect.TypeOf(fCmd.Config) sCmdConfigType := reflect.TypeOf(s.command.Config) if fCmdConfigType != sCmdConfigType { - return nil, fmt.Errorf("command %s : Config type doesn't match with root command config type. Expected %s got %s", fCmd.Name, sCmdConfigType.Name(), fCmdConfigType.Name()) + return nil, fmt.Errorf("command %s : Config type doesn't match with root command config type. Expected %s got %s", + fCmd.Name, sCmdConfigType.Name(), fCmdConfigType.Name()) } s.command = fCmd } else { - // ELSE (not parseAllSources) - s.command, err = f.Parse(fCmd) + // (not parseAllSources) + s.command, err = flg.Parse(fCmd) return s.command.Config, err } } @@ -78,117 +62,19 @@ func (s *Staert) LoadConfig() (interface{}, error) { return s.command.Config, err } +// parseConfigAllSources getConfig for a flaeg.Command run sources Parse func in the raw +func (s *Staert) parseConfigAllSources(cmd *flaeg.Command) error { + for _, src := range s.sources { + _, err := src.Parse(cmd) + if err != nil { + return err + } + } + return nil +} + // Run calls the Run func of the command // Warning, Run doesn't parse the config func (s *Staert) Run() error { return s.command.Run() } - -//TomlSource impement Source -type TomlSource struct { - filename string - dirNfullpath []string - fullpath string -} - -// NewTomlSource creates and return a pointer on TomlSource. -// Parameter filename is the file name (without extension type, ".toml" will be added) -// dirNfullpath may contain directories or fullpath to the file. -func NewTomlSource(filename string, dirNfullpath []string) *TomlSource { - return &TomlSource{filename, dirNfullpath, ""} -} - -// ConfigFileUsed return config file used -func (ts *TomlSource) ConfigFileUsed() string { - return ts.fullpath -} - -func preprocessDir(dirIn string) (string, error) { - dirOut := dirIn - expanded := os.ExpandEnv(dirIn) - dirOut, err := filepath.Abs(expanded) - return dirOut, err -} - -func findFile(filename string, dirNfile []string) string { - for _, df := range dirNfile { - if df != "" { - fullPath, _ := preprocessDir(df) - if fileInfo, err := os.Stat(fullPath); err == nil && !fileInfo.IsDir() { - return fullPath - } - - fullPath = filepath.Join(fullPath, filename+".toml") - if fileInfo, err := os.Stat(fullPath); err == nil && !fileInfo.IsDir() { - return fullPath - } - } - } - return "" -} - -// Parse calls toml.DecodeFile() func -func (ts *TomlSource) Parse(cmd *flaeg.Command) (*flaeg.Command, error) { - ts.fullpath = findFile(ts.filename, ts.dirNfullpath) - if len(ts.fullpath) < 2 { - return cmd, nil - } - metadata, err := toml.DecodeFile(ts.fullpath, cmd.Config) - if err != nil { - return nil, err - } - boolFlags, err := flaeg.GetBoolFlags(cmd.Config) - if err != nil { - return nil, err - } - flaegArgs, hasUnderField, err := generateArgs(metadata, boolFlags) - if err != nil { - return nil, err - } - - // fmt.Println(flaegArgs) - err = flaeg.Load(cmd.Config, cmd.DefaultPointersConfig, flaegArgs) - //if err!= missing parser err - if err != nil && err != flaeg.ErrParserNotFound { - return nil, err - } - if hasUnderField { - _, err := toml.DecodeFile(ts.fullpath, cmd.Config) - if err != nil { - return nil, err - } - } - - return cmd, nil -} - -func generateArgs(metadata toml.MetaData, flags []string) ([]string, bool, error) { - var flaegArgs []string - keys := metadata.Keys() - hasUnderField := false - for i, key := range keys { - // fmt.Println(key) - if metadata.Type(key.String()) == "Hash" { - // TOML hashes correspond to Go structs or maps. - // fmt.Printf("%s could be a ptr on a struct, or a map\n", key) - for j := i; j < len(keys); j++ { - // fmt.Printf("%s =? %s\n", keys[j].String(), "."+key.String()) - if strings.Contains(keys[j].String(), key.String()+".") { - hasUnderField = true - break - } - } - match := false - for _, flag := range flags { - if flag == strings.ToLower(key.String()) { - match = true - break - } - } - if match { - flaegArgs = append(flaegArgs, "--"+strings.ToLower(key.String())) - } - } - } - return flaegArgs, hasUnderField, nil -} diff --git a/vendor/github.com/containous/staert/toml.go b/vendor/github.com/containous/staert/toml.go new file mode 100644 index 000000000..9f6fb7a23 --- /dev/null +++ b/vendor/github.com/containous/staert/toml.go @@ -0,0 +1,121 @@ +package staert + +import ( + "os" + "path/filepath" + "strings" + + "github.com/BurntSushi/toml" + "github.com/containous/flaeg" +) + +var _ Source = (*TomlSource)(nil) + +// TomlSource implement staert.Source +type TomlSource struct { + filename string + dirNFullPath []string + fullPath string +} + +// NewTomlSource creates and return a pointer on Source. +// Parameter filename is the file name (without extension type, ".toml" will be added) +// dirNFullPath may contain directories or fullPath to the file. +func NewTomlSource(filename string, dirNFullPath []string) *TomlSource { + return &TomlSource{filename, dirNFullPath, ""} +} + +// ConfigFileUsed return config file used +func (ts *TomlSource) ConfigFileUsed() string { + return ts.fullPath +} + +// Parse calls toml.DecodeFile() func +func (ts *TomlSource) Parse(cmd *flaeg.Command) (*flaeg.Command, error) { + ts.fullPath = findFile(ts.filename, ts.dirNFullPath) + if len(ts.fullPath) < 2 { + return cmd, nil + } + + metadata, err := toml.DecodeFile(ts.fullPath, cmd.Config) + if err != nil { + return nil, err + } + + boolFlags, err := flaeg.GetBoolFlags(cmd.Config) + if err != nil { + return nil, err + } + + flgArgs, hasUnderField, err := generateArgs(metadata, boolFlags) + if err != nil { + return nil, err + } + + err = flaeg.Load(cmd.Config, cmd.DefaultPointersConfig, flgArgs) + if err != nil && err != flaeg.ErrParserNotFound { + return nil, err + } + + if hasUnderField { + _, err := toml.DecodeFile(ts.fullPath, cmd.Config) + if err != nil { + return nil, err + } + } + + return cmd, nil +} + +func preProcessDir(dirIn string) (string, error) { + expanded := os.ExpandEnv(dirIn) + return filepath.Abs(expanded) +} + +func findFile(filename string, dirNFile []string) string { + for _, df := range dirNFile { + if df != "" { + fullPath, _ := preProcessDir(df) + if fileInfo, err := os.Stat(fullPath); err == nil && !fileInfo.IsDir() { + return fullPath + } + + fullPath = filepath.Join(fullPath, filename+".toml") + if fileInfo, err := os.Stat(fullPath); err == nil && !fileInfo.IsDir() { + return fullPath + } + } + } + return "" +} + +func generateArgs(metadata toml.MetaData, flags []string) ([]string, bool, error) { + var flgArgs []string + keys := metadata.Keys() + hasUnderField := false + + for i, key := range keys { + if metadata.Type(key.String()) == "Hash" { + // TOML hashes correspond to Go structs or maps. + for j := i; j < len(keys); j++ { + if strings.Contains(keys[j].String(), key.String()+".") { + hasUnderField = true + break + } + } + + match := false + for _, flag := range flags { + if flag == strings.ToLower(key.String()) { + match = true + break + } + } + if match { + flgArgs = append(flgArgs, "--"+strings.ToLower(key.String())) + } + } + } + + return flgArgs, hasUnderField, nil +}