2015-12-09 17:15:46 +00:00
|
|
|
package altsrc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
2016-04-29 16:33:59 +00:00
|
|
|
"strings"
|
2015-12-09 17:15:46 +00:00
|
|
|
"time"
|
|
|
|
|
2019-08-03 10:55:06 +00:00
|
|
|
"github.com/urfave/cli"
|
2015-12-09 17:15:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// MapInputSource implements InputSourceContext to return
|
|
|
|
// data from the map that is loaded.
|
|
|
|
type MapInputSource struct {
|
2016-04-29 16:33:59 +00:00
|
|
|
valueMap map[interface{}]interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nestedVal checks if the name has '.' delimiters.
|
|
|
|
// If so, it tries to traverse the tree by the '.' delimited sections to find
|
|
|
|
// a nested value for the key.
|
|
|
|
func nestedVal(name string, tree map[interface{}]interface{}) (interface{}, bool) {
|
|
|
|
if sections := strings.Split(name, "."); len(sections) > 1 {
|
|
|
|
node := tree
|
|
|
|
for _, section := range sections[:len(sections)-1] {
|
2017-10-06 05:29:13 +00:00
|
|
|
child, ok := node[section]
|
|
|
|
if !ok {
|
2016-04-29 16:33:59 +00:00
|
|
|
return nil, false
|
|
|
|
}
|
2017-10-06 05:29:13 +00:00
|
|
|
ctype, ok := child.(map[interface{}]interface{})
|
|
|
|
if !ok {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
node = ctype
|
2016-04-29 16:33:59 +00:00
|
|
|
}
|
|
|
|
if val, ok := node[sections[len(sections)-1]]; ok {
|
|
|
|
return val, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, false
|
2015-12-09 17:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Int returns an int from the map if it exists otherwise returns 0
|
|
|
|
func (fsm *MapInputSource) Int(name string) (int, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(int)
|
|
|
|
if !isType {
|
|
|
|
return 0, incorrectTypeForFlagError(name, "int", otherGenericValue)
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
return otherValue, nil
|
|
|
|
}
|
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(int)
|
|
|
|
if !isType {
|
|
|
|
return 0, incorrectTypeForFlagError(name, "int", nestedGenericValue)
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
return otherValue, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Duration returns a duration from the map if it exists otherwise returns 0
|
|
|
|
func (fsm *MapInputSource) Duration(name string) (time.Duration, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(time.Duration)
|
|
|
|
if !isType {
|
|
|
|
return 0, incorrectTypeForFlagError(name, "duration", otherGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(time.Duration)
|
|
|
|
if !isType {
|
|
|
|
return 0, incorrectTypeForFlagError(name, "duration", nestedGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Float64 returns an float64 from the map if it exists otherwise returns 0
|
|
|
|
func (fsm *MapInputSource) Float64(name string) (float64, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(float64)
|
|
|
|
if !isType {
|
|
|
|
return 0, incorrectTypeForFlagError(name, "float64", otherGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(float64)
|
|
|
|
if !isType {
|
|
|
|
return 0, incorrectTypeForFlagError(name, "float64", nestedGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a string from the map if it exists otherwise returns an empty string
|
|
|
|
func (fsm *MapInputSource) String(name string) (string, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(string)
|
|
|
|
if !isType {
|
|
|
|
return "", incorrectTypeForFlagError(name, "string", otherGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(string)
|
|
|
|
if !isType {
|
|
|
|
return "", incorrectTypeForFlagError(name, "string", nestedGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// StringSlice returns an []string from the map if it exists otherwise returns nil
|
|
|
|
func (fsm *MapInputSource) StringSlice(name string) ([]string, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
2017-01-08 23:11:26 +00:00
|
|
|
if !exists {
|
|
|
|
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
|
|
|
|
if !exists {
|
|
|
|
return nil, nil
|
2015-12-09 17:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-08 23:11:26 +00:00
|
|
|
|
|
|
|
otherValue, isType := otherGenericValue.([]interface{})
|
|
|
|
if !isType {
|
|
|
|
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
var stringSlice = make([]string, 0, len(otherValue))
|
|
|
|
for i, v := range otherValue {
|
|
|
|
stringValue, isType := v.(string)
|
|
|
|
|
2016-04-29 16:33:59 +00:00
|
|
|
if !isType {
|
2017-01-08 23:11:26 +00:00
|
|
|
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "string", v)
|
2016-04-29 16:33:59 +00:00
|
|
|
}
|
2017-01-08 23:11:26 +00:00
|
|
|
|
|
|
|
stringSlice = append(stringSlice, stringValue)
|
2016-04-29 16:33:59 +00:00
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
2017-01-08 23:11:26 +00:00
|
|
|
return stringSlice, nil
|
2015-12-09 17:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IntSlice returns an []int from the map if it exists otherwise returns nil
|
|
|
|
func (fsm *MapInputSource) IntSlice(name string) ([]int, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
2017-01-08 23:11:26 +00:00
|
|
|
if !exists {
|
|
|
|
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
|
|
|
|
if !exists {
|
|
|
|
return nil, nil
|
2015-12-09 17:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-08 23:11:26 +00:00
|
|
|
|
|
|
|
otherValue, isType := otherGenericValue.([]interface{})
|
|
|
|
if !isType {
|
|
|
|
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
var intSlice = make([]int, 0, len(otherValue))
|
|
|
|
for i, v := range otherValue {
|
|
|
|
intValue, isType := v.(int)
|
|
|
|
|
2016-04-29 16:33:59 +00:00
|
|
|
if !isType {
|
2017-01-08 23:11:26 +00:00
|
|
|
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "int", v)
|
2016-04-29 16:33:59 +00:00
|
|
|
}
|
2017-01-08 23:11:26 +00:00
|
|
|
|
|
|
|
intSlice = append(intSlice, intValue)
|
2016-04-29 16:33:59 +00:00
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
2017-01-08 23:11:26 +00:00
|
|
|
return intSlice, nil
|
2015-12-09 17:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generic returns an cli.Generic from the map if it exists otherwise returns nil
|
|
|
|
func (fsm *MapInputSource) Generic(name string) (cli.Generic, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(cli.Generic)
|
|
|
|
if !isType {
|
|
|
|
return nil, incorrectTypeForFlagError(name, "cli.Generic", otherGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(cli.Generic)
|
|
|
|
if !isType {
|
|
|
|
return nil, incorrectTypeForFlagError(name, "cli.Generic", nestedGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bool returns an bool from the map otherwise returns false
|
|
|
|
func (fsm *MapInputSource) Bool(name string) (bool, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(bool)
|
|
|
|
if !isType {
|
|
|
|
return false, incorrectTypeForFlagError(name, "bool", otherGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(bool)
|
|
|
|
if !isType {
|
|
|
|
return false, incorrectTypeForFlagError(name, "bool", nestedGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// BoolT returns an bool from the map otherwise returns true
|
|
|
|
func (fsm *MapInputSource) BoolT(name string) (bool, error) {
|
|
|
|
otherGenericValue, exists := fsm.valueMap[name]
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := otherGenericValue.(bool)
|
|
|
|
if !isType {
|
|
|
|
return true, incorrectTypeForFlagError(name, "bool", otherGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2016-04-29 16:33:59 +00:00
|
|
|
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
|
|
|
if exists {
|
|
|
|
otherValue, isType := nestedGenericValue.(bool)
|
|
|
|
if !isType {
|
|
|
|
return true, incorrectTypeForFlagError(name, "bool", nestedGenericValue)
|
|
|
|
}
|
|
|
|
return otherValue, nil
|
|
|
|
}
|
2015-12-09 17:15:46 +00:00
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func incorrectTypeForFlagError(name, expectedTypeName string, value interface{}) error {
|
|
|
|
valueType := reflect.TypeOf(value)
|
|
|
|
valueTypeName := ""
|
|
|
|
if valueType != nil {
|
|
|
|
valueTypeName = valueType.Name()
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("Mismatched type for flag '%s'. Expected '%s' but actual is '%s'", name, expectedTypeName, valueTypeName)
|
|
|
|
}
|