feat(kit/cli): add support for int32 and int64 CLI flags
parent
affb64c888
commit
a952dff92d
|
@ -150,6 +150,58 @@ func BindOptions(v *viper.Viper, cmd *cobra.Command, opts []Opt) {
|
||||||
}
|
}
|
||||||
mustBindPFlag(v, o.Flag, flagset)
|
mustBindPFlag(v, o.Flag, flagset)
|
||||||
*destP = v.GetInt(envVar)
|
*destP = v.GetInt(envVar)
|
||||||
|
case *int32:
|
||||||
|
var d int32
|
||||||
|
if o.Default != nil {
|
||||||
|
// N.B. since our CLI kit types default values as interface{} and
|
||||||
|
// literal numbers get typed as int by default, it's very easy to
|
||||||
|
// create an int32 CLI flag with an int default value.
|
||||||
|
//
|
||||||
|
// The compiler doesn't know to complain in that case, so you end up
|
||||||
|
// with a runtime panic when trying to bind the CLI options.
|
||||||
|
//
|
||||||
|
// To avoid that headache, we support both int32 and int defaults
|
||||||
|
// for int32 fields. This introduces a new runtime bomb if somebody
|
||||||
|
// specifies an int default > math.MaxInt32, but that's hopefully
|
||||||
|
// less likely.
|
||||||
|
var ok bool
|
||||||
|
d, ok = o.Default.(int32)
|
||||||
|
if !ok {
|
||||||
|
d = int32(o.Default.(int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasShort {
|
||||||
|
flagset.Int32VarP(destP, o.Flag, string(o.Short), d, o.Desc)
|
||||||
|
} else {
|
||||||
|
flagset.Int32Var(destP, o.Flag, d, o.Desc)
|
||||||
|
}
|
||||||
|
mustBindPFlag(v, o.Flag, flagset)
|
||||||
|
*destP = v.GetInt32(envVar)
|
||||||
|
case *int64:
|
||||||
|
var d int64
|
||||||
|
if o.Default != nil {
|
||||||
|
// N.B. since our CLI kit types default values as interface{} and
|
||||||
|
// literal numbers get typed as int by default, it's very easy to
|
||||||
|
// create an int64 CLI flag with an int default value.
|
||||||
|
//
|
||||||
|
// The compiler doesn't know to complain in that case, so you end up
|
||||||
|
// with a runtime panic when trying to bind the CLI options.
|
||||||
|
//
|
||||||
|
// To avoid that headache, we support both int64 and int defaults
|
||||||
|
// for int64 fields.
|
||||||
|
var ok bool
|
||||||
|
d, ok = o.Default.(int64)
|
||||||
|
if !ok {
|
||||||
|
d = int64(o.Default.(int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasShort {
|
||||||
|
flagset.Int64VarP(destP, o.Flag, string(o.Short), d, o.Desc)
|
||||||
|
} else {
|
||||||
|
flagset.Int64Var(destP, o.Flag, d, o.Desc)
|
||||||
|
}
|
||||||
|
mustBindPFlag(v, o.Flag, flagset)
|
||||||
|
*destP = v.GetInt64(envVar)
|
||||||
case *bool:
|
case *bool:
|
||||||
var d bool
|
var d bool
|
||||||
if o.Default != nil {
|
if o.Default != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -40,6 +41,8 @@ func (c *customFlag) Type() string {
|
||||||
func ExampleNewCommand() {
|
func ExampleNewCommand() {
|
||||||
var monitorHost string
|
var monitorHost string
|
||||||
var number int
|
var number int
|
||||||
|
var smallerNumber int32
|
||||||
|
var longerNumber int64
|
||||||
var sleep bool
|
var sleep bool
|
||||||
var duration time.Duration
|
var duration time.Duration
|
||||||
var stringSlice []string
|
var stringSlice []string
|
||||||
|
@ -50,6 +53,7 @@ func ExampleNewCommand() {
|
||||||
for i := 0; i < number; i++ {
|
for i := 0; i < number; i++ {
|
||||||
fmt.Printf("%d\n", i)
|
fmt.Printf("%d\n", i)
|
||||||
}
|
}
|
||||||
|
fmt.Println(longerNumber - int64(smallerNumber))
|
||||||
fmt.Println(sleep)
|
fmt.Println(sleep)
|
||||||
fmt.Println(duration)
|
fmt.Println(duration)
|
||||||
fmt.Println(stringSlice)
|
fmt.Println(stringSlice)
|
||||||
|
@ -70,6 +74,18 @@ func ExampleNewCommand() {
|
||||||
Default: 2,
|
Default: 2,
|
||||||
Desc: "number of times to loop",
|
Desc: "number of times to loop",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
DestP: &smallerNumber,
|
||||||
|
Flag: "smaller-number",
|
||||||
|
Default: math.MaxInt32,
|
||||||
|
Desc: "limited size number",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DestP: &longerNumber,
|
||||||
|
Flag: "longer-number",
|
||||||
|
Default: math.MaxInt64,
|
||||||
|
Desc: "explicitly expanded-size number",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
DestP: &sleep,
|
DestP: &sleep,
|
||||||
Flag: "sleep",
|
Flag: "sleep",
|
||||||
|
@ -104,6 +120,7 @@ func ExampleNewCommand() {
|
||||||
// http://localhost:8086
|
// http://localhost:8086
|
||||||
// 0
|
// 0
|
||||||
// 1
|
// 1
|
||||||
|
// 9223372034707292160
|
||||||
// true
|
// true
|
||||||
// 1m0s
|
// 1m0s
|
||||||
// [foo bar]
|
// [foo bar]
|
||||||
|
@ -113,8 +130,10 @@ func ExampleNewCommand() {
|
||||||
func Test_NewProgram(t *testing.T) {
|
func Test_NewProgram(t *testing.T) {
|
||||||
testFilePath, cleanup := newConfigFile(t, map[string]string{
|
testFilePath, cleanup := newConfigFile(t, map[string]string{
|
||||||
// config values should be same as flags
|
// config values should be same as flags
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"shoe-fly": "yadon",
|
"shoe-fly": "yadon",
|
||||||
|
"number": "2147483647",
|
||||||
|
"long-number": "9223372036854775807",
|
||||||
})
|
})
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
defer setEnvVar("TEST_CONFIG_PATH", testFilePath)()
|
defer setEnvVar("TEST_CONFIG_PATH", testFilePath)()
|
||||||
|
@ -155,6 +174,8 @@ func Test_NewProgram(t *testing.T) {
|
||||||
|
|
||||||
var testVar string
|
var testVar string
|
||||||
var testFly string
|
var testFly string
|
||||||
|
var testNumber int32
|
||||||
|
var testLongNumber int64
|
||||||
program := &Program{
|
program := &Program{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Opts: []Opt{
|
Opts: []Opt{
|
||||||
|
@ -167,6 +188,14 @@ func Test_NewProgram(t *testing.T) {
|
||||||
DestP: &testFly,
|
DestP: &testFly,
|
||||||
Flag: "shoe-fly",
|
Flag: "shoe-fly",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
DestP: &testNumber,
|
||||||
|
Flag: "number",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DestP: &testLongNumber,
|
||||||
|
Flag: "long-number",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Run: func() error { return nil },
|
Run: func() error { return nil },
|
||||||
}
|
}
|
||||||
|
@ -177,6 +206,8 @@ func Test_NewProgram(t *testing.T) {
|
||||||
|
|
||||||
require.Equal(t, tt.expected, testVar)
|
require.Equal(t, tt.expected, testVar)
|
||||||
assert.Equal(t, "yadon", testFly)
|
assert.Equal(t, "yadon", testFly)
|
||||||
|
assert.Equal(t, int32(math.MaxInt32), testNumber)
|
||||||
|
assert.Equal(t, int64(math.MaxInt64), testLongNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run(tt.name, fn)
|
t.Run(tt.name, fn)
|
||||||
|
|
Loading…
Reference in New Issue