Lift embedded structure out of ManifestURLHeader field
Kubernetes-commit: 7cb21746c09cd7dd8e2beaaa03f17ba41563a318
This commit is contained in:
parent
703a17eb2a
commit
ce50eca6d7
|
|
@ -9,6 +9,7 @@ load(
|
|||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"colon_separated_multimap_string_string_test.go",
|
||||
"map_string_bool_test.go",
|
||||
"namedcertkey_flag_test.go",
|
||||
],
|
||||
|
|
@ -24,6 +25,7 @@ go_test(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"colon_separated_multimap_string_string.go",
|
||||
"configuration_map.go",
|
||||
"flags.go",
|
||||
"map_string_bool.go",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package flag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ColonSeparatedMultimapStringString supports setting a map[string][]string from an encoding
|
||||
// that separates keys from values with ':' and separates key-value pairs with ','.
|
||||
// A key can be repeated multiple times, in which case the values are appended to a
|
||||
// slice of strings associated with that key. Items in the list associated with a given
|
||||
// key will appear in the order provided.
|
||||
// For example: `a:hello,b:again,c:world,b:beautiful` results in `{"a": ["hello"], "b": ["again", "beautiful"], "c": ["world"]}`
|
||||
type ColonSeparatedMultimapStringString map[string][]string
|
||||
|
||||
// Set implements github.com/spf13/pflag.Value
|
||||
func (m ColonSeparatedMultimapStringString) Set(value string) error {
|
||||
// clear old values
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
for _, pair := range strings.Split(value, ",") {
|
||||
if len(pair) == 0 {
|
||||
continue
|
||||
}
|
||||
kv := strings.SplitN(pair, ":", 2)
|
||||
if len(kv) != 2 {
|
||||
return fmt.Errorf("malformed pair, expect string:string")
|
||||
}
|
||||
k := strings.TrimSpace(kv[0])
|
||||
v := strings.TrimSpace(kv[1])
|
||||
m[k] = append(m[k], v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements github.com/spf13/pflag.Value
|
||||
func (m ColonSeparatedMultimapStringString) String() string {
|
||||
type kv struct {
|
||||
k string
|
||||
v string
|
||||
}
|
||||
kvs := make([]kv, 0, len(m))
|
||||
for k, vs := range m {
|
||||
for i := range vs {
|
||||
kvs = append(kvs, kv{k: k, v: vs[i]})
|
||||
}
|
||||
}
|
||||
// stable sort by keys, order of values should be preserved
|
||||
sort.SliceStable(kvs, func(i, j int) bool {
|
||||
return kvs[i].k < kvs[j].k
|
||||
})
|
||||
pairs := make([]string, 0, len(kvs))
|
||||
for i := range kvs {
|
||||
pairs = append(pairs, fmt.Sprintf("%s:%s", kvs[i].k, kvs[i].v))
|
||||
}
|
||||
return strings.Join(pairs, ",")
|
||||
}
|
||||
|
||||
// Type implements github.com/spf13/pflag.Value
|
||||
func (m ColonSeparatedMultimapStringString) Type() string {
|
||||
return "colonSeparatedMultimapStringString"
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package flag
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringColonSeparatedMultimapStringString(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
m ColonSeparatedMultimapStringString
|
||||
expect string
|
||||
}{
|
||||
{"empty", ColonSeparatedMultimapStringString{}, ""},
|
||||
{"empty key", ColonSeparatedMultimapStringString{"": []string{"foo"}}, ":foo"},
|
||||
{"one key", ColonSeparatedMultimapStringString{"one": []string{"foo"}}, "one:foo"},
|
||||
{"two keys", ColonSeparatedMultimapStringString{"one": []string{"foo"}, "two": []string{"bar"}}, "one:foo,two:bar"},
|
||||
{"two keys, multiple items in one key", ColonSeparatedMultimapStringString{"one": []string{"foo", "baz"}, "two": []string{"bar"}}, "one:foo,one:baz,two:bar"},
|
||||
{"three keys, multiple items in one key", ColonSeparatedMultimapStringString{"a": []string{"hello"}, "b": []string{"again", "beautiful"}, "c": []string{"world"}}, "a:hello,b:again,b:beautiful,c:world"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
str := c.m.String()
|
||||
if c.expect != str {
|
||||
t.Fatalf("expect %q but got %q", c.expect, str)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetColonSeparatedMultimapStringString(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
val string
|
||||
expect ColonSeparatedMultimapStringString
|
||||
err string
|
||||
}{
|
||||
{"empty", "", ColonSeparatedMultimapStringString{}, ""},
|
||||
{"empty key", ":foo", ColonSeparatedMultimapStringString{
|
||||
"": []string{"foo"},
|
||||
}, ""},
|
||||
{"one key", "one:foo", ColonSeparatedMultimapStringString{
|
||||
"one": []string{"foo"}}, ""},
|
||||
{"two keys", "one:foo,two:bar", ColonSeparatedMultimapStringString{
|
||||
"one": []string{"foo"},
|
||||
"two": []string{"bar"},
|
||||
}, ""},
|
||||
{"two keys with space", "one:foo, two:bar", ColonSeparatedMultimapStringString{
|
||||
"one": []string{"foo"},
|
||||
"two": []string{"bar"},
|
||||
}, ""},
|
||||
{"two keys, multiple items in one key", "one: foo, two:bar, one:baz", ColonSeparatedMultimapStringString{
|
||||
"one": []string{"foo", "baz"},
|
||||
"two": []string{"bar"},
|
||||
}, ""},
|
||||
{"three keys, multiple items in one key", "a:hello,b:again,c:world,b:beautiful", ColonSeparatedMultimapStringString{
|
||||
"a": []string{"hello"},
|
||||
"b": []string{"again", "beautiful"},
|
||||
"c": []string{"world"},
|
||||
}, ""},
|
||||
{"missing value", "one", ColonSeparatedMultimapStringString{}, "malformed pair, expect string:string"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
// we initialize the map with a default key that should be cleared by Set (no test cases specify "default")
|
||||
m := ColonSeparatedMultimapStringString{"default": []string{}}
|
||||
err := m.Set(c.val)
|
||||
if c.err != "" {
|
||||
if err.Error() != c.err {
|
||||
t.Fatalf("expect error %s but got %v", c.err, err)
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(c.expect, m) {
|
||||
t.Fatalf("expect %#v but got %#v", c.expect, m)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTripColonSeparatedMultimapStringString(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
val string
|
||||
expect string
|
||||
}{
|
||||
{"empty", "", ""},
|
||||
{"empty key", ":foo", ":foo"},
|
||||
{"one key", "one:foo", "one:foo"},
|
||||
{"two keys", "one:foo,two:bar", "one:foo,two:bar"},
|
||||
{"two keys, multiple items in one key", "one:foo, two:bar, one:baz", "one:foo,one:baz,two:bar"},
|
||||
{"three keys, multiple items in one key", "a:hello,b:again,c:world,b:beautiful", "a:hello,b:again,b:beautiful,c:world"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
m := ColonSeparatedMultimapStringString{}
|
||||
if err := m.Set(c.val); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
str := m.String()
|
||||
if c.expect != str {
|
||||
t.Fatalf("expect %q but got %q", c.expect, str)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue