Skip to content

Commit

Permalink
Update to add build contraints to not compile in yaml support
Browse files Browse the repository at this point in the history
in the case the golang version is less than golang 1.2
  • Loading branch information
ChrisPRobinson authored and Chris Robinson committed Feb 22, 2016
1 parent 0c31022 commit d3b02e4
Show file tree
Hide file tree
Showing 10 changed files with 353 additions and 218 deletions.
46 changes: 44 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -60,7 +60,7 @@ func main() {
app.Action = func(c *cli.Context) {
println("boom! I say!")
}

app.Run(os.Args)
}
```
Expand Down Expand Up @@ -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.
Expand Down
123 changes: 103 additions & 20 deletions inputfilesupport/flag.go → altsrc/flag.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package inputfilesupport
package altsrc

import (
"flag"
Expand All @@ -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
Expand All @@ -30,17 +76,22 @@ 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())
})
}
}
}

return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -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) {
Expand All @@ -78,6 +132,7 @@ func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputS
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -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) {
Expand All @@ -115,6 +173,7 @@ func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSour
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -137,17 +196,21 @@ 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))
})
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -170,17 +233,21 @@ 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))
})
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -204,17 +271,21 @@ 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)
})
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -238,17 +309,21 @@ 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))
})
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -271,17 +346,21 @@ 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())
})
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand All @@ -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) {
Expand All @@ -317,6 +399,7 @@ func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourc
}
}
}
return nil
}

// Apply saves the flagSet for later usage then calls
Expand Down
2 changes: 1 addition & 1 deletion inputfilesupport/flag_test.go → altsrc/flag_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package inputfilesupport
package altsrc

import (
"flag"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package inputfilesupport
package altsrc

import (
"reflect"
Expand Down
21 changes: 21 additions & 0 deletions altsrc/input_source_context.go
Original file line number Diff line number Diff line change
@@ -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)
}
Loading

0 comments on commit d3b02e4

Please sign in to comment.