Update to add build contraints to not compile in yaml support
in the case the golang version is less than golang 1.2
This commit is contained in:
parent
0c3102278a
commit
d3b02e41b0
46
README.md
46
README.md
@ -28,7 +28,7 @@ export PATH=$PATH:$GOPATH/bin
|
||||
|
||||
## Getting Started
|
||||
|
||||
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
|
||||
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
|
||||
|
||||
``` go
|
||||
package main
|
||||
@ -60,7 +60,7 @@ func main() {
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("boom! I say!")
|
||||
}
|
||||
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
```
|
||||
@ -238,6 +238,48 @@ app.Flags = []cli.Flag {
|
||||
}
|
||||
```
|
||||
|
||||
#### Values from alternate input sources (YAML and others)
|
||||
|
||||
There is a separate package altsrc that adds support for getting flag values from other input sources like YAML.
|
||||
|
||||
In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below:
|
||||
|
||||
``` go
|
||||
altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
|
||||
```
|
||||
|
||||
Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below.
|
||||
|
||||
``` go
|
||||
command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
```
|
||||
|
||||
The code above will use the "load" string as a flag name to get the file name of a yaml file from the cli.Context.
|
||||
It will then use that file name to initialize the yaml input source for any flags that are defined on that command.
|
||||
As a note the "load" flag used would also have to be defined on the command flags in order for this code snipped to work.
|
||||
|
||||
Currently only YAML files are supported but developers can add support for other input sources by implementing the
|
||||
altsrc.InputSourceContext for their given sources.
|
||||
|
||||
Here is a more complete sample of a command using YAML support:
|
||||
|
||||
``` go
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) {
|
||||
// Action to run
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c)
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
Subcommands can be defined for a more git-like command line app.
|
||||
|
@ -1,4 +1,4 @@
|
||||
package inputfilesupport
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
@ -14,7 +14,53 @@ import (
|
||||
// allows a value to be set on the existing parsed flags.
|
||||
type FlagInputSourceExtension interface {
|
||||
cli.Flag
|
||||
ApplyInputSourceValue(context *cli.Context, isc InputSourceContext)
|
||||
ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error
|
||||
}
|
||||
|
||||
// ApplyInputSourceValues iterates over all provided flags and
|
||||
// executes ApplyInputSourceValue on flags implementing the
|
||||
// FlagInputSourceExtension interface to initialize these flags
|
||||
// to an alternate input source.
|
||||
func ApplyInputSourceValues(context *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error {
|
||||
for _, f := range flags {
|
||||
inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension)
|
||||
if isType {
|
||||
err := inputSourceExtendedFlag.ApplyInputSourceValue(context, inputSourceContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitInputSource is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
|
||||
// input source based on the func provided. If there is no error it will then apply the new input source to any flags
|
||||
// that are supported by the input source
|
||||
func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) func(context *cli.Context) error {
|
||||
return func(context *cli.Context) error {
|
||||
inputSource, err := createInputSource()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create input source: inner error: \n'%v'", err.Error())
|
||||
}
|
||||
|
||||
return ApplyInputSourceValues(context, inputSource, flags)
|
||||
}
|
||||
}
|
||||
|
||||
// InitInputSourceWithContext is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
|
||||
// input source based on the func provided with potentially using existing cli.Context values to initialize itself. If there is
|
||||
// no error it will then apply the new input source to any flags that are supported by the input source
|
||||
func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context *cli.Context) (InputSourceContext, error)) func(context *cli.Context) error {
|
||||
return func(context *cli.Context) error {
|
||||
inputSource, err := createInputSource(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create input source with context: inner error: \n'%v'", err.Error())
|
||||
}
|
||||
|
||||
return ApplyInputSourceValues(context, inputSource, flags)
|
||||
}
|
||||
}
|
||||
|
||||
// GenericFlag is the flag type that wraps cli.GenericFlag to allow
|
||||
@ -30,10 +76,13 @@ func NewGenericFlag(flag cli.GenericFlag) *GenericFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a generic value to the flagSet if required
|
||||
func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||
value := isc.Generic(f.GenericFlag.Name)
|
||||
value, err := isc.Generic(f.GenericFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value != nil {
|
||||
eachName(f.Name, func(name string) {
|
||||
f.set.Set(f.Name, value.String())
|
||||
@ -41,6 +90,8 @@ func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -63,10 +114,13 @@ func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
||||
func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||
value := isc.StringSlice(f.StringSliceFlag.Name)
|
||||
value, err := isc.StringSlice(f.StringSliceFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value != nil {
|
||||
var sliceValue cli.StringSlice = value
|
||||
eachName(f.Name, func(name string) {
|
||||
@ -78,6 +132,7 @@ func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputS
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -100,10 +155,13 @@ func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a IntSlice value if required
|
||||
func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||
value := isc.IntSlice(f.IntSliceFlag.Name)
|
||||
value, err := isc.IntSlice(f.IntSliceFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value != nil {
|
||||
var sliceValue cli.IntSlice = value
|
||||
eachName(f.Name, func(name string) {
|
||||
@ -115,6 +173,7 @@ func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSour
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -137,10 +196,13 @@ func NewBoolFlag(flag cli.BoolFlag) *BoolFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Bool value to the flagSet if required
|
||||
func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||
value := isc.Bool(f.BoolFlag.Name)
|
||||
value, err := isc.Bool(f.BoolFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value {
|
||||
eachName(f.Name, func(name string) {
|
||||
f.set.Set(f.Name, strconv.FormatBool(value))
|
||||
@ -148,6 +210,7 @@ func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceCo
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -170,10 +233,13 @@ func NewBoolTFlag(flag cli.BoolTFlag) *BoolTFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a BoolT value to the flagSet if required
|
||||
func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
||||
value := isc.BoolT(f.BoolTFlag.Name)
|
||||
value, err := isc.BoolT(f.BoolTFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !value {
|
||||
eachName(f.Name, func(name string) {
|
||||
f.set.Set(f.Name, strconv.FormatBool(value))
|
||||
@ -181,6 +247,7 @@ func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceC
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -204,10 +271,13 @@ func NewStringFlag(flag cli.StringFlag) *StringFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a String value to the flagSet if required
|
||||
func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||
value := isc.String(f.StringFlag.Name)
|
||||
value, err := isc.String(f.StringFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value != "" {
|
||||
eachName(f.Name, func(name string) {
|
||||
f.set.Set(f.Name, value)
|
||||
@ -215,6 +285,7 @@ func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSource
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -238,10 +309,13 @@ func NewIntFlag(flag cli.IntFlag) *IntFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a int value to the flagSet if required
|
||||
func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||
value := isc.Int(f.IntFlag.Name)
|
||||
value, err := isc.Int(f.IntFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value > 0 {
|
||||
eachName(f.Name, func(name string) {
|
||||
f.set.Set(f.Name, strconv.FormatInt(int64(value), 10))
|
||||
@ -249,6 +323,7 @@ func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceCon
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -271,10 +346,13 @@ func NewDurationFlag(flag cli.DurationFlag) *DurationFlag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Duration value to the flagSet if required
|
||||
func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||
value := isc.Duration(f.DurationFlag.Name)
|
||||
value, err := isc.Duration(f.DurationFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value > 0 {
|
||||
eachName(f.Name, func(name string) {
|
||||
f.set.Set(f.Name, value.String())
|
||||
@ -282,6 +360,7 @@ func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSour
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
||||
@ -305,10 +384,13 @@ func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag {
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
||||
func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) {
|
||||
func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||
if f.set != nil {
|
||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
||||
value := isc.Float64(f.Float64Flag.Name)
|
||||
value, err := isc.Float64(f.Float64Flag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value > 0 {
|
||||
floatStr := float64ToString(value)
|
||||
eachName(f.Name, func(name string) {
|
||||
@ -317,6 +399,7 @@ func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourc
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage then calls
|
@ -1,4 +1,4 @@
|
||||
package inputfilesupport
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
@ -1,4 +1,4 @@
|
||||
package inputfilesupport
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"reflect"
|
21
altsrc/input_source_context.go
Normal file
21
altsrc/input_source_context.go
Normal file
@ -0,0 +1,21 @@
|
||||
package altsrc
|
||||
|
||||
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, error)
|
||||
Duration(name string) (time.Duration, error)
|
||||
Float64(name string) (float64, error)
|
||||
String(name string) (string, error)
|
||||
StringSlice(name string) ([]string, error)
|
||||
IntSlice(name string) ([]int, error)
|
||||
Generic(name string) (cli.Generic, error)
|
||||
Bool(name string) (bool, error)
|
||||
BoolT(name string) (bool, error)
|
||||
}
|
152
altsrc/map_input_source.go
Normal file
152
altsrc/map_input_source.go
Normal file
@ -0,0 +1,152 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
// MapInputSource implements InputSourceContext to return
|
||||
// data from the map that is loaded.
|
||||
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, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.(int)
|
||||
if !isType {
|
||||
return 0, incorrectTypeForFlagError(name, "int", otherGenericValue)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.([]string)
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "[]string", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 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]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.([]int)
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "[]int", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
@ -1,4 +1,9 @@
|
||||
package inputfilesupport
|
||||
// Disabling building of yaml support in cases where golang is 1.0 or 1.1
|
||||
// as the encoding library is not implemented or supported.
|
||||
|
||||
// +build !go1,!go1.1
|
||||
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
@ -32,7 +37,7 @@ func TestCommandYamlFileTest(t *testing.T) {
|
||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitializeYaml("load", command.Flags)
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c)
|
||||
|
||||
expect(t, err, nil)
|
||||
@ -64,7 +69,7 @@ func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
|
||||
NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitializeYaml("load", command.Flags)
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c)
|
||||
|
||||
@ -95,7 +100,7 @@ func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
|
||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitializeYaml("load", command.Flags)
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c)
|
||||
|
||||
@ -126,7 +131,7 @@ func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
|
||||
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitializeYaml("load", command.Flags)
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c)
|
||||
|
||||
@ -160,7 +165,7 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T
|
||||
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitializeYaml("load", command.Flags)
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c)
|
||||
|
||||
expect(t, err, nil)
|
@ -1,4 +1,9 @@
|
||||
package inputfilesupport
|
||||
// Disabling building of yaml support in cases where golang is 1.0 or 1.1
|
||||
// as the encoding library is not implemented or supported.
|
||||
|
||||
// +build !go1,!go1.1
|
||||
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -8,54 +13,34 @@ import (
|
||||
"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 {
|
||||
type yamlSourceContext 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) {
|
||||
// NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
|
||||
func NewYamlSourceFromFile(file string) (InputSourceContext, error) {
|
||||
ymlLoader := &yamlSourceLoader{FilePath: file}
|
||||
var results map[string]interface{}
|
||||
err := readCommandYaml(ysl.FilePath, &results)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return fmt.Errorf("Unable to load Yaml file '%s': inner error: \n'%v'", filePath, err.Error())
|
||||
}
|
||||
|
||||
return &MapInputSource{valueMap: results}, nil
|
||||
}
|
||||
|
||||
// NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a provided flag name and source context.
|
||||
func NewYamlSourceFromFlagFunc(flagFileName string) func(InputSourceContext, error) {
|
||||
return func(context cli.Context) {
|
||||
filePath := context.String(flagFileName)
|
||||
return NewYamlSourceFromFile(filePath)
|
||||
}
|
||||
}
|
||||
|
||||
func readCommandYaml(filePath string, container interface{}) (err error) {
|
||||
b, err := loadDataFrom(filePath)
|
||||
if err != nil {
|
@ -1,21 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user