Skip to content

Commit

Permalink
Feature: Add support for uint64slice flags
Browse files Browse the repository at this point in the history
  • Loading branch information
dearchap committed Apr 26, 2022
1 parent 9280375 commit 87ce263
Show file tree
Hide file tree
Showing 9 changed files with 674 additions and 8 deletions.
42 changes: 42 additions & 0 deletions altsrc/flag.go
Expand Up @@ -2,6 +2,7 @@ package altsrc

import (
"fmt"
"log"
"path/filepath"
"strconv"
"syscall"
Expand Down Expand Up @@ -119,6 +120,47 @@ func (f *IntSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceC
return nil
}

// ApplyInputSourceValue applies a Int64Slice value if required
func (f *Int64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
if f.set != nil && !cCtx.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) && isc.isSet(f.Int64SliceFlag.Name) {
value, err := isc.Int64Slice(f.Int64SliceFlag.Name)
if err != nil {
log.Print(err)
return err
}
if value != nil {
var sliceValue cli.Int64Slice = *(cli.NewInt64Slice(value...))
for _, name := range f.Names() {
underlyingFlag := f.set.Lookup(name)
if underlyingFlag != nil {
underlyingFlag.Value = &sliceValue
}
}
}
}
return nil
}

// ApplyInputSourceValue applies a Uint64Slice value if required
func (f *Uint64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
if f.set != nil && !cCtx.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) && isc.isSet(f.Uint64SliceFlag.Name) {
value, err := isc.Uint64Slice(f.Uint64SliceFlag.Name)
if err != nil {
return err
}
if value != nil {
var sliceValue cli.Uint64Slice = *(cli.NewUint64Slice(value...))
for _, name := range f.Names() {
underlyingFlag := f.set.Lookup(name)
if underlyingFlag != nil {
underlyingFlag.Value = &sliceValue
}
}
}
}
return nil
}

// ApplyInputSourceValue applies a Bool value to the flagSet if required
func (f *BoolFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
if f.set != nil && !cCtx.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) && isc.isSet(f.BoolFlag.Name) {
Expand Down
19 changes: 19 additions & 0 deletions altsrc/flag_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 84 additions & 0 deletions altsrc/flag_test.go
Expand Up @@ -165,6 +165,90 @@ func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
refute(t, c.IntSlice("test"), []int{3, 4})
}

func TestInt64SliceApplyInputSourceValue(t *testing.T) {
tis := testApplyInputSource{
Flag: NewInt64SliceFlag(&cli.Int64SliceFlag{Name: "test"}),
FlagName: "test",
MapValue: []interface{}{1, 2},
}
c := runTest(t, tis)
expect(t, c.Int64Slice("test"), []int64{1, 2})

c = runRacyTest(t, tis)
refute(t, c.Int64Slice("test"), []int64{1, 2})
}

func TestInt64SliceApplyInputSourceMethodContextSet(t *testing.T) {
tis := testApplyInputSource{
Flag: NewInt64SliceFlag(&cli.Int64SliceFlag{Name: "test"}),
FlagName: "test",
MapValue: []interface{}{1, 2},
ContextValueString: "3",
}
c := runTest(t, tis)
expect(t, c.Int64Slice("test"), []int64{3})

c = runRacyTest(t, tis)
refute(t, c.Int64Slice("test"), []int64{3})
}

func TestInt64SliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
tis := testApplyInputSource{
Flag: NewInt64SliceFlag(&cli.Int64SliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test",
MapValue: []interface{}{1, 2},
EnvVarName: "TEST",
EnvVarValue: "3,4",
}
c := runTest(t, tis)
expect(t, c.Int64Slice("test"), []int64{3, 4})

c = runRacyTest(t, tis)
refute(t, c.Int64Slice("test"), []int64{3, 4})
}

func TestUInt64SliceApplyInputSourceValue(t *testing.T) {
tis := testApplyInputSource{
Flag: NewUint64SliceFlag(&cli.Uint64SliceFlag{Name: "test"}),
FlagName: "test",
MapValue: []interface{}{1, 2},
}
c := runTest(t, tis)
expect(t, c.Uint64Slice("test"), []uint64{1, 2})

c = runRacyTest(t, tis)
refute(t, c.Uint64Slice("test"), []uint64{1, 2})
}

func TestUInt64SliceApplyInputSourceMethodContextSet(t *testing.T) {
tis := testApplyInputSource{
Flag: NewUint64SliceFlag(&cli.Uint64SliceFlag{Name: "test"}),
FlagName: "test",
MapValue: []interface{}{1, 2},
ContextValueString: "3",
}
c := runTest(t, tis)
expect(t, c.Uint64Slice("test"), []uint64{3})

c = runRacyTest(t, tis)
refute(t, c.Uint64Slice("test"), []uint64{3})
}

func TestUint64SliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
tis := testApplyInputSource{
Flag: NewUint64SliceFlag(&cli.Uint64SliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
FlagName: "test",
MapValue: []interface{}{1, 2},
EnvVarName: "TEST",
EnvVarValue: "3,4",
}
c := runTest(t, tis)
expect(t, c.Uint64Slice("test"), []uint64{3, 4})

c = runRacyTest(t, tis)
refute(t, c.Uint64Slice("test"), []uint64{3, 4})
}

func TestBoolApplyInputSourceMethodSet(t *testing.T) {
tis := testApplyInputSource{
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
Expand Down
2 changes: 2 additions & 0 deletions altsrc/input_source_context.go
Expand Up @@ -20,6 +20,8 @@ type InputSourceContext interface {
String(name string) (string, error)
StringSlice(name string) ([]string, error)
IntSlice(name string) ([]int, error)
Int64Slice(name string) ([]int64, error)
Uint64Slice(name string) ([]uint64, error)
Generic(name string) (cli.Generic, error)
Bool(name string) (bool, error)

Expand Down
54 changes: 54 additions & 0 deletions altsrc/json_source_context.go
Expand Up @@ -160,6 +160,60 @@ func (x *jsonSource) IntSlice(name string) ([]int, error) {
}
}

func (x *jsonSource) Int64Slice(name string) ([]int64, error) {
i, err := x.getValue(name)
if err != nil {
return nil, err
}
switch v := i.(type) {
default:
return nil, fmt.Errorf("unexpected type %T for %q", i, name)
case []int:
c := []int64{}
for _, s := range v {
c = append(c, int64(s))
}
return c, nil
case []interface{}:
c := []int64{}
for _, s := range v {
if i2, ok := s.(int64); ok {
c = append(c, i2)
} else {
return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
}
}
return c, nil
}
}

func (x *jsonSource) Uint64Slice(name string) ([]uint64, error) {
i, err := x.getValue(name)
if err != nil {
return nil, err
}
switch v := i.(type) {
default:
return nil, fmt.Errorf("unexpected type %T for %q", i, name)
case []int:
c := []uint64{}
for _, s := range v {
c = append(c, uint64(s))
}
return c, nil
case []interface{}:
c := []uint64{}
for _, s := range v {
if i2, ok := s.(uint64); ok {
c = append(c, i2)
} else {
return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
}
}
return c, nil
}
}

func (x *jsonSource) Generic(name string) (cli.Generic, error) {
i, err := x.getValue(name)
if err != nil {
Expand Down
68 changes: 68 additions & 0 deletions altsrc/map_input_source.go
Expand Up @@ -200,6 +200,74 @@ func (fsm *MapInputSource) IntSlice(name string) ([]int, error) {
return intSlice, nil
}

// Int64Slice returns an []int64 from the map if it exists otherwise returns nil
func (fsm *MapInputSource) Int64Slice(name string) ([]int64, error) {
otherGenericValue, exists := fsm.valueMap[name]
if !exists {
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
if !exists {
return nil, nil
}
}

otherValue, isType := otherGenericValue.([]interface{})
if !isType {
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
}

var int64Slice = make([]int64, 0, len(otherValue))
for i, v := range otherValue {
var int64Value int64
switch v.(type) {
case int:
int64Value = int64(v.(int))
case int64:
int64Value = v.(int64)
default:
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "int64", v)
}

int64Slice = append(int64Slice, int64Value)
}

return int64Slice, nil
}

// Uint64Slice returns an []uint64 from the map if it exists otherwise returns nil
func (fsm *MapInputSource) Uint64Slice(name string) ([]uint64, error) {
otherGenericValue, exists := fsm.valueMap[name]
if !exists {
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
if !exists {
return nil, nil
}
}

otherValue, isType := otherGenericValue.([]interface{})
if !isType {
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
}

var uint64Slice = make([]uint64, 0, len(otherValue))
for i, v := range otherValue {
var uint64Value uint64
switch v.(type) {
case int:
uint64Value = uint64(v.(int))
case int64:
uint64Value = uint64(v.(int64))
case uint64:
uint64Value = v.(uint64)
default:
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "int64", v)
}

uint64Slice = append(uint64Slice, uint64Value)
}

return uint64Slice, 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]
Expand Down
11 changes: 11 additions & 0 deletions flag.go
Expand Up @@ -332,6 +332,17 @@ func stringifyInt64SliceFlag(f *Int64SliceFlag) string {
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}

func stringifyUint64SliceFlag(f *Uint64SliceFlag) string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatUint(i, 10))
}
}

return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}

func stringifyFloat64SliceFlag(f *Float64SliceFlag) string {
var defaultVals []string

Expand Down

0 comments on commit 87ce263

Please sign in to comment.