commit
6aa0ab6903
@ -0,0 +1,37 @@
|
|||||||
|
default: test
|
||||||
|
|
||||||
|
deps:
|
||||||
|
go get golang.org/x/tools/cmd/goimports || true
|
||||||
|
go get github.com/urfave/gfmrun/... || true
|
||||||
|
go list ./... \
|
||||||
|
| xargs go list -f '{{ join .Deps "\n" }}{{ printf "\n" }}{{ join .TestImports "\n" }}' \
|
||||||
|
| grep -v github.com/urfave/cli \
|
||||||
|
| xargs go get
|
||||||
|
@if [ ! -f node_modules/.bin/markdown-toc ]; then \
|
||||||
|
npm install markdown-toc ; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
gen: deps
|
||||||
|
./runtests gen
|
||||||
|
|
||||||
|
vet:
|
||||||
|
./runtests vet
|
||||||
|
|
||||||
|
gfmrun:
|
||||||
|
./runtests gfmrun
|
||||||
|
|
||||||
|
v1-to-v2:
|
||||||
|
./cli-v1-to-v2 --selftest
|
||||||
|
|
||||||
|
migrations:
|
||||||
|
./runtests migrations
|
||||||
|
|
||||||
|
toc:
|
||||||
|
./runtests toc
|
||||||
|
|
||||||
|
test: deps
|
||||||
|
./runtests test
|
||||||
|
|
||||||
|
all: gen vet test gfmrun v1-to-v2 migrations toc
|
||||||
|
|
||||||
|
.PHONY: default gen vet test gfmrun migrations toc v1-to-v2 deps all
|
@ -0,0 +1,310 @@
|
|||||||
|
// Disabling building of toml support in cases where golang is 1.0 or 1.1
|
||||||
|
// as the encoding library is not implemented or supported.
|
||||||
|
|
||||||
|
// +build go1.2
|
||||||
|
|
||||||
|
package altsrc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommandTomFileTest(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 15)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileTestGlobalEnvVarWins(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
os.Setenv("THE_TEST", "10")
|
||||||
|
defer os.Setenv("THE_TEST", "")
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 10)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileTestGlobalEnvVarWinsNested(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
os.Setenv("THE_TEST", "10")
|
||||||
|
defer os.Setenv("THE_TEST", "")
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("top.test")
|
||||||
|
expect(t, val, 10)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileTestSpecifiedFlagWins(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml", "--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) error {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 7)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileTestSpecifiedFlagWinsNested(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte(`[top]
|
||||||
|
test = 15`), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml", "--top.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) error {
|
||||||
|
val := c.Int("top.test")
|
||||||
|
expect(t, val, 7)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "top.test"}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileTestDefaultValueFileWins(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 15)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileTestDefaultValueFileWinsNested(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("top.test")
|
||||||
|
expect(t, val, 15)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileFlagHasDefaultGlobalEnvTomlSetGlobalEnvWins(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
os.Setenv("THE_TEST", "11")
|
||||||
|
defer os.Setenv("THE_TEST", "")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("test")
|
||||||
|
expect(t, val, 11)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandTomlFileFlagHasDefaultGlobalEnvTomlSetGlobalEnvWinsNested(t *testing.T) {
|
||||||
|
app := (&cli.App{})
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
|
||||||
|
defer os.Remove("current.toml")
|
||||||
|
|
||||||
|
os.Setenv("THE_TEST", "11")
|
||||||
|
defer os.Setenv("THE_TEST", "")
|
||||||
|
|
||||||
|
test := []string{"test-cmd", "--load", "current.toml"}
|
||||||
|
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) error {
|
||||||
|
val := c.Int("top.test")
|
||||||
|
expect(t, val, 11)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||||
|
&cli.StringFlag{Name: "load"}},
|
||||||
|
}
|
||||||
|
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||||
|
err := command.Run(c)
|
||||||
|
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
// Disabling building of toml support in cases where golang is 1.0 or 1.1
|
||||||
|
// as the encoding library is not implemented or supported.
|
||||||
|
|
||||||
|
// +build go1.2
|
||||||
|
|
||||||
|
package altsrc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tomlMap struct {
|
||||||
|
Map map[interface{}]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalMap(i interface{}) (ret map[interface{}]interface{}, err error) {
|
||||||
|
ret = make(map[interface{}]interface{})
|
||||||
|
m := i.(map[string]interface{})
|
||||||
|
for key, val := range m {
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
ret[key] = val.(bool)
|
||||||
|
case reflect.String:
|
||||||
|
ret[key] = val.(string)
|
||||||
|
case reflect.Int:
|
||||||
|
ret[key] = int(val.(int))
|
||||||
|
case reflect.Int8:
|
||||||
|
ret[key] = int(val.(int8))
|
||||||
|
case reflect.Int16:
|
||||||
|
ret[key] = int(val.(int16))
|
||||||
|
case reflect.Int32:
|
||||||
|
ret[key] = int(val.(int32))
|
||||||
|
case reflect.Int64:
|
||||||
|
ret[key] = int(val.(int64))
|
||||||
|
case reflect.Uint:
|
||||||
|
ret[key] = int(val.(uint))
|
||||||
|
case reflect.Uint8:
|
||||||
|
ret[key] = int(val.(uint8))
|
||||||
|
case reflect.Uint16:
|
||||||
|
ret[key] = int(val.(uint16))
|
||||||
|
case reflect.Uint32:
|
||||||
|
ret[key] = int(val.(uint32))
|
||||||
|
case reflect.Uint64:
|
||||||
|
ret[key] = int(val.(uint64))
|
||||||
|
case reflect.Float32:
|
||||||
|
ret[key] = float64(val.(float32))
|
||||||
|
case reflect.Float64:
|
||||||
|
ret[key] = float64(val.(float64))
|
||||||
|
case reflect.Map:
|
||||||
|
if tmp, err := unmarshalMap(val); err == nil {
|
||||||
|
ret[key] = tmp
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case reflect.Array:
|
||||||
|
fallthrough // [todo] - Support array type
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unsupported: type = %#v", v.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *tomlMap) UnmarshalTOML(i interface{}) error {
|
||||||
|
if tmp, err := unmarshalMap(i); err == nil {
|
||||||
|
self.Map = tmp
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tomlSourceContext struct {
|
||||||
|
FilePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTomlSourceFromFile creates a new TOML InputSourceContext from a filepath.
|
||||||
|
func NewTomlSourceFromFile(file string) (InputSourceContext, error) {
|
||||||
|
tsc := &tomlSourceContext{FilePath: file}
|
||||||
|
var results tomlMap = tomlMap{}
|
||||||
|
if err := readCommandToml(tsc.FilePath, &results); err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to load TOML file '%s': inner error: \n'%v'", tsc.FilePath, err.Error())
|
||||||
|
}
|
||||||
|
return &MapInputSource{valueMap: results.Map}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTomlSourceFromFlagFunc creates a new TOML InputSourceContext from a provided flag name and source context.
|
||||||
|
func NewTomlSourceFromFlagFunc(flagFileName string) func(context *cli.Context) (InputSourceContext, error) {
|
||||||
|
return func(context *cli.Context) (InputSourceContext, error) {
|
||||||
|
filePath := context.String(flagFileName)
|
||||||
|
return NewTomlSourceFromFile(filePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCommandToml(filePath string, container interface{}) (err error) {
|
||||||
|
b, err := loadDataFrom(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = toml.Unmarshal(b, container)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in new issue