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
|
## 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
|
``` go
|
||||||
package main
|
package main
|
||||||
@ -60,7 +60,7 @@ func main() {
|
|||||||
app.Action = func(c *cli.Context) {
|
app.Action = func(c *cli.Context) {
|
||||||
println("boom! I say!")
|
println("boom! I say!")
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Run(os.Args)
|
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
|
||||||
|
|
||||||
Subcommands can be defined for a more git-like command line app.
|
Subcommands can be defined for a more git-like command line app.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package inputfilesupport
|
package altsrc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
@ -14,7 +14,53 @@ import (
|
|||||||
// allows a value to be set on the existing parsed flags.
|
// allows a value to be set on the existing parsed flags.
|
||||||
type FlagInputSourceExtension interface {
|
type FlagInputSourceExtension interface {
|
||||||
cli.Flag
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
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 {
|
if value != nil {
|
||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
f.set.Set(f.Name, value.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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
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 {
|
if value != nil {
|
||||||
var sliceValue cli.StringSlice = value
|
var sliceValue cli.StringSlice = value
|
||||||
eachName(f.Name, func(name string) {
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
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 {
|
if value != nil {
|
||||||
var sliceValue cli.IntSlice = value
|
var sliceValue cli.IntSlice = value
|
||||||
eachName(f.Name, func(name string) {
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
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 {
|
if value {
|
||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
f.set.Set(f.Name, strconv.FormatBool(value))
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
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 {
|
if !value {
|
||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
f.set.Set(f.Name, strconv.FormatBool(value))
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
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 != "" {
|
if value != "" {
|
||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
f.set.Set(f.Name, value)
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
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 {
|
if value > 0 {
|
||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
f.set.Set(f.Name, strconv.FormatInt(int64(value), 10))
|
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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
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 {
|
if value > 0 {
|
||||||
eachName(f.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
f.set.Set(f.Name, value.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
|
// 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
|
// 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 f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
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 {
|
if value > 0 {
|
||||||
floatStr := float64ToString(value)
|
floatStr := float64ToString(value)
|
||||||
eachName(f.Name, func(name string) {
|
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
|
// Apply saves the flagSet for later usage then calls
|
@ -1,4 +1,4 @@
|
|||||||
package inputfilesupport
|
package altsrc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
@ -1,4 +1,4 @@
|
|||||||
package inputfilesupport
|
package altsrc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"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 (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
@ -32,7 +37,7 @@ func TestCommandYamlFileTest(t *testing.T) {
|
|||||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitializeYaml("load", command.Flags)
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
|
|
||||||
expect(t, err, nil)
|
expect(t, err, nil)
|
||||||
@ -64,7 +69,7 @@ func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
|
|||||||
NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
|
NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitializeYaml("load", command.Flags)
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
|
|
||||||
@ -95,7 +100,7 @@ func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
|
|||||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitializeYaml("load", command.Flags)
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
|
|
||||||
@ -126,7 +131,7 @@ func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
|
|||||||
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
|
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
|
||||||
cli.StringFlag{Name: "load"}},
|
cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitializeYaml("load", command.Flags)
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
|
|
||||||
@ -160,7 +165,7 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T
|
|||||||
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
|
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitializeYaml("load", command.Flags)
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
|
|
||||||
expect(t, err, nil)
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -8,54 +13,34 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoadFlag is a default load flag used to get a inputFilePath for a yaml file
|
type yamlSourceContext struct {
|
||||||
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
|
FilePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load returns an input source if successful or an error if there is a failure
|
// NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
|
||||||
// loading the yaml file
|
func NewYamlSourceFromFile(file string) (InputSourceContext, error) {
|
||||||
func (ysl *YamlSourceLoader) Load() (InputSourceContext, error) {
|
ymlLoader := &yamlSourceLoader{FilePath: file}
|
||||||
var results map[string]interface{}
|
var results map[string]interface{}
|
||||||
err := readCommandYaml(ysl.FilePath, &results)
|
err := readCommandYaml(ysl.FilePath, &results)
|
||||||
if err != nil {
|
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
|
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) {
|
func readCommandYaml(filePath string, container interface{}) (err error) {
|
||||||
b, err := loadDataFrom(filePath)
|
b, err := loadDataFrom(filePath)
|
||||||
if err != nil {
|
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