Update to add yaml support
This commit is contained in:
parent
9001f738f4
commit
0c3102278a
356
inputfilesupport/flag.go
Normal file
356
inputfilesupport/flag.go
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FlagInputSourceExtension is an extension interface of cli.Flag that
|
||||||
|
// allows a value to be set on the existing parsed flags.
|
||||||
|
type FlagInputSourceExtension interface {
|
||||||
|
cli.Flag
|
||||||
|
ApplyInputSourceValue(context *cli.Context, isc InputSourceContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericFlag is the flag type that wraps cli.GenericFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type GenericFlag struct {
|
||||||
|
cli.GenericFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGenericFlag creates a new GenericFlag
|
||||||
|
func NewGenericFlag(flag cli.GenericFlag) *GenericFlag {
|
||||||
|
return &GenericFlag{GenericFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a generic value to the flagSet if required
|
||||||
|
func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||||
|
value := isc.Generic(f.GenericFlag.Name)
|
||||||
|
if value != nil {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, value.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped GenericFlag.Apply
|
||||||
|
func (f *GenericFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
f.GenericFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type StringSliceFlag struct {
|
||||||
|
cli.StringSliceFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStringSliceFlag creates a new StringSliceFlag
|
||||||
|
func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag {
|
||||||
|
return &StringSliceFlag{StringSliceFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
||||||
|
func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||||
|
value := isc.StringSlice(f.StringSliceFlag.Name)
|
||||||
|
if value != nil {
|
||||||
|
var sliceValue cli.StringSlice = value
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
underlyingFlag := f.set.Lookup(f.Name)
|
||||||
|
if underlyingFlag != nil {
|
||||||
|
underlyingFlag.Value = &sliceValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped StringSliceFlag.Apply
|
||||||
|
func (f *StringSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
f.StringSliceFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type IntSliceFlag struct {
|
||||||
|
cli.IntSliceFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIntSliceFlag creates a new IntSliceFlag
|
||||||
|
func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag {
|
||||||
|
return &IntSliceFlag{IntSliceFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a IntSlice value if required
|
||||||
|
func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||||
|
value := isc.IntSlice(f.IntSliceFlag.Name)
|
||||||
|
if value != nil {
|
||||||
|
var sliceValue cli.IntSlice = value
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
underlyingFlag := f.set.Lookup(f.Name)
|
||||||
|
if underlyingFlag != nil {
|
||||||
|
underlyingFlag.Value = &sliceValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped IntSliceFlag.Apply
|
||||||
|
func (f *IntSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
f.IntSliceFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolFlag is the flag type that wraps cli.BoolFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type BoolFlag struct {
|
||||||
|
cli.BoolFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBoolFlag creates a new BoolFlag
|
||||||
|
func NewBoolFlag(flag cli.BoolFlag) *BoolFlag {
|
||||||
|
return &BoolFlag{BoolFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a Bool value to the flagSet if required
|
||||||
|
func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||||
|
value := isc.Bool(f.BoolFlag.Name)
|
||||||
|
if value {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, strconv.FormatBool(value))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped BoolFlag.Apply
|
||||||
|
func (f *BoolFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
f.BoolFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolTFlag is the flag type that wraps cli.BoolTFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type BoolTFlag struct {
|
||||||
|
cli.BoolTFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBoolTFlag creates a new BoolTFlag
|
||||||
|
func NewBoolTFlag(flag cli.BoolTFlag) *BoolTFlag {
|
||||||
|
return &BoolTFlag{BoolTFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a BoolT value to the flagSet if required
|
||||||
|
func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||||
|
value := isc.BoolT(f.BoolTFlag.Name)
|
||||||
|
if !value {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, strconv.FormatBool(value))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped BoolTFlag.Apply
|
||||||
|
func (f *BoolTFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
|
||||||
|
f.BoolTFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringFlag is the flag type that wraps cli.StringFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type StringFlag struct {
|
||||||
|
cli.StringFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStringFlag creates a new StringFlag
|
||||||
|
func NewStringFlag(flag cli.StringFlag) *StringFlag {
|
||||||
|
return &StringFlag{StringFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a String value to the flagSet if required
|
||||||
|
func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||||
|
value := isc.String(f.StringFlag.Name)
|
||||||
|
if value != "" {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped StringFlag.Apply
|
||||||
|
func (f *StringFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
|
||||||
|
f.StringFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntFlag is the flag type that wraps cli.IntFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type IntFlag struct {
|
||||||
|
cli.IntFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIntFlag creates a new IntFlag
|
||||||
|
func NewIntFlag(flag cli.IntFlag) *IntFlag {
|
||||||
|
return &IntFlag{IntFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a int value to the flagSet if required
|
||||||
|
func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||||
|
value := isc.Int(f.IntFlag.Name)
|
||||||
|
if value > 0 {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, strconv.FormatInt(int64(value), 10))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped IntFlag.Apply
|
||||||
|
func (f *IntFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
f.IntFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationFlag is the flag type that wraps cli.DurationFlag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type DurationFlag struct {
|
||||||
|
cli.DurationFlag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDurationFlag creates a new DurationFlag
|
||||||
|
func NewDurationFlag(flag cli.DurationFlag) *DurationFlag {
|
||||||
|
return &DurationFlag{DurationFlag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a Duration value to the flagSet if required
|
||||||
|
func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||||
|
value := isc.Duration(f.DurationFlag.Name)
|
||||||
|
if value > 0 {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, value.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped DurationFlag.Apply
|
||||||
|
func (f *DurationFlag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
|
||||||
|
f.DurationFlag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Flag is the flag type that wraps cli.Float64Flag to allow
|
||||||
|
// for other values to be specified
|
||||||
|
type Float64Flag struct {
|
||||||
|
cli.Float64Flag
|
||||||
|
set *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFloat64Flag creates a new Float64Flag
|
||||||
|
func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag {
|
||||||
|
return &Float64Flag{Float64Flag: flag, set: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
||||||
|
func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||||
|
if f.set != nil {
|
||||||
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||||
|
value := isc.Float64(f.Float64Flag.Name)
|
||||||
|
if value > 0 {
|
||||||
|
floatStr := float64ToString(value)
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
f.set.Set(f.Name, floatStr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply saves the flagSet for later usage then calls
|
||||||
|
// the wrapped Float64Flag.Apply
|
||||||
|
func (f *Float64Flag) Apply(set *flag.FlagSet) {
|
||||||
|
f.set = set
|
||||||
|
|
||||||
|
f.Float64Flag.Apply(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEnvVarSet(envVars string) bool {
|
||||||
|
for _, envVar := range strings.Split(envVars, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
// TODO: Can't use this for bools as
|
||||||
|
// set means that it was true or false based on
|
||||||
|
// Bool flag type, should work for other types
|
||||||
|
if len(envVal) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func float64ToString(f float64) string {
|
||||||
|
return fmt.Sprintf("%v", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func eachName(longName string, fn func(string)) {
|
||||||
|
parts := strings.Split(longName, ",")
|
||||||
|
for _, name := range parts {
|
||||||
|
name = strings.Trim(name, " ")
|
||||||
|
fn(name)
|
||||||
|
}
|
||||||
|
}
|
336
inputfilesupport/flag_test.go
Normal file
336
inputfilesupport/flag_test.go
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testApplyInputSource struct {
|
||||||
|
Flag FlagInputSourceExtension
|
||||||
|
FlagName string
|
||||||
|
FlagSetName string
|
||||||
|
Expected string
|
||||||
|
ContextValueString string
|
||||||
|
ContextValue flag.Value
|
||||||
|
EnvVarValue string
|
||||||
|
EnvVarName string
|
||||||
|
MapValue interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenericApplyInputSourceValue(t *testing.T) {
|
||||||
|
v := &Parser{"abc", "def"}
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: v,
|
||||||
|
})
|
||||||
|
expect(t, v, c.Generic("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
p := &Parser{"abc", "def"}
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: &Parser{"efg", "hig"},
|
||||||
|
ContextValueString: p.String(),
|
||||||
|
})
|
||||||
|
expect(t, p, c.Generic("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}, EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: &Parser{"efg", "hij"},
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "abc,def",
|
||||||
|
})
|
||||||
|
expect(t, &Parser{"abc", "def"}, c.Generic("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceApplyInputSourceValue(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: []string{"hello", "world"},
|
||||||
|
})
|
||||||
|
expect(t, c.StringSlice("test"), []string{"hello", "world"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: []string{"hello", "world"},
|
||||||
|
ContextValueString: "ohno",
|
||||||
|
})
|
||||||
|
expect(t, c.StringSlice("test"), []string{"ohno"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: []string{"hello", "world"},
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "oh,no",
|
||||||
|
})
|
||||||
|
expect(t, c.StringSlice("test"), []string{"oh", "no"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntSliceApplyInputSourceValue(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: []int{1, 2},
|
||||||
|
})
|
||||||
|
expect(t, c.IntSlice("test"), []int{1, 2})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: []int{1, 2},
|
||||||
|
ContextValueString: "3",
|
||||||
|
})
|
||||||
|
expect(t, c.IntSlice("test"), []int{3})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: []int{1, 2},
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "3,4",
|
||||||
|
})
|
||||||
|
expect(t, c.IntSlice("test"), []int{3, 4})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolApplyInputSourceMethodSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: true,
|
||||||
|
})
|
||||||
|
expect(t, true, c.Bool("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: false,
|
||||||
|
ContextValueString: "true",
|
||||||
|
})
|
||||||
|
expect(t, true, c.Bool("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewBoolFlag(cli.BoolFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: false,
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "true",
|
||||||
|
})
|
||||||
|
expect(t, true, c.Bool("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolTApplyInputSourceMethodSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: false,
|
||||||
|
})
|
||||||
|
expect(t, false, c.BoolT("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolTApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: true,
|
||||||
|
ContextValueString: "false",
|
||||||
|
})
|
||||||
|
expect(t, false, c.BoolT("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolTApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: true,
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "false",
|
||||||
|
})
|
||||||
|
expect(t, false, c.BoolT("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringApplyInputSourceMethodSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewStringFlag(cli.StringFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: "hello",
|
||||||
|
})
|
||||||
|
expect(t, "hello", c.String("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewStringFlag(cli.StringFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: "hello",
|
||||||
|
ContextValueString: "goodbye",
|
||||||
|
})
|
||||||
|
expect(t, "goodbye", c.String("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewStringFlag(cli.StringFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: "hello",
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "goodbye",
|
||||||
|
})
|
||||||
|
expect(t, "goodbye", c.String("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntApplyInputSourceMethodSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: 15,
|
||||||
|
})
|
||||||
|
expect(t, 15, c.Int("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: 15,
|
||||||
|
ContextValueString: "7",
|
||||||
|
})
|
||||||
|
expect(t, 7, c.Int("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: 15,
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: "12",
|
||||||
|
})
|
||||||
|
expect(t, 12, c.Int("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDurationApplyInputSourceMethodSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: time.Duration(30 * time.Second),
|
||||||
|
})
|
||||||
|
expect(t, time.Duration(30*time.Second), c.Duration("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: time.Duration(30 * time.Second),
|
||||||
|
ContextValueString: time.Duration(15 * time.Second).String(),
|
||||||
|
})
|
||||||
|
expect(t, time.Duration(15*time.Second), c.Duration("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewDurationFlag(cli.DurationFlag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: time.Duration(30 * time.Second),
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: time.Duration(15 * time.Second).String(),
|
||||||
|
})
|
||||||
|
expect(t, time.Duration(15*time.Second), c.Duration("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: 1.3,
|
||||||
|
})
|
||||||
|
expect(t, 1.3, c.Float64("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: 1.3,
|
||||||
|
ContextValueString: fmt.Sprintf("%v", 1.4),
|
||||||
|
})
|
||||||
|
expect(t, 1.4, c.Float64("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
|
c := runTest(t, testApplyInputSource{
|
||||||
|
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test", EnvVar: "TEST"}),
|
||||||
|
FlagName: "test",
|
||||||
|
MapValue: 1.3,
|
||||||
|
EnvVarName: "TEST",
|
||||||
|
EnvVarValue: fmt.Sprintf("%v", 1.4),
|
||||||
|
})
|
||||||
|
expect(t, 1.4, c.Float64("test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTest(t *testing.T, test testApplyInputSource) *cli.Context {
|
||||||
|
inputSource := &MapInputSource{valueMap: map[string]interface{}{test.FlagName: test.MapValue}}
|
||||||
|
set := flag.NewFlagSet(test.FlagSetName, flag.ContinueOnError)
|
||||||
|
c := cli.NewContext(nil, set, nil)
|
||||||
|
if test.EnvVarName != "" && test.EnvVarValue != "" {
|
||||||
|
os.Setenv(test.EnvVarName, test.EnvVarValue)
|
||||||
|
defer os.Setenv(test.EnvVarName, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
test.Flag.Apply(set)
|
||||||
|
if test.ContextValue != nil {
|
||||||
|
flag := set.Lookup(test.FlagName)
|
||||||
|
flag.Value = test.ContextValue
|
||||||
|
}
|
||||||
|
if test.ContextValueString != "" {
|
||||||
|
set.Set(test.FlagName, test.ContextValueString)
|
||||||
|
}
|
||||||
|
test.Flag.ApplyInputSourceValue(c, inputSource)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parser [2]string
|
||||||
|
|
||||||
|
func (p *Parser) Set(value string) error {
|
||||||
|
parts := strings.Split(value, ",")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("invalid format")
|
||||||
|
}
|
||||||
|
|
||||||
|
(*p)[0] = parts[0]
|
||||||
|
(*p)[1] = parts[1]
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) String() string {
|
||||||
|
return fmt.Sprintf("%s,%s", p[0], p[1])
|
||||||
|
}
|
18
inputfilesupport/helpers_test.go
Normal file
18
inputfilesupport/helpers_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||||
|
if !reflect.DeepEqual(b, a) {
|
||||||
|
t.Errorf("Expected %#v (type %v) - Got %#v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||||
|
if a == b {
|
||||||
|
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||||
|
}
|
||||||
|
}
|
21
inputfilesupport/input_source_context.go
Normal file
21
inputfilesupport/input_source_context.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InputSourceContext is an interface used to allow
|
||||||
|
// other input sources to be implemented as needed.
|
||||||
|
type InputSourceContext interface {
|
||||||
|
Int(name string) int
|
||||||
|
Duration(name string) time.Duration
|
||||||
|
Float64(name string) float64
|
||||||
|
String(name string) string
|
||||||
|
StringSlice(name string) []string
|
||||||
|
IntSlice(name string) []int
|
||||||
|
Generic(name string) cli.Generic
|
||||||
|
Bool(name string) bool
|
||||||
|
BoolT(name string) bool
|
||||||
|
}
|
132
inputfilesupport/map_input_source.go
Normal file
132
inputfilesupport/map_input_source.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MapInputSource implements InputSourceContext to return
|
||||||
|
// data from the map that is loaded.
|
||||||
|
// TODO: Didn't implement a way to write out various errors
|
||||||
|
// need to figure this part out.
|
||||||
|
type MapInputSource struct {
|
||||||
|
valueMap map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns an int from the map if it exists otherwise returns 0
|
||||||
|
func (fsm *MapInputSource) Int(name string) int {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(int)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration returns a duration from the map if it exists otherwise returns 0
|
||||||
|
func (fsm *MapInputSource) Duration(name string) time.Duration {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(time.Duration)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 returns an float64 from the map if it exists otherwise returns 0
|
||||||
|
func (fsm *MapInputSource) Float64(name string) float64 {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(float64)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string from the map if it exists otherwise returns an empty string
|
||||||
|
func (fsm *MapInputSource) String(name string) string {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(string)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice returns an []string from the map if it exists otherwise returns nil
|
||||||
|
func (fsm *MapInputSource) StringSlice(name string) []string {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.([]string)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntSlice returns an []int from the map if it exists otherwise returns nil
|
||||||
|
func (fsm *MapInputSource) IntSlice(name string) []int {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.([]int)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic returns an cli.Generic from the map if it exists otherwise returns nil
|
||||||
|
func (fsm *MapInputSource) Generic(name string) cli.Generic {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(cli.Generic)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns an bool from the map otherwise returns false
|
||||||
|
func (fsm *MapInputSource) Bool(name string) bool {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(bool)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolT returns an bool from the map otherwise returns true
|
||||||
|
func (fsm *MapInputSource) BoolT(name string) bool {
|
||||||
|
otherGenericValue, exists := fsm.valueMap[name]
|
||||||
|
if exists {
|
||||||
|
otherValue, isType := otherGenericValue.(bool)
|
||||||
|
if isType {
|
||||||
|
return otherValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
167
inputfilesupport/yaml_command_test.go
Normal file
167
inputfilesupport/yaml_command_test.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommandYamlFileTest(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||||
|
defer os.Remove("current.yaml")
|
||||||
|
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||||
|
set.Parse(test)
|
||||||
|
|
||||||
|
c := cli.NewContext(app, set, nil)
|
||||||
|
|
||||||
|
command := &cli.Command{
|
||||||
|
Name: "test-cmd",
|
||||||
|
Aliases: []string{"tc"},
|
||||||
|
Usage: "this is for testing",
|
||||||
|
Description: "testing",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 15)
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
|
cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitializeYaml("load", command.Flags)
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||||
|
defer os.Remove("current.yaml")
|
||||||
|
|
||||||
|
os.Setenv("THE_TEST", "10")
|
||||||
|
defer os.Setenv("THE_TEST", "")
|
||||||
|
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||||
|
set.Parse(test)
|
||||||
|
|
||||||
|
c := cli.NewContext(app, set, nil)
|
||||||
|
|
||||||
|
command := &cli.Command{
|
||||||
|
Name: "test-cmd",
|
||||||
|
Aliases: []string{"tc"},
|
||||||
|
Usage: "this is for testing",
|
||||||
|
Description: "testing",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 10)
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
|
||||||
|
cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitializeYaml("load", command.Flags)
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||||
|
defer os.Remove("current.yaml")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.yaml", "--test", "7"}
|
||||||
|
set.Parse(test)
|
||||||
|
|
||||||
|
c := cli.NewContext(app, set, nil)
|
||||||
|
|
||||||
|
command := &cli.Command{
|
||||||
|
Name: "test-cmd",
|
||||||
|
Aliases: []string{"tc"},
|
||||||
|
Usage: "this is for testing",
|
||||||
|
Description: "testing",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 7)
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
|
cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitializeYaml("load", command.Flags)
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||||
|
defer os.Remove("current.yaml")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||||
|
set.Parse(test)
|
||||||
|
|
||||||
|
c := cli.NewContext(app, set, nil)
|
||||||
|
|
||||||
|
command := &cli.Command{
|
||||||
|
Name: "test-cmd",
|
||||||
|
Aliases: []string{"tc"},
|
||||||
|
Usage: "this is for testing",
|
||||||
|
Description: "testing",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 15)
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
|
||||||
|
cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitializeYaml("load", command.Flags)
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||||
|
defer os.Remove("current.yaml")
|
||||||
|
|
||||||
|
os.Setenv("THE_TEST", "11")
|
||||||
|
defer os.Setenv("THE_TEST", "")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||||
|
set.Parse(test)
|
||||||
|
|
||||||
|
c := cli.NewContext(app, set, nil)
|
||||||
|
|
||||||
|
command := &cli.Command{
|
||||||
|
Name: "test-cmd",
|
||||||
|
Aliases: []string{"tc"},
|
||||||
|
Usage: "this is for testing",
|
||||||
|
Description: "testing",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 11)
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
|
||||||
|
cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitializeYaml("load", command.Flags)
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
99
inputfilesupport/yaml_file_loader.go
Normal file
99
inputfilesupport/yaml_file_loader.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package inputfilesupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadFlag is a default load flag used to get a inputFilePath for a yaml file
|
||||||
|
var LoadFlag = cli.StringFlag{
|
||||||
|
Name: "load",
|
||||||
|
Usage: "file path to a yaml file",
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeYaml is used to initialize Before funcs for commands.
|
||||||
|
func InitializeYaml(filePathFlagName string, flags []cli.Flag) func(context *cli.Context) error {
|
||||||
|
return func(context *cli.Context) error {
|
||||||
|
filePath := context.String(filePathFlagName)
|
||||||
|
ymlLoader := &YamlSourceLoader{FilePath: filePath}
|
||||||
|
yamlInputSource, err := ymlLoader.Load()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to load Yaml file '%s': inner error: \n'%v'", filePath, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range flags {
|
||||||
|
inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension)
|
||||||
|
if isType {
|
||||||
|
inputSourceExtendedFlag.ApplyInputSourceValue(context, yamlInputSource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// YamlSourceLoader can load yaml files and return a InputSourceContext
|
||||||
|
// to be used for a parameter value
|
||||||
|
type YamlSourceLoader struct {
|
||||||
|
FilePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load returns an input source if successful or an error if there is a failure
|
||||||
|
// loading the yaml file
|
||||||
|
func (ysl *YamlSourceLoader) Load() (InputSourceContext, error) {
|
||||||
|
var results map[string]interface{}
|
||||||
|
err := readCommandYaml(ysl.FilePath, &results)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MapInputSource{valueMap: results}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCommandYaml(filePath string, container interface{}) (err error) {
|
||||||
|
b, err := loadDataFrom(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(b, container)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadDataFrom(filePath string) ([]byte, error) {
|
||||||
|
u, err := url.Parse(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Host != "" { // i have a host, now do i support the scheme?
|
||||||
|
switch u.Scheme {
|
||||||
|
case "http", "https":
|
||||||
|
res, err := http.Get(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutil.ReadAll(res.Body)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("scheme of %s is unsupported", filePath)
|
||||||
|
}
|
||||||
|
} else if u.Path != "" { // i dont have a host, but I have a path. I am a local file.
|
||||||
|
if _, notFoundFileErr := os.Stat(filePath); notFoundFileErr != nil {
|
||||||
|
return nil, fmt.Errorf("Cannot read from file: '%s' because it does not exist.", filePath)
|
||||||
|
}
|
||||||
|
return ioutil.ReadFile(filePath)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unable to determine how to load from path %s", filePath)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user