-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package flagvalue | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
type simpleMapValue[K, V SimpleValue] struct { | ||
value *map[K]V | ||
changed bool | ||
} | ||
|
||
// SimpleMap returns a pflags.Value that sets the map at p with the default | ||
// val or the value(s) provided via a flag. | ||
func SimpleMap[K, V SimpleValue](val map[K]V, p *map[K]V) *simpleMapValue[K, V] { | ||
isv := new(simpleMapValue[K, V]) | ||
isv.value = p | ||
*isv.value = val | ||
return isv | ||
} | ||
|
||
func (m *simpleMapValue[K, V]) Set(s string) error { | ||
// Split the string, KEY=VALUE, into its parts | ||
parts := strings.SplitN(s, "=", 2) | ||
if len(parts) != 2 { | ||
return fmt.Errorf("expected key=value, got %q", s) | ||
} | ||
|
||
// Parse the key | ||
var key K | ||
_, err := fmt.Sscanf(parts[0], "%v", &key) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse key: %w", err) | ||
} | ||
|
||
// Parse the value | ||
var value V | ||
_, err = fmt.Sscanf(parts[1], "%v", &value) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse value: %w", err) | ||
} | ||
|
||
if !m.changed { | ||
*m.value = map[K]V{ | ||
key: value, | ||
} | ||
} else { | ||
(*m.value)[key] = value | ||
} | ||
|
||
m.changed = true | ||
return nil | ||
} | ||
|
||
func (m *simpleMapValue[K, V]) Type() string { | ||
return reflect.TypeOf(*m.value).String() | ||
} | ||
|
||
func (m *simpleMapValue[K, V]) String() string { | ||
out := make([]string, 0, len(*m.value)) | ||
for k, v := range *m.value { | ||
out = append(out, fmt.Sprintf("%v=%v", k, v)) | ||
} | ||
return "[" + strings.Join(out, ",") + "]" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package flagvalue_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/hcp/internal/pkg/flagvalue" | ||
"github.com/spf13/pflag" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func ExampleSimpleMap() { | ||
var headers map[string]string | ||
f := pflag.NewFlagSet("example", pflag.ContinueOnError) | ||
f.AddFlag(&pflag.Flag{ | ||
Name: "headers", | ||
Usage: "headers is a set of headers to send with the request. May be specified multiple times in the form of KEY=VALUE.", | ||
Value: flagvalue.SimpleMap(nil, &headers), | ||
}) | ||
|
||
// Make the request | ||
} | ||
|
||
func TestSimpleMap_StringToString(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
var m map[string]string | ||
f := pflag.NewFlagSet("test", pflag.ContinueOnError) | ||
f.AddFlag(&pflag.Flag{ | ||
Name: "values", | ||
Value: flagvalue.SimpleMap(map[string]string{"test": "value"}, &m), | ||
}) | ||
|
||
// Parse an empty set of args | ||
r.NoError(f.Parse([]string{})) | ||
|
||
// Expect the default | ||
r.Equal(map[string]string{"test": "value"}, m) | ||
|
||
// Parse with the flag set | ||
r.NoError(f.Parse([]string{"--values", "hello=world", "--values", "false=123"})) | ||
r.EqualValues(map[string]string{ | ||
"hello": "world", | ||
"false": "123", | ||
}, m) | ||
} | ||
|
||
func TestSimpleMap_StringToInt(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
var m map[string]int | ||
f := pflag.NewFlagSet("test", pflag.ContinueOnError) | ||
f.AddFlag(&pflag.Flag{ | ||
Name: "values", | ||
Value: flagvalue.SimpleMap(map[string]int{"test": 22}, &m), | ||
}) | ||
|
||
// Parse an empty set of args | ||
r.NoError(f.Parse([]string{})) | ||
|
||
// Expect the default | ||
r.Equal(map[string]int{"test": 22}, m) | ||
|
||
// Parse with the flag set | ||
r.NoError(f.Parse([]string{"--values", "hello=49", "--values", "123=123"})) | ||
r.EqualValues(map[string]int{ | ||
"hello": 49, | ||
"123": 123, | ||
}, m) | ||
} | ||
|
||
func TestSimpleMap_StringToBool(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
var m map[string]bool | ||
f := pflag.NewFlagSet("test", pflag.ContinueOnError) | ||
f.AddFlag(&pflag.Flag{ | ||
Name: "values", | ||
Value: flagvalue.SimpleMap(map[string]bool{"test": true}, &m), | ||
}) | ||
|
||
// Parse an empty set of args | ||
r.NoError(f.Parse([]string{})) | ||
|
||
// Expect the default | ||
r.Equal(map[string]bool{"test": true}, m) | ||
|
||
// Parse with the flag set | ||
r.NoError(f.Parse([]string{"--values", "hello=true", "--values", "test=false"})) | ||
r.EqualValues(map[string]bool{ | ||
"hello": true, | ||
"test": false, | ||
}, m) | ||
} | ||
|
||
func TestSimpleMap_IntToString(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
var m map[int]string | ||
f := pflag.NewFlagSet("test", pflag.ContinueOnError) | ||
f.AddFlag(&pflag.Flag{ | ||
Name: "values", | ||
Value: flagvalue.SimpleMap(map[int]string{49: "test"}, &m), | ||
}) | ||
|
||
// Parse an empty set of args | ||
r.NoError(f.Parse([]string{})) | ||
|
||
// Expect the default | ||
r.Equal(map[int]string{49: "test"}, m) | ||
|
||
// Parse with the flag set | ||
r.NoError(f.Parse([]string{"--values", "49=other", "--values", "123=123"})) | ||
r.EqualValues(map[int]string{ | ||
49: "other", | ||
123: "123", | ||
}, m) | ||
} | ||
|
||
func TestSimpleMap(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
var stringToString map[string]string | ||
var stringToInt map[string]int | ||
var i8Tof64 map[int8]float64 | ||
|
||
r.Equal("map[string]string", flagvalue.SimpleMap(nil, &stringToString).Type()) | ||
r.Equal("map[string]int", flagvalue.SimpleMap(nil, &stringToInt).Type()) | ||
r.Equal("map[int8]float64", flagvalue.SimpleMap(nil, &i8Tof64).Type()) | ||
} |