From c7299d9da0add5fcabbe9e03726551dbb8106e9f Mon Sep 17 00:00:00 2001 From: Marek Counts Date: Fri, 15 Feb 2019 10:28:13 -0500 Subject: [PATCH] Moved flag and globalflag Moved all flag code from `staging/src/k8s.io/apiserver/pkg/util/[flag|globalflag]` to `component-base/cli/[flag|globalflag]` except for the term function because of unwanted dependencies. Kubernetes-commit: 7744f908306e5131be5a94815ac76a7cba6454f2 --- pkg/server/options/api_enablement.go | 6 +- pkg/server/options/api_enablement_test.go | 10 +- pkg/server/options/serving.go | 14 +- pkg/server/options/serving_test.go | 6 +- pkg/server/resourceconfig/helpers.go | 8 +- pkg/util/flag/ciphersuites_flag.go | 105 -------- pkg/util/flag/ciphersuites_flag_test.go | 114 --------- .../colon_separated_multimap_string_string.go | 102 -------- ...n_separated_multimap_string_string_test.go | 242 ------------------ pkg/util/flag/configuration_map.go | 53 ---- pkg/util/flag/flags.go | 54 ---- .../langle_separated_map_string_string.go | 82 ------ ...langle_separated_map_string_string_test.go | 159 ------------ pkg/util/flag/map_string_bool.go | 90 ------- pkg/util/flag/map_string_bool_test.go | 163 ------------ pkg/util/flag/map_string_string.go | 112 -------- pkg/util/flag/map_string_string_test.go | 181 ------------- pkg/util/flag/namedcertkey_flag.go | 113 -------- pkg/util/flag/namedcertkey_flag_test.go | 138 ---------- pkg/util/flag/noop.go | 41 --- pkg/util/flag/omitempty.go | 24 -- pkg/util/flag/sectioned.go | 95 ------- pkg/util/flag/string_flag.go | 56 ---- pkg/util/flag/tristate.go | 83 ------ pkg/util/globalflag/globalflags.go | 68 ----- pkg/util/globalflag/globalflags_test.go | 86 ------- pkg/util/term/term.go | 39 +++ 27 files changed, 61 insertions(+), 2183 deletions(-) delete mode 100644 pkg/util/flag/ciphersuites_flag.go delete mode 100644 pkg/util/flag/ciphersuites_flag_test.go delete mode 100644 pkg/util/flag/colon_separated_multimap_string_string.go delete mode 100644 pkg/util/flag/colon_separated_multimap_string_string_test.go delete mode 100644 pkg/util/flag/configuration_map.go delete mode 100644 pkg/util/flag/flags.go delete mode 100644 pkg/util/flag/langle_separated_map_string_string.go delete mode 100644 pkg/util/flag/langle_separated_map_string_string_test.go delete mode 100644 pkg/util/flag/map_string_bool.go delete mode 100644 pkg/util/flag/map_string_bool_test.go delete mode 100644 pkg/util/flag/map_string_string.go delete mode 100644 pkg/util/flag/map_string_string_test.go delete mode 100644 pkg/util/flag/namedcertkey_flag.go delete mode 100644 pkg/util/flag/namedcertkey_flag_test.go delete mode 100644 pkg/util/flag/noop.go delete mode 100644 pkg/util/flag/omitempty.go delete mode 100644 pkg/util/flag/sectioned.go delete mode 100644 pkg/util/flag/string_flag.go delete mode 100644 pkg/util/flag/tristate.go delete mode 100644 pkg/util/globalflag/globalflags.go delete mode 100644 pkg/util/globalflag/globalflags_test.go create mode 100644 pkg/util/term/term.go diff --git a/pkg/server/options/api_enablement.go b/pkg/server/options/api_enablement.go index 71eda2981..686be5aba 100644 --- a/pkg/server/options/api_enablement.go +++ b/pkg/server/options/api_enablement.go @@ -25,18 +25,18 @@ import ( "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/resourceconfig" serverstore "k8s.io/apiserver/pkg/server/storage" - utilflag "k8s.io/apiserver/pkg/util/flag" + cliflag "k8s.io/component-base/cli/flag" ) // APIEnablementOptions contains the options for which resources to turn on and off. // Given small aggregated API servers, this option isn't required for "normal" API servers type APIEnablementOptions struct { - RuntimeConfig utilflag.ConfigurationMap + RuntimeConfig cliflag.ConfigurationMap } func NewAPIEnablementOptions() *APIEnablementOptions { return &APIEnablementOptions{ - RuntimeConfig: make(utilflag.ConfigurationMap), + RuntimeConfig: make(cliflag.ConfigurationMap), } } diff --git a/pkg/server/options/api_enablement_test.go b/pkg/server/options/api_enablement_test.go index e08fcd2a1..fb146bf28 100644 --- a/pkg/server/options/api_enablement_test.go +++ b/pkg/server/options/api_enablement_test.go @@ -21,7 +21,7 @@ import ( "testing" utilerrors "k8s.io/apimachinery/pkg/util/errors" - utilflag "k8s.io/apiserver/pkg/util/flag" + cliflag "k8s.io/component-base/cli/flag" ) type fakeGroupRegisty struct{} @@ -42,28 +42,28 @@ func TestAPIEnablementOptionsValidate(t *testing.T) { { name: "test when invalid key with only api/all=false", testOptions: &APIEnablementOptions{ - RuntimeConfig: utilflag.ConfigurationMap{"api/all": "false"}, + RuntimeConfig: cliflag.ConfigurationMap{"api/all": "false"}, }, expectErr: "invalid key with only api/all=false", }, { name: "test when ConfigurationMap key is invalid", testOptions: &APIEnablementOptions{ - RuntimeConfig: utilflag.ConfigurationMap{"apiall": "false"}, + RuntimeConfig: cliflag.ConfigurationMap{"apiall": "false"}, }, expectErr: "runtime-config invalid key", }, { name: "test when unknown api groups", testOptions: &APIEnablementOptions{ - RuntimeConfig: utilflag.ConfigurationMap{"api/v1": "true"}, + RuntimeConfig: cliflag.ConfigurationMap{"api/v1": "true"}, }, expectErr: "unknown api groups", }, { name: "test when valid api groups", testOptions: &APIEnablementOptions{ - RuntimeConfig: utilflag.ConfigurationMap{"apiregistration.k8s.io/v1beta1": "true"}, + RuntimeConfig: cliflag.ConfigurationMap{"apiregistration.k8s.io/v1beta1": "true"}, }, }, } diff --git a/pkg/server/options/serving.go b/pkg/server/options/serving.go index 939e05741..605bf1a6d 100644 --- a/pkg/server/options/serving.go +++ b/pkg/server/options/serving.go @@ -29,8 +29,8 @@ import ( utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/server" - utilflag "k8s.io/apiserver/pkg/util/flag" certutil "k8s.io/client-go/util/cert" + cliflag "k8s.io/component-base/cli/flag" ) type SecureServingOptions struct { @@ -54,7 +54,7 @@ type SecureServingOptions struct { // ServerCert is the TLS cert info for serving secure traffic ServerCert GeneratableKeyCert // SNICertKeys are named CertKeys for serving secure traffic with SNI support. - SNICertKeys []utilflag.NamedCertKey + SNICertKeys []cliflag.NamedCertKey // CipherSuites is the list of allowed cipher suites for the server. // Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). CipherSuites []string @@ -165,18 +165,18 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile, "File containing the default x509 private key matching --tls-cert-file.") - tlsCipherPossibleValues := utilflag.TLSCipherPossibleValues() + tlsCipherPossibleValues := cliflag.TLSCipherPossibleValues() fs.StringSliceVar(&s.CipherSuites, "tls-cipher-suites", s.CipherSuites, "Comma-separated list of cipher suites for the server. "+ "If omitted, the default Go cipher suites will be use. "+ "Possible values: "+strings.Join(tlsCipherPossibleValues, ",")) - tlsPossibleVersions := utilflag.TLSPossibleVersions() + tlsPossibleVersions := cliflag.TLSPossibleVersions() fs.StringVar(&s.MinTLSVersion, "tls-min-version", s.MinTLSVersion, "Minimum TLS version supported. "+ "Possible values: "+strings.Join(tlsPossibleVersions, ", ")) - fs.Var(utilflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+ + fs.Var(cliflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+ "A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+ "domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+ "segments. If no domain patterns are provided, the names of the certificate are "+ @@ -234,7 +234,7 @@ func (s *SecureServingOptions) ApplyTo(config **server.SecureServingInfo) error } if len(s.CipherSuites) != 0 { - cipherSuites, err := utilflag.TLSCipherSuites(s.CipherSuites) + cipherSuites, err := cliflag.TLSCipherSuites(s.CipherSuites) if err != nil { return err } @@ -242,7 +242,7 @@ func (s *SecureServingOptions) ApplyTo(config **server.SecureServingInfo) error } var err error - c.MinTLSVersion, err = utilflag.TLSVersion(s.MinTLSVersion) + c.MinTLSVersion, err = cliflag.TLSVersion(s.MinTLSVersion) if err != nil { return err } diff --git a/pkg/server/options/serving_test.go b/pkg/server/options/serving_test.go index 73375bb70..1d6cecfe3 100644 --- a/pkg/server/options/serving_test.go +++ b/pkg/server/options/serving_test.go @@ -44,9 +44,9 @@ import ( "k8s.io/apimachinery/pkg/version" "k8s.io/apiserver/pkg/server" . "k8s.io/apiserver/pkg/server" - utilflag "k8s.io/apiserver/pkg/util/flag" "k8s.io/client-go/discovery" restclient "k8s.io/client-go/rest" + cliflag "k8s.io/component-base/cli/flag" ) func setUp(t *testing.T) Config { @@ -417,7 +417,7 @@ func TestServerRunWithSNI(t *testing.T) { caCerts := []*x509.Certificate{ca} // create SNI certs - var namedCertKeys []utilflag.NamedCertKey + var namedCertKeys []cliflag.NamedCertKey serverSig, err := certFileSignature(serverCertBundleFile, serverKeyFile) if err != nil { t.Fatalf("failed to get server cert signature: %v", err) @@ -434,7 +434,7 @@ func TestServerRunWithSNI(t *testing.T) { t.Fatalf("failed to create SNI cert %d: %v", j, err) } - namedCertKeys = append(namedCertKeys, utilflag.NamedCertKey{ + namedCertKeys = append(namedCertKeys, cliflag.NamedCertKey{ KeyFile: keyFile, CertFile: certBundleFile, Names: c.explicitNames, diff --git a/pkg/server/resourceconfig/helpers.go b/pkg/server/resourceconfig/helpers.go index fa5fcc768..09047cfe9 100644 --- a/pkg/server/resourceconfig/helpers.go +++ b/pkg/server/resourceconfig/helpers.go @@ -24,7 +24,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" serverstore "k8s.io/apiserver/pkg/server/storage" - utilflag "k8s.io/apiserver/pkg/util/flag" + cliflag "k8s.io/component-base/cli/flag" "k8s.io/klog" ) @@ -56,7 +56,7 @@ func MergeResourceEncodingConfigs( // not registered in group, then it will fail. func MergeAPIResourceConfigs( defaultAPIResourceConfig *serverstore.ResourceConfig, - resourceConfigOverrides utilflag.ConfigurationMap, + resourceConfigOverrides cliflag.ConfigurationMap, registry GroupVersionRegistry, ) (*serverstore.ResourceConfig, error) { resourceConfig := defaultAPIResourceConfig @@ -134,7 +134,7 @@ func MergeAPIResourceConfigs( return resourceConfig, nil } -func getRuntimeConfigValue(overrides utilflag.ConfigurationMap, apiKey string, defaultValue bool) (bool, error) { +func getRuntimeConfigValue(overrides cliflag.ConfigurationMap, apiKey string, defaultValue bool) (bool, error) { flagValue, ok := overrides[apiKey] if ok { if flagValue == "" { @@ -150,7 +150,7 @@ func getRuntimeConfigValue(overrides utilflag.ConfigurationMap, apiKey string, d } // ParseGroups takes in resourceConfig and returns parsed groups. -func ParseGroups(resourceConfig utilflag.ConfigurationMap) ([]string, error) { +func ParseGroups(resourceConfig cliflag.ConfigurationMap) ([]string, error) { groups := []string{} for key := range resourceConfig { if key == "api/all" { diff --git a/pkg/util/flag/ciphersuites_flag.go b/pkg/util/flag/ciphersuites_flag.go deleted file mode 100644 index 764747c25..000000000 --- a/pkg/util/flag/ciphersuites_flag.go +++ /dev/null @@ -1,105 +0,0 @@ -/* -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 ( - "crypto/tls" - "fmt" - - "k8s.io/apimachinery/pkg/util/sets" -) - -// ciphers maps strings into tls package cipher constants in -// https://golang.org/pkg/crypto/tls/#pkg-constants -var ciphers = map[string]uint16{ - "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, - "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, - "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, - "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, - "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, -} - -func TLSCipherPossibleValues() []string { - cipherKeys := sets.NewString() - for key := range ciphers { - cipherKeys.Insert(key) - } - return cipherKeys.List() -} - -func TLSCipherSuites(cipherNames []string) ([]uint16, error) { - if len(cipherNames) == 0 { - return nil, nil - } - ciphersIntSlice := make([]uint16, 0) - for _, cipher := range cipherNames { - intValue, ok := ciphers[cipher] - if !ok { - return nil, fmt.Errorf("Cipher suite %s not supported or doesn't exist", cipher) - } - ciphersIntSlice = append(ciphersIntSlice, intValue) - } - return ciphersIntSlice, nil -} - -var versions = map[string]uint16{ - "VersionTLS10": tls.VersionTLS10, - "VersionTLS11": tls.VersionTLS11, - "VersionTLS12": tls.VersionTLS12, -} - -func TLSPossibleVersions() []string { - versionsKeys := sets.NewString() - for key := range versions { - versionsKeys.Insert(key) - } - return versionsKeys.List() -} - -func TLSVersion(versionName string) (uint16, error) { - if len(versionName) == 0 { - return DefaultTLSVersion(), nil - } - if version, ok := versions[versionName]; ok { - return version, nil - } - return 0, fmt.Errorf("unknown tls version %q", versionName) -} - -func DefaultTLSVersion() uint16 { - // Can't use SSLv3 because of POODLE and BEAST - // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher - // Can't use TLSv1.1 because of RC4 cipher usage - return tls.VersionTLS12 -} diff --git a/pkg/util/flag/ciphersuites_flag_test.go b/pkg/util/flag/ciphersuites_flag_test.go deleted file mode 100644 index 4a8c4efeb..000000000 --- a/pkg/util/flag/ciphersuites_flag_test.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -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 ( - "crypto/tls" - "fmt" - "go/importer" - "reflect" - "strings" - "testing" -) - -func TestStrToUInt16(t *testing.T) { - tests := []struct { - flag []string - expected []uint16 - expected_error bool - }{ - { - // Happy case - flag: []string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"}, - expected: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, - expected_error: false, - }, - { - // One flag only - flag: []string{"TLS_RSA_WITH_RC4_128_SHA"}, - expected: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA}, - expected_error: false, - }, - { - // Empty flag - flag: []string{}, - expected: nil, - expected_error: false, - }, - { - // Duplicated flag - flag: []string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_RC4_128_SHA"}, - expected: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_RC4_128_SHA}, - expected_error: false, - }, - { - // Invalid flag - flag: []string{"foo"}, - expected: nil, - expected_error: true, - }, - } - - for i, test := range tests { - uIntFlags, err := TLSCipherSuites(test.flag) - if reflect.DeepEqual(uIntFlags, test.expected) == false { - t.Errorf("%d: expected %+v, got %+v", i, test.expected, uIntFlags) - } - if test.expected_error && err == nil { - t.Errorf("%d: expecting error, got %+v", i, err) - } - } -} - -func TestConstantMaps(t *testing.T) { - pkg, err := importer.Default().Import("crypto/tls") - if err != nil { - fmt.Printf("error: %s\n", err.Error()) - return - } - discoveredVersions := map[string]bool{} - discoveredCiphers := map[string]bool{} - for _, declName := range pkg.Scope().Names() { - if strings.HasPrefix(declName, "VersionTLS") { - discoveredVersions[declName] = true - } - if strings.HasPrefix(declName, "TLS_RSA_") || strings.HasPrefix(declName, "TLS_ECDHE_") { - discoveredCiphers[declName] = true - } - } - - for k := range discoveredCiphers { - if _, ok := ciphers[k]; !ok { - t.Errorf("discovered cipher tls.%s not in ciphers map", k) - } - } - for k := range ciphers { - if _, ok := discoveredCiphers[k]; !ok { - t.Errorf("ciphers map has %s not in tls package", k) - } - } - for k := range discoveredVersions { - if _, ok := versions[k]; !ok { - t.Errorf("discovered version tls.%s not in version map", k) - } - } - for k := range versions { - if _, ok := discoveredVersions[k]; !ok { - t.Errorf("versions map has %s not in tls package", k) - } - } -} diff --git a/pkg/util/flag/colon_separated_multimap_string_string.go b/pkg/util/flag/colon_separated_multimap_string_string.go deleted file mode 100644 index bd2cf5f87..000000000 --- a/pkg/util/flag/colon_separated_multimap_string_string.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -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"]}` -// The first call to Set will clear the map before adding entries; subsequent calls will simply append to the map. -// This makes it possible to override default values with a command-line option rather than appending to defaults, -// while still allowing the distribution of key-value pairs across multiple flag invocations. -// For example: `--flag "a:hello" --flag "b:again" --flag "b:beautiful" --flag "c:world"` results in `{"a": ["hello"], "b": ["again", "beautiful"], "c": ["world"]}` -type ColonSeparatedMultimapStringString struct { - Multimap *map[string][]string - initialized bool // set to true after the first Set call -} - -// NewColonSeparatedMultimapStringString takes a pointer to a map[string][]string and returns the -// ColonSeparatedMultimapStringString flag parsing shim for that map. -func NewColonSeparatedMultimapStringString(m *map[string][]string) *ColonSeparatedMultimapStringString { - return &ColonSeparatedMultimapStringString{Multimap: m} -} - -// Set implements github.com/spf13/pflag.Value -func (m *ColonSeparatedMultimapStringString) Set(value string) error { - if m.Multimap == nil { - return fmt.Errorf("no target (nil pointer to map[string][]string)") - } - if !m.initialized || *m.Multimap == nil { - // clear default values, or allocate if no existing map - *m.Multimap = make(map[string][]string) - m.initialized = true - } - 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.Multimap)[k] = append((*m.Multimap)[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.Multimap)) - for k, vs := range *m.Multimap { - 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" -} - -// Empty implements OmitEmpty -func (m *ColonSeparatedMultimapStringString) Empty() bool { - return len(*m.Multimap) == 0 -} diff --git a/pkg/util/flag/colon_separated_multimap_string_string_test.go b/pkg/util/flag/colon_separated_multimap_string_string_test.go deleted file mode 100644 index 9e77035c3..000000000 --- a/pkg/util/flag/colon_separated_multimap_string_string_test.go +++ /dev/null @@ -1,242 +0,0 @@ -/* -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) { - var nilMap map[string][]string - cases := []struct { - desc string - m *ColonSeparatedMultimapStringString - expect string - }{ - {"nil", NewColonSeparatedMultimapStringString(&nilMap), ""}, - {"empty", NewColonSeparatedMultimapStringString(&map[string][]string{}), ""}, - {"empty key", NewColonSeparatedMultimapStringString( - &map[string][]string{ - "": {"foo"}, - }), - ":foo"}, - {"one key", NewColonSeparatedMultimapStringString( - &map[string][]string{ - "one": {"foo"}, - }), - "one:foo"}, - {"two keys", NewColonSeparatedMultimapStringString( - &map[string][]string{ - "one": {"foo"}, - "two": {"bar"}, - }), - "one:foo,two:bar"}, - {"two keys, multiple items in one key", NewColonSeparatedMultimapStringString( - &map[string][]string{ - "one": {"foo", "baz"}, - "two": {"bar"}, - }), - "one:foo,one:baz,two:bar"}, - {"three keys, multiple items in one key", NewColonSeparatedMultimapStringString( - &map[string][]string{ - "a": {"hello"}, - "b": {"again", "beautiful"}, - "c": {"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) { - var nilMap map[string][]string - cases := []struct { - desc string - vals []string - start *ColonSeparatedMultimapStringString - expect *ColonSeparatedMultimapStringString - err string - }{ - // we initialize the map with a default key that should be cleared by Set - {"clears defaults", []string{""}, - NewColonSeparatedMultimapStringString(&map[string][]string{"default": {}}), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{}}, ""}, - // make sure we still allocate for "initialized" multimaps where Multimap was initially set to a nil map - {"allocates map if currently nil", []string{""}, - &ColonSeparatedMultimapStringString{initialized: true, Multimap: &nilMap}, - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{}, - }, ""}, - // for most cases, we just reuse nilMap, which should be allocated by Set, and is reset before each test case - {"empty", []string{""}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{}}, ""}, - {"empty key", []string{":foo"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "": {"foo"}, - }}, ""}, - {"one key", []string{"one:foo"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "one": {"foo"}, - }}, ""}, - {"two keys", []string{"one:foo,two:bar"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "one": {"foo"}, - "two": {"bar"}, - }}, ""}, - {"two keys with space", []string{"one:foo, two:bar"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "one": {"foo"}, - "two": {"bar"}, - }}, ""}, - {"two keys, multiple items in one key", []string{"one: foo, two:bar, one:baz"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "one": {"foo", "baz"}, - "two": {"bar"}, - }}, ""}, - {"three keys, multiple items in one key", []string{"a:hello,b:again,c:world,b:beautiful"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "a": {"hello"}, - "b": {"again", "beautiful"}, - "c": {"world"}, - }}, ""}, - {"three keys, multiple items in one key, multiple Set invocations", []string{"a:hello,b:again", "c:world", "b:beautiful"}, - NewColonSeparatedMultimapStringString(&nilMap), - &ColonSeparatedMultimapStringString{ - initialized: true, - Multimap: &map[string][]string{ - "a": {"hello"}, - "b": {"again", "beautiful"}, - "c": {"world"}, - }}, ""}, - {"missing value", []string{"a"}, - NewColonSeparatedMultimapStringString(&nilMap), - nil, - "malformed pair, expect string:string"}, - {"no target", []string{"a:foo"}, - NewColonSeparatedMultimapStringString(nil), - nil, - "no target (nil pointer to map[string][]string)"}, - } - - for _, c := range cases { - nilMap = nil - t.Run(c.desc, func(t *testing.T) { - var err error - for _, val := range c.vals { - err = c.start.Set(val) - if err != nil { - break - } - } - if c.err != "" { - if err == nil || 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, c.start) { - t.Fatalf("expect %#v but got %#v", c.expect, c.start) - } - }) - } -} - -func TestRoundTripColonSeparatedMultimapStringString(t *testing.T) { - cases := []struct { - desc string - vals []string - expect string - }{ - {"empty", []string{""}, ""}, - {"empty key", []string{":foo"}, ":foo"}, - {"one key", []string{"one:foo"}, "one:foo"}, - {"two keys", []string{"one:foo,two:bar"}, "one:foo,two:bar"}, - {"two keys, multiple items in one key", []string{"one:foo, two:bar, one:baz"}, "one:foo,one:baz,two:bar"}, - {"three keys, multiple items in one key", []string{"a:hello,b:again,c:world,b:beautiful"}, "a:hello,b:again,b:beautiful,c:world"}, - {"three keys, multiple items in one key, multiple Set invocations", []string{"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 := NewColonSeparatedMultimapStringString(&map[string][]string{}) - for _, val := range c.vals { - if err := m.Set(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) - } - }) - } -} - -func TestEmptyColonSeparatedMultimapStringString(t *testing.T) { - var nilMap map[string][]string - cases := []struct { - desc string - val *ColonSeparatedMultimapStringString - expect bool - }{ - {"nil", NewColonSeparatedMultimapStringString(&nilMap), true}, - {"empty", NewColonSeparatedMultimapStringString(&map[string][]string{}), true}, - {"populated", NewColonSeparatedMultimapStringString(&map[string][]string{"foo": {}}), false}, - } - for _, c := range cases { - t.Run(c.desc, func(t *testing.T) { - result := c.val.Empty() - if result != c.expect { - t.Fatalf("expect %t but got %t", c.expect, result) - } - }) - } -} diff --git a/pkg/util/flag/configuration_map.go b/pkg/util/flag/configuration_map.go deleted file mode 100644 index 911b05ec6..000000000 --- a/pkg/util/flag/configuration_map.go +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2014 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" -) - -type ConfigurationMap map[string]string - -func (m *ConfigurationMap) String() string { - pairs := []string{} - for k, v := range *m { - pairs = append(pairs, fmt.Sprintf("%s=%s", k, v)) - } - sort.Strings(pairs) - return strings.Join(pairs, ",") -} - -func (m *ConfigurationMap) Set(value string) error { - for _, s := range strings.Split(value, ",") { - if len(s) == 0 { - continue - } - arr := strings.SplitN(s, "=", 2) - if len(arr) == 2 { - (*m)[strings.TrimSpace(arr[0])] = strings.TrimSpace(arr[1]) - } else { - (*m)[strings.TrimSpace(arr[0])] = "" - } - } - return nil -} - -func (*ConfigurationMap) Type() string { - return "mapStringString" -} diff --git a/pkg/util/flag/flags.go b/pkg/util/flag/flags.go deleted file mode 100644 index d0fff8db2..000000000 --- a/pkg/util/flag/flags.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2014 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 ( - goflag "flag" - "strings" - - "github.com/spf13/pflag" - "k8s.io/klog" -) - -// WordSepNormalizeFunc changes all flags that contain "_" separators -func WordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - if strings.Contains(name, "_") { - return pflag.NormalizedName(strings.Replace(name, "_", "-", -1)) - } - return pflag.NormalizedName(name) -} - -// WarnWordSepNormalizeFunc changes and warns for flags that contain "_" separators -func WarnWordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - if strings.Contains(name, "_") { - nname := strings.Replace(name, "_", "-", -1) - klog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", name, nname) - - return pflag.NormalizedName(nname) - } - return pflag.NormalizedName(name) -} - -// InitFlags normalizes, parses, then logs the command line flags -func InitFlags() { - pflag.CommandLine.SetNormalizeFunc(WordSepNormalizeFunc) - pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) - pflag.Parse() - pflag.VisitAll(func(flag *pflag.Flag) { - klog.V(2).Infof("FLAG: --%s=%q", flag.Name, flag.Value) - }) -} diff --git a/pkg/util/flag/langle_separated_map_string_string.go b/pkg/util/flag/langle_separated_map_string_string.go deleted file mode 100644 index bf8dbfb9b..000000000 --- a/pkg/util/flag/langle_separated_map_string_string.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -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" -) - -// LangleSeparatedMapStringString can be set from the command line with the format `--flag "string 0 { - s = s + ":" + strings.Join(nkc.Names, ",") - } - return s -} - -func (nkc *NamedCertKey) Set(value string) error { - cs := strings.SplitN(value, ":", 2) - var keycert string - if len(cs) == 2 { - var names string - keycert, names = strings.TrimSpace(cs[0]), strings.TrimSpace(cs[1]) - if names == "" { - return errors.New("empty names list is not allowed") - } - nkc.Names = nil - for _, name := range strings.Split(names, ",") { - nkc.Names = append(nkc.Names, strings.TrimSpace(name)) - } - } else { - nkc.Names = nil - keycert = strings.TrimSpace(cs[0]) - } - cs = strings.Split(keycert, ",") - if len(cs) != 2 { - return errors.New("expected comma separated certificate and key file paths") - } - nkc.CertFile = strings.TrimSpace(cs[0]) - nkc.KeyFile = strings.TrimSpace(cs[1]) - return nil -} - -func (*NamedCertKey) Type() string { - return "namedCertKey" -} - -// NamedCertKeyArray is a flag value parsing NamedCertKeys, each passed with its own -// flag instance (in contrast to comma separated slices). -type NamedCertKeyArray struct { - value *[]NamedCertKey - changed bool -} - -var _ flag.Value = &NamedCertKey{} - -// NewNamedKeyCertArray creates a new NamedCertKeyArray with the internal value -// pointing to p. -func NewNamedCertKeyArray(p *[]NamedCertKey) *NamedCertKeyArray { - return &NamedCertKeyArray{ - value: p, - } -} - -func (a *NamedCertKeyArray) Set(val string) error { - nkc := NamedCertKey{} - err := nkc.Set(val) - if err != nil { - return err - } - if !a.changed { - *a.value = []NamedCertKey{nkc} - a.changed = true - } else { - *a.value = append(*a.value, nkc) - } - return nil -} - -func (a *NamedCertKeyArray) Type() string { - return "namedCertKey" -} - -func (a *NamedCertKeyArray) String() string { - nkcs := make([]string, 0, len(*a.value)) - for i := range *a.value { - nkcs = append(nkcs, (*a.value)[i].String()) - } - return "[" + strings.Join(nkcs, ";") + "]" -} diff --git a/pkg/util/flag/namedcertkey_flag_test.go b/pkg/util/flag/namedcertkey_flag_test.go deleted file mode 100644 index 542e221c9..000000000 --- a/pkg/util/flag/namedcertkey_flag_test.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -Copyright 2016 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" - "reflect" - "strings" - "testing" - - "github.com/spf13/pflag" -) - -func TestNamedCertKeyArrayFlag(t *testing.T) { - tests := []struct { - args []string - def []NamedCertKey - expected []NamedCertKey - parseError string - }{ - { - args: []string{}, - expected: nil, - }, - { - args: []string{"foo.crt,foo.key"}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - }}, - }, - { - args: []string{" foo.crt , foo.key "}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - }}, - }, - { - args: []string{"foo.crt,foo.key:abc"}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - Names: []string{"abc"}, - }}, - }, - { - args: []string{"foo.crt,foo.key: abc "}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - Names: []string{"abc"}, - }}, - }, - { - args: []string{"foo.crt,foo.key:"}, - parseError: "empty names list is not allowed", - }, - { - args: []string{""}, - parseError: "expected comma separated certificate and key file paths", - }, - { - args: []string{" "}, - parseError: "expected comma separated certificate and key file paths", - }, - { - args: []string{"a,b,c"}, - parseError: "expected comma separated certificate and key file paths", - }, - { - args: []string{"foo.crt,foo.key:abc,def,ghi"}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - Names: []string{"abc", "def", "ghi"}, - }}, - }, - { - args: []string{"foo.crt,foo.key:*.*.*"}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - Names: []string{"*.*.*"}, - }}, - }, - { - args: []string{"foo.crt,foo.key", "bar.crt,bar.key"}, - expected: []NamedCertKey{{ - KeyFile: "foo.key", - CertFile: "foo.crt", - }, { - KeyFile: "bar.key", - CertFile: "bar.crt", - }}, - }, - } - for i, test := range tests { - fs := pflag.NewFlagSet("testNamedCertKeyArray", pflag.ContinueOnError) - var nkcs []NamedCertKey - nkcs = append(nkcs, test.def...) - - fs.Var(NewNamedCertKeyArray(&nkcs), "tls-sni-cert-key", "usage") - - args := []string{} - for _, a := range test.args { - args = append(args, fmt.Sprintf("--tls-sni-cert-key=%s", a)) - } - - err := fs.Parse(args) - if test.parseError != "" { - if err == nil { - t.Errorf("%d: expected error %q, got nil", i, test.parseError) - } else if !strings.Contains(err.Error(), test.parseError) { - t.Errorf("%d: expected error %q, got %q", i, test.parseError, err) - } - } else if err != nil { - t.Errorf("%d: expected nil error, got %v", i, err) - } - if !reflect.DeepEqual(nkcs, test.expected) { - t.Errorf("%d: expected %+v, got %+v", i, test.expected, nkcs) - } - } -} diff --git a/pkg/util/flag/noop.go b/pkg/util/flag/noop.go deleted file mode 100644 index 03f7f14c0..000000000 --- a/pkg/util/flag/noop.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2018 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 ( - goflag "flag" - "github.com/spf13/pflag" -) - -// NoOp implements goflag.Value and plfag.Value, -// but has a noop Set implementation -type NoOp struct{} - -var _ goflag.Value = NoOp{} -var _ pflag.Value = NoOp{} - -func (NoOp) String() string { - return "" -} - -func (NoOp) Set(val string) error { - return nil -} - -func (NoOp) Type() string { - return "NoOp" -} diff --git a/pkg/util/flag/omitempty.go b/pkg/util/flag/omitempty.go deleted file mode 100644 index c354754ea..000000000 --- a/pkg/util/flag/omitempty.go +++ /dev/null @@ -1,24 +0,0 @@ -/* -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 - -// OmitEmpty is an interface for flags to report whether their underlying value -// is "empty." If a flag implements OmitEmpty and returns true for a call to Empty(), -// it is assumed that flag may be omitted from the command line. -type OmitEmpty interface { - Empty() bool -} diff --git a/pkg/util/flag/sectioned.go b/pkg/util/flag/sectioned.go deleted file mode 100644 index 52275aa6f..000000000 --- a/pkg/util/flag/sectioned.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 2018 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 ( - "bytes" - "fmt" - "io" - "strings" - - "github.com/docker/docker/pkg/term" - "github.com/spf13/pflag" -) - -// NamedFlagSets stores named flag sets in the order of calling FlagSet. -type NamedFlagSets struct { - // Order is an ordered list of flag set names. - Order []string - // FlagSets stores the flag sets by name. - FlagSets map[string]*pflag.FlagSet -} - -// FlagSet returns the flag set with the given name and adds it to the -// ordered name list if it is not in there yet. -func (nfs *NamedFlagSets) FlagSet(name string) *pflag.FlagSet { - if nfs.FlagSets == nil { - nfs.FlagSets = map[string]*pflag.FlagSet{} - } - if _, ok := nfs.FlagSets[name]; !ok { - nfs.FlagSets[name] = pflag.NewFlagSet(name, pflag.ExitOnError) - nfs.Order = append(nfs.Order, name) - } - return nfs.FlagSets[name] -} - -// PrintSections prints the given names flag sets in sections, with the maximal given column number. -// If cols is zero, lines are not wrapped. -func PrintSections(w io.Writer, fss NamedFlagSets, cols int) { - for _, name := range fss.Order { - fs := fss.FlagSets[name] - if !fs.HasFlags() { - continue - } - - wideFS := pflag.NewFlagSet("", pflag.ExitOnError) - wideFS.AddFlagSet(fs) - - var zzz string - if cols > 24 { - zzz = strings.Repeat("z", cols-24) - wideFS.Int(zzz, 0, strings.Repeat("z", cols-24)) - } - - var buf bytes.Buffer - fmt.Fprintf(&buf, "\n%s flags:\n\n%s", strings.ToUpper(name[:1])+name[1:], wideFS.FlagUsagesWrapped(cols)) - - if cols > 24 { - i := strings.Index(buf.String(), zzz) - lines := strings.Split(buf.String()[:i], "\n") - fmt.Fprint(w, strings.Join(lines[:len(lines)-1], "\n")) - fmt.Fprintln(w) - } else { - fmt.Fprint(w, buf.String()) - } - } -} - -// TerminalSize returns the current width and height of the user's terminal. If it isn't a terminal, -// nil is returned. On error, zero values are returned for width and height. -// Usually w must be the stdout of the process. Stderr won't work. -func TerminalSize(w io.Writer) (int, int, error) { - outFd, isTerminal := term.GetFdInfo(w) - if !isTerminal { - return 0, 0, fmt.Errorf("given writer is no terminal") - } - winsize, err := term.GetWinsize(outFd) - if err != nil { - return 0, 0, err - } - return int(winsize.Width), int(winsize.Height), nil -} diff --git a/pkg/util/flag/string_flag.go b/pkg/util/flag/string_flag.go deleted file mode 100644 index 331bdb66e..000000000 --- a/pkg/util/flag/string_flag.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2014 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 - -// StringFlag is a string flag compatible with flags and pflags that keeps track of whether it had a value supplied or not. -type StringFlag struct { - // If Set has been invoked this value is true - provided bool - // The exact value provided on the flag - value string -} - -func NewStringFlag(defaultVal string) StringFlag { - return StringFlag{value: defaultVal} -} - -func (f *StringFlag) Default(value string) { - f.value = value -} - -func (f StringFlag) String() string { - return f.value -} - -func (f StringFlag) Value() string { - return f.value -} - -func (f *StringFlag) Set(value string) error { - f.value = value - f.provided = true - - return nil -} - -func (f StringFlag) Provided() bool { - return f.provided -} - -func (f *StringFlag) Type() string { - return "string" -} diff --git a/pkg/util/flag/tristate.go b/pkg/util/flag/tristate.go deleted file mode 100644 index cf16376bf..000000000 --- a/pkg/util/flag/tristate.go +++ /dev/null @@ -1,83 +0,0 @@ -/* -Copyright 2014 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" - "strconv" -) - -// Tristate is a flag compatible with flags and pflags that -// keeps track of whether it had a value supplied or not. -type Tristate int - -const ( - Unset Tristate = iota // 0 - True - False -) - -func (f *Tristate) Default(value bool) { - *f = triFromBool(value) -} - -func (f Tristate) String() string { - b := boolFromTri(f) - return fmt.Sprintf("%t", b) -} - -func (f Tristate) Value() bool { - b := boolFromTri(f) - return b -} - -func (f *Tristate) Set(value string) error { - boolVal, err := strconv.ParseBool(value) - if err != nil { - return err - } - - *f = triFromBool(boolVal) - return nil -} - -func (f Tristate) Provided() bool { - if f != Unset { - return true - } - return false -} - -func (f *Tristate) Type() string { - return "tristate" -} - -func boolFromTri(t Tristate) bool { - if t == True { - return true - } else { - return false - } -} - -func triFromBool(b bool) Tristate { - if b { - return True - } else { - return False - } -} diff --git a/pkg/util/globalflag/globalflags.go b/pkg/util/globalflag/globalflags.go deleted file mode 100644 index 455153f68..000000000 --- a/pkg/util/globalflag/globalflags.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2018 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 globalflag - -import ( - "flag" - "fmt" - "strings" - - "github.com/spf13/pflag" - - "k8s.io/component-base/logs" -) - -// AddGlobalFlags explicitly registers flags that libraries (klog, verflag, etc.) register -// against the global flagsets from "flag" and "k8s.io/klog". -// We do this in order to prevent unwanted flags from leaking into the component's flagset. -func AddGlobalFlags(fs *pflag.FlagSet, name string) { - addGlogFlags(fs) - logs.AddFlags(fs) - - fs.BoolP("help", "h", false, fmt.Sprintf("help for %s", name)) -} - -// addGlogFlags explicitly registers flags that klog libraries(k8s.io/klog) register. -func addGlogFlags(fs *pflag.FlagSet) { - // lookup flags of klog libraries in global flag set and re-register the values with our flagset - Register(fs, "logtostderr") - Register(fs, "alsologtostderr") - Register(fs, "v") - Register(fs, "skip_headers") - Register(fs, "stderrthreshold") - Register(fs, "vmodule") - Register(fs, "log_backtrace_at") - Register(fs, "log_dir") - Register(fs, "log_file") -} - -// normalize replaces underscores with hyphens -// we should always use hyphens instead of underscores when registering component flags -func normalize(s string) string { - return strings.Replace(s, "_", "-", -1) -} - -// Register adds a flag to local that targets the Value associated with the Flag named globalName in flag.CommandLine. -func Register(local *pflag.FlagSet, globalName string) { - if f := flag.CommandLine.Lookup(globalName); f != nil { - pflagFlag := pflag.PFlagFromGoFlag(f) - pflagFlag.Name = normalize(pflagFlag.Name) - local.AddFlag(pflagFlag) - } else { - panic(fmt.Sprintf("failed to find flag in global flagset (flag): %s", globalName)) - } -} diff --git a/pkg/util/globalflag/globalflags_test.go b/pkg/util/globalflag/globalflags_test.go deleted file mode 100644 index 16475154a..000000000 --- a/pkg/util/globalflag/globalflags_test.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2018 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 globalflag - -import ( - "flag" - "reflect" - "sort" - "strings" - "testing" - - "github.com/spf13/pflag" - - apiserverflag "k8s.io/apiserver/pkg/util/flag" -) - -func TestAddGlobalFlags(t *testing.T) { - namedFlagSets := &apiserverflag.NamedFlagSets{} - nfs := namedFlagSets.FlagSet("global") - AddGlobalFlags(nfs, "test-cmd") - - actualFlag := []string{} - nfs.VisitAll(func(flag *pflag.Flag) { - actualFlag = append(actualFlag, flag.Name) - }) - - // Get all flags from flags.CommandLine, except flag `test.*`. - wantedFlag := []string{"help"} - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - pflag.VisitAll(func(flag *pflag.Flag) { - if !strings.Contains(flag.Name, "test.") { - wantedFlag = append(wantedFlag, normalize(flag.Name)) - } - }) - sort.Strings(wantedFlag) - - if !reflect.DeepEqual(wantedFlag, actualFlag) { - t.Errorf("[Default]: expected %+v, got %+v", wantedFlag, actualFlag) - } - - tests := []struct { - expectedFlag []string - matchExpected bool - }{ - { - // Happy case - expectedFlag: []string{"alsologtostderr", "help", "log-backtrace-at", "log-dir", "log-file", "log-flush-frequency", "logtostderr", "skip-headers", "stderrthreshold", "v", "vmodule"}, - matchExpected: false, - }, - { - // Missing flag - expectedFlag: []string{"logtostderr", "log-dir"}, - matchExpected: true, - }, - { - // Empty flag - expectedFlag: []string{}, - matchExpected: true, - }, - { - // Invalid flag - expectedFlag: []string{"foo"}, - matchExpected: true, - }, - } - - for i, test := range tests { - if reflect.DeepEqual(test.expectedFlag, actualFlag) == test.matchExpected { - t.Errorf("[%d]: expected %+v, got %+v", i, test.expectedFlag, actualFlag) - } - } -} diff --git a/pkg/util/term/term.go b/pkg/util/term/term.go new file mode 100644 index 000000000..123985bbf --- /dev/null +++ b/pkg/util/term/term.go @@ -0,0 +1,39 @@ +/* +Copyright 2019 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 term + +import ( + "fmt" + "io" + + "github.com/docker/docker/pkg/term" +) + +// TerminalSize returns the current width and height of the user's terminal. If it isn't a terminal, +// nil is returned. On error, zero values are returned for width and height. +// Usually w must be the stdout of the process. Stderr won't work. +func TerminalSize(w io.Writer) (int, int, error) { + outFd, isTerminal := term.GetFdInfo(w) + if !isTerminal { + return 0, 0, fmt.Errorf("given writer is no terminal") + } + winsize, err := term.GetWinsize(outFd) + if err != nil { + return 0, 0, err + } + return int(winsize.Width), int(winsize.Height), nil +}