vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

54
vendor/k8s.io/kubernetes/pkg/kubectl/util/BUILD generated vendored Normal file
View File

@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"umask.go",
"util.go",
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"umask_windows.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/kubectl/util",
visibility = ["//build/visible_to:pkg_kubectl_util_CONSUMERS"],
deps = [
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/kubectl/util/crlf:all-srcs",
"//pkg/kubectl/util/hash:all-srcs",
"//pkg/kubectl/util/i18n:all-srcs",
"//pkg/kubectl/util/logs:all-srcs",
"//pkg/kubectl/util/slice:all-srcs",
"//pkg/kubectl/util/term:all-srcs",
],
tags = ["automanaged"],
visibility = ["//build/visible_to:pkg_kubectl_util_CONSUMERS"],
)
go_test(
name = "go_default_test",
srcs = ["util_test.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util",
library = ":go_default_library",
)

25
vendor/k8s.io/kubernetes/pkg/kubectl/util/crlf/BUILD generated vendored Normal file
View File

@ -0,0 +1,25 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["crlf.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/crlf",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

57
vendor/k8s.io/kubernetes/pkg/kubectl/util/crlf/crlf.go generated vendored Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright 2015 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 crlf
import (
"bytes"
"io"
)
type crlfWriter struct {
io.Writer
}
// NewCRLFWriter implements a CR/LF line ending writer used for normalizing
// text for Windows platforms.
func NewCRLFWriter(w io.Writer) io.Writer {
return crlfWriter{w}
}
func (w crlfWriter) Write(b []byte) (n int, err error) {
for i, written := 0, 0; ; {
next := bytes.Index(b[i:], []byte("\n"))
if next == -1 {
n, err := w.Writer.Write(b[i:])
return written + n, err
}
next = next + i
n, err := w.Writer.Write(b[i:next])
if err != nil {
return written + n, err
}
written += n
n, err = w.Writer.Write([]byte("\r\n"))
if err != nil {
if n > 1 {
n = 1
}
return written + n, err
}
written += 1
i = next + 1
}
}

35
vendor/k8s.io/kubernetes/pkg/kubectl/util/hash/BUILD generated vendored Normal file
View File

@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["hash_test.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/hash",
library = ":go_default_library",
deps = ["//vendor/k8s.io/api/core/v1:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["hash.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/hash",
deps = ["//vendor/k8s.io/api/core/v1:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

110
vendor/k8s.io/kubernetes/pkg/kubectl/util/hash/hash.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
/*
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 hash
import (
"crypto/sha256"
"encoding/json"
"fmt"
"k8s.io/api/core/v1"
)
// ConfigMapHash returns a hash of the ConfigMap.
// The Data, Kind, and Name are taken into account.
func ConfigMapHash(cm *v1.ConfigMap) (string, error) {
encoded, err := encodeConfigMap(cm)
if err != nil {
return "", err
}
h, err := encodeHash(hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// SecretHash returns a hash of the Secret.
// The Data, Kind, Name, and Type are taken into account.
func SecretHash(sec *v1.Secret) (string, error) {
encoded, err := encodeSecret(sec)
if err != nil {
return "", err
}
h, err := encodeHash(hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// encodeConfigMap encodes a ConfigMap.
// Data, Kind, and Name are taken into account.
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data})
if err != nil {
return "", err
}
return string(data), nil
}
// encodeSecret encodes a Secret.
// Data, Kind, Name, and Type are taken into account.
func encodeSecret(sec *v1.Secret) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
if err != nil {
return "", err
}
return string(data), nil
}
// encodeHash extracts the first 40 bits of the hash from the hex string
// (1 hex char represents 4 bits), and then maps vowels and vowel-like hex
// characters to consonants to prevent bad words from being formed (the theory
// is that no vowels makes it really hard to make bad words). Since the string
// is hex, the only vowels it can contain are 'a' and 'e'.
// We picked some arbitrary consonants to map to from the same character set as GenerateName.
// See: https://github.com/kubernetes/apimachinery/blob/dc1f89aff9a7509782bde3b68824c8043a3e58cc/pkg/util/rand/rand.go#L75
// If the hex string contains fewer than ten characters, returns an error.
func encodeHash(hex string) (string, error) {
if len(hex) < 10 {
return "", fmt.Errorf("the hex string must contain at least 10 characters")
}
enc := []rune(hex[:10])
for i := range enc {
switch enc[i] {
case '0':
enc[i] = 'g'
case '1':
enc[i] = 'h'
case '3':
enc[i] = 'k'
case 'a':
enc[i] = 'm'
case 'e':
enc[i] = 't'
}
}
return string(enc), nil
}
// hash hashes `data` with sha256 and returns the hex string
func hash(data string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
}

View File

@ -0,0 +1,178 @@
/*
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 hash
import (
"reflect"
"strings"
"testing"
"k8s.io/api/core/v1"
)
func TestConfigMapHash(t *testing.T) {
cases := []struct {
desc string
cm *v1.ConfigMap
hash string
err string
}{
// empty map
{"empty data", &v1.ConfigMap{Data: map[string]string{}}, "42745tchd9", ""},
// one key
{"one key", &v1.ConfigMap{Data: map[string]string{"one": ""}}, "9g67k2htb6", ""},
// three keys (tests sorting order)
{"three keys", &v1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}}, "f5h7t85m9b", ""},
}
for _, c := range cases {
h, err := ConfigMapHash(c.cm)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestSecretHash(t *testing.T) {
cases := []struct {
desc string
secret *v1.Secret
hash string
err string
}{
// empty map
{"empty data", &v1.Secret{Type: "my-type", Data: map[string][]byte{}}, "t75bgf6ctb", ""},
// one key
{"one key", &v1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, "74bd68bm66", ""},
// three keys (tests sorting order)
{"three keys", &v1.Secret{Type: "my-type", Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, "dgcb6h9tmk", ""},
}
for _, c := range cases {
h, err := SecretHash(c.secret)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestEncodeConfigMap(t *testing.T) {
cases := []struct {
desc string
cm *v1.ConfigMap
expect string
err string
}{
// empty map
{"empty data", &v1.ConfigMap{Data: map[string]string{}}, `{"data":{},"kind":"ConfigMap","name":""}`, ""},
// one key
{"one key", &v1.ConfigMap{Data: map[string]string{"one": ""}}, `{"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
// three keys (tests sorting order)
{"three keys", &v1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}}, `{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}`, ""},
}
for _, c := range cases {
s, err := encodeConfigMap(c.cm)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if s != c.expect {
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.cm)
}
}
}
func TestEncodeSecret(t *testing.T) {
cases := []struct {
desc string
secret *v1.Secret
expect string
err string
}{
// empty map
{"empty data", &v1.Secret{Type: "my-type", Data: map[string][]byte{}}, `{"data":{},"kind":"Secret","name":"","type":"my-type"}`, ""},
// one key
{"one key", &v1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
{"three keys", &v1.Secret{Type: "my-type", Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, `{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}`, ""},
}
for _, c := range cases {
s, err := encodeSecret(c.secret)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if s != c.expect {
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.secret)
}
}
}
func TestHash(t *testing.T) {
// hash the empty string to be sure that sha256 is being used
expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
sum := hash("")
if expect != sum {
t.Errorf("expected hash %q but got %q", expect, sum)
}
}
// warn devs who change types that they might have to update a hash function
// not perfect, as it only checks the number of top-level fields
func TestTypeStability(t *testing.T) {
errfmt := `case %q, expected %d fields but got %d
Depending on the field(s) you added, you may need to modify the hash function for this type.
To guide you: the hash function targets fields that comprise the contents of objects,
not their metadata (e.g. the Data of a ConfigMap, but nothing in ObjectMeta).
`
cases := []struct {
typeName string
obj interface{}
expect int
}{
{"ConfigMap", v1.ConfigMap{}, 3},
{"Secret", v1.Secret{}, 5},
}
for _, c := range cases {
val := reflect.ValueOf(c.obj)
if num := val.NumField(); c.expect != num {
t.Errorf(errfmt, c.typeName, c.expect, num)
}
}
}
// SkipRest returns true if there was a non-nil error or if we expected an error that didn't happen,
// and logs the appropriate error on the test object.
// The return value indicates whether we should skip the rest of the test case due to the error result.
func SkipRest(t *testing.T, desc string, err error, contains string) bool {
if err != nil {
if len(contains) == 0 {
t.Errorf("case %q, expect nil error but got %q", desc, err.Error())
} else if !strings.Contains(err.Error(), contains) {
t.Errorf("case %q, expect error to contain %q but got %q", desc, contains, err.Error())
}
return true
} else if len(contains) > 0 {
t.Errorf("case %q, expect error to contain %q but got nil error", desc, contains)
return true
}
return false
}

38
vendor/k8s.io/kubernetes/pkg/kubectl/util/i18n/BUILD generated vendored Normal file
View File

@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["i18n.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/i18n",
deps = [
"//pkg/generated:go_default_library",
"//vendor/github.com/chai2010/gettext-go/gettext:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["i18n_test.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/i18n",
library = ":go_default_library",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

139
vendor/k8s.io/kubernetes/pkg/kubectl/util/i18n/i18n.go generated vendored Normal file
View File

@ -0,0 +1,139 @@
/*
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 i18n
import (
"archive/zip"
"bytes"
"errors"
"fmt"
"os"
"strings"
"k8s.io/kubernetes/pkg/generated"
"github.com/chai2010/gettext-go/gettext"
"github.com/golang/glog"
)
var knownTranslations = map[string][]string{
"kubectl": {
"default",
"en_US",
"fr_FR",
"zh_CN",
"ja_JP",
"zh_TW",
"it_IT",
"de_DE",
},
// only used for unit tests.
"test": {
"default",
"en_US",
},
}
func loadSystemLanguage() string {
langStr := os.Getenv("LANG")
if langStr == "" {
glog.V(3).Infof("Couldn't find the LANG environment variable, defaulting to en_US")
return "default"
}
pieces := strings.Split(langStr, ".")
if len(pieces) != 2 {
glog.V(3).Infof("Unexpected system language (%s), defaulting to en_US", langStr)
return "default"
}
return pieces[0]
}
func findLanguage(root string, getLanguageFn func() string) string {
langStr := getLanguageFn()
translations := knownTranslations[root]
if translations != nil {
for ix := range translations {
if translations[ix] == langStr {
return langStr
}
}
}
glog.V(3).Infof("Couldn't find translations for %s, using default", langStr)
return "default"
}
// LoadTranslations loads translation files. getLanguageFn should return a language
// string (e.g. 'en-US'). If getLanguageFn is nil, then the loadSystemLanguage function
// is used, which uses the 'LANG' environment variable.
func LoadTranslations(root string, getLanguageFn func() string) error {
if getLanguageFn == nil {
getLanguageFn = loadSystemLanguage
}
langStr := findLanguage(root, getLanguageFn)
translationFiles := []string{
fmt.Sprintf("%s/%s/LC_MESSAGES/k8s.po", root, langStr),
fmt.Sprintf("%s/%s/LC_MESSAGES/k8s.mo", root, langStr),
}
glog.V(3).Infof("Setting language to %s", langStr)
// TODO: list the directory and load all files.
buf := new(bytes.Buffer)
w := zip.NewWriter(buf)
// Make sure to check the error on Close.
for _, file := range translationFiles {
filename := "translations/" + file
f, err := w.Create(file)
if err != nil {
return err
}
data, err := generated.Asset(filename)
if err != nil {
return err
}
if _, err := f.Write(data); err != nil {
return nil
}
}
if err := w.Close(); err != nil {
return err
}
gettext.BindTextdomain("k8s", root+".zip", buf.Bytes())
gettext.Textdomain("k8s")
gettext.SetLocale(langStr)
return nil
}
// T translates a string, possibly substituting arguments into it along
// the way. If len(args) is > 0, args1 is assumed to be the plural value
// and plural translation is used.
func T(defaultValue string, args ...int) string {
if len(args) == 0 {
return gettext.PGettext("", defaultValue)
}
return fmt.Sprintf(gettext.PNGettext("", defaultValue, defaultValue+".plural", args[0]),
args[0])
}
// Errorf produces an error with a translated error string.
// Substitution is performed via the `T` function above, following
// the same rules.
func Errorf(defaultValue string, args ...int) error {
return errors.New(T(defaultValue, args...))
}

View File

@ -0,0 +1,64 @@
/*
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 i18n
import (
"os"
"testing"
)
func TestTranslation(t *testing.T) {
err := LoadTranslations("test", func() string { return "default" })
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
result := T("test_string")
if result != "foo" {
t.Errorf("expected: %s, saw: %s", "foo", result)
}
}
func TestTranslationPlural(t *testing.T) {
err := LoadTranslations("test", func() string { return "default" })
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
result := T("test_plural", 3)
if result != "there were 3 items" {
t.Errorf("expected: %s, saw: %s", "there were 3 items", result)
}
result = T("test_plural", 1)
if result != "there was 1 item" {
t.Errorf("expected: %s, saw: %s", "there was 1 item", result)
}
}
func TestTranslationEnUSEnv(t *testing.T) {
os.Setenv("LANG", "en_US.UTF-8")
err := LoadTranslations("test", nil)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
result := T("test_string")
if result != "baz" {
t.Errorf("expected: %s, saw: %s", "baz", result)
}
}

30
vendor/k8s.io/kubernetes/pkg/kubectl/util/logs/BUILD generated vendored Normal file
View File

@ -0,0 +1,30 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["logs.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/logs",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

61
vendor/k8s.io/kubernetes/pkg/kubectl/util/logs/logs.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
/*
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 logs
import (
"flag"
"log"
"time"
"github.com/golang/glog"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
)
var logFlushFreq = pflag.Duration("log-flush-frequency", 5*time.Second, "Maximum number of seconds between log flushes")
// TODO(thockin): This is temporary until we agree on log dirs and put those into each cmd.
func init() {
flag.Set("logtostderr", "true")
}
// GlogWriter serves as a bridge between the standard log package and the glog package.
type GlogWriter struct{}
// Write implements the io.Writer interface.
func (writer GlogWriter) Write(data []byte) (n int, err error) {
glog.Info(string(data))
return len(data), nil
}
// InitLogs initializes logs the way we want for kubernetes.
func InitLogs() {
log.SetOutput(GlogWriter{})
log.SetFlags(0)
// The default glog flush interval is 30 seconds, which is frighteningly long.
go wait.Until(glog.Flush, *logFlushFreq, wait.NeverStop)
}
// FlushLogs flushes logs immediately.
func FlushLogs() {
glog.Flush()
}
// NewLogger creates a new log.Logger which sends logs to glog.Info.
func NewLogger(prefix string) *log.Logger {
return log.New(GlogWriter{}, prefix, 0)
}

33
vendor/k8s.io/kubernetes/pkg/kubectl/util/slice/BUILD generated vendored Normal file
View File

@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["slice.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/slice",
)
go_test(
name = "go_default_test",
srcs = ["slice_test.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/slice",
library = ":go_default_library",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,32 @@
/*
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 slice
import (
"sort"
)
// Int64Slice attaches the methods of Interface to []int64,
// sorting in increasing order.
type Int64Slice []int64
func (p Int64Slice) Len() int { return len(p) }
func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sorts []int64 in increasing order
func SortInts64(a []int64) { sort.Sort(Int64Slice(a)) }

View File

@ -0,0 +1,31 @@
/*
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 slice
import (
"reflect"
"testing"
)
func TestSortInts64(t *testing.T) {
src := []int64{10, 1, 2, 3, 4, 5, 6}
expected := []int64{1, 2, 3, 4, 5, 6, 10}
SortInts64(src)
if !reflect.DeepEqual(src, expected) {
t.Errorf("func Ints64 didnt sort correctly, %v !- %v", src, expected)
}
}

51
vendor/k8s.io/kubernetes/pkg/kubectl/util/term/BUILD generated vendored Normal file
View File

@ -0,0 +1,51 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"resize.go",
"resizeevents.go",
"term.go",
"term_writer.go",
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"resizeevents_windows.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/kubectl/util/term",
deps = [
"//pkg/util/interrupt:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/github.com/mitchellh/go-wordwrap:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["term_writer_test.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/term",
library = ":go_default_library",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,132 @@
/*
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 term
import (
"fmt"
"github.com/docker/docker/pkg/term"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/remotecommand"
)
// GetSize returns the current size of the user's terminal. If it isn't a terminal,
// nil is returned.
func (t TTY) GetSize() *remotecommand.TerminalSize {
outFd, isTerminal := term.GetFdInfo(t.Out)
if !isTerminal {
return nil
}
return GetSize(outFd)
}
// GetSize returns the current size of the terminal associated with fd.
func GetSize(fd uintptr) *remotecommand.TerminalSize {
winsize, err := term.GetWinsize(fd)
if err != nil {
runtime.HandleError(fmt.Errorf("unable to get terminal size: %v", err))
return nil
}
return &remotecommand.TerminalSize{Width: winsize.Width, Height: winsize.Height}
}
// MonitorSize monitors the terminal's size. It returns a TerminalSizeQueue primed with
// initialSizes, or nil if there's no TTY present.
func (t *TTY) MonitorSize(initialSizes ...*remotecommand.TerminalSize) remotecommand.TerminalSizeQueue {
outFd, isTerminal := term.GetFdInfo(t.Out)
if !isTerminal {
return nil
}
t.sizeQueue = &sizeQueue{
t: *t,
// make it buffered so we can send the initial terminal sizes without blocking, prior to starting
// the streaming below
resizeChan: make(chan remotecommand.TerminalSize, len(initialSizes)),
stopResizing: make(chan struct{}),
}
t.sizeQueue.monitorSize(outFd, initialSizes...)
return t.sizeQueue
}
// sizeQueue implements remotecommand.TerminalSizeQueue
type sizeQueue struct {
t TTY
// resizeChan receives a Size each time the user's terminal is resized.
resizeChan chan remotecommand.TerminalSize
stopResizing chan struct{}
}
// make sure sizeQueue implements the resize.TerminalSizeQueue interface
var _ remotecommand.TerminalSizeQueue = &sizeQueue{}
// monitorSize primes resizeChan with initialSizes and then monitors for resize events. With each
// new event, it sends the current terminal size to resizeChan.
func (s *sizeQueue) monitorSize(outFd uintptr, initialSizes ...*remotecommand.TerminalSize) {
// send the initial sizes
for i := range initialSizes {
if initialSizes[i] != nil {
s.resizeChan <- *initialSizes[i]
}
}
resizeEvents := make(chan remotecommand.TerminalSize, 1)
monitorResizeEvents(outFd, resizeEvents, s.stopResizing)
// listen for resize events in the background
go func() {
defer runtime.HandleCrash()
for {
select {
case size, ok := <-resizeEvents:
if !ok {
return
}
select {
// try to send the size to resizeChan, but don't block
case s.resizeChan <- size:
// send successful
default:
// unable to send / no-op
}
case <-s.stopResizing:
return
}
}
}()
}
// Next returns the new terminal size after the terminal has been resized. It returns nil when
// monitoring has been stopped.
func (s *sizeQueue) Next() *remotecommand.TerminalSize {
size, ok := <-s.resizeChan
if !ok {
return nil
}
return &size
}
// stop stops the background goroutine that is monitoring for terminal resizes.
func (s *sizeQueue) stop() {
close(s.stopResizing)
}

View File

@ -0,0 +1,61 @@
// +build !windows
/*
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 term
import (
"os"
"os/signal"
"golang.org/x/sys/unix"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/remotecommand"
)
// monitorResizeEvents spawns a goroutine that waits for SIGWINCH signals (these indicate the
// terminal has resized). After receiving a SIGWINCH, this gets the terminal size and tries to send
// it to the resizeEvents channel. The goroutine stops when the stop channel is closed.
func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) {
go func() {
defer runtime.HandleCrash()
winch := make(chan os.Signal, 1)
signal.Notify(winch, unix.SIGWINCH)
defer signal.Stop(winch)
for {
select {
case <-winch:
size := GetSize(fd)
if size == nil {
return
}
// try to send size
select {
case resizeEvents <- *size:
// success
default:
// not sent
}
case <-stop:
return
}
}
}()
}

View File

@ -0,0 +1,62 @@
/*
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 term
import (
"time"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/remotecommand"
)
// monitorResizeEvents spawns a goroutine that periodically gets the terminal size and tries to send
// it to the resizeEvents channel if the size has changed. The goroutine stops when the stop channel
// is closed.
func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) {
go func() {
defer runtime.HandleCrash()
size := GetSize(fd)
if size == nil {
return
}
lastSize := *size
for {
// see if we need to stop running
select {
case <-stop:
return
default:
}
size := GetSize(fd)
if size == nil {
return
}
if size.Height != lastSize.Height || size.Width != lastSize.Width {
lastSize.Height = size.Height
lastSize.Width = size.Width
resizeEvents <- *size
}
// sleep to avoid hot looping
time.Sleep(250 * time.Millisecond)
}
}()
}

110
vendor/k8s.io/kubernetes/pkg/kubectl/util/term/term.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
/*
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 term
import (
"io"
"os"
"github.com/docker/docker/pkg/term"
"k8s.io/kubernetes/pkg/util/interrupt"
)
// SafeFunc is a function to be invoked by TTY.
type SafeFunc func() error
// TTY helps invoke a function and preserve the state of the terminal, even if the process is
// terminated during execution. It also provides support for terminal resizing for remote command
// execution/attachment.
type TTY struct {
// In is a reader representing stdin. It is a required field.
In io.Reader
// Out is a writer representing stdout. It must be set to support terminal resizing. It is an
// optional field.
Out io.Writer
// Raw is true if the terminal should be set raw.
Raw bool
// TryDev indicates the TTY should try to open /dev/tty if the provided input
// is not a file descriptor.
TryDev bool
// Parent is an optional interrupt handler provided to this function - if provided
// it will be invoked after the terminal state is restored. If it is not provided,
// a signal received during the TTY will result in os.Exit(0) being invoked.
Parent *interrupt.Handler
// sizeQueue is set after a call to MonitorSize() and is used to monitor SIGWINCH signals when the
// user's terminal resizes.
sizeQueue *sizeQueue
}
// IsTerminalIn returns true if t.In is a terminal. Does not check /dev/tty
// even if TryDev is set.
func (t TTY) IsTerminalIn() bool {
return IsTerminal(t.In)
}
// IsTerminalOut returns true if t.Out is a terminal. Does not check /dev/tty
// even if TryDev is set.
func (t TTY) IsTerminalOut() bool {
return IsTerminal(t.Out)
}
// IsTerminal returns whether the passed object is a terminal or not
func IsTerminal(i interface{}) bool {
_, terminal := term.GetFdInfo(i)
return terminal
}
// Safe invokes the provided function and will attempt to ensure that when the
// function returns (or a termination signal is sent) that the terminal state
// is reset to the condition it was in prior to the function being invoked. If
// t.Raw is true the terminal will be put into raw mode prior to calling the function.
// If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file
// will be opened (if available).
func (t TTY) Safe(fn SafeFunc) error {
inFd, isTerminal := term.GetFdInfo(t.In)
if !isTerminal && t.TryDev {
if f, err := os.Open("/dev/tty"); err == nil {
defer f.Close()
inFd = f.Fd()
isTerminal = term.IsTerminal(inFd)
}
}
if !isTerminal {
return fn()
}
var state *term.State
var err error
if t.Raw {
state, err = term.MakeRaw(inFd)
} else {
state, err = term.SaveState(inFd)
}
if err != nil {
return err
}
return interrupt.Chain(t.Parent, func() {
if t.sizeQueue != nil {
t.sizeQueue.stop()
}
term.RestoreTerminal(inFd, state)
}).Run(fn)
}

View File

@ -0,0 +1,124 @@
/*
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 term
import (
"io"
"os"
"github.com/docker/docker/pkg/term"
wordwrap "github.com/mitchellh/go-wordwrap"
)
type wordWrapWriter struct {
limit uint
writer io.Writer
}
// NewResponsiveWriter creates a Writer that detects the column width of the
// terminal we are in, and adjusts every line width to fit and use recommended
// terminal sizes for better readability. Does proper word wrapping automatically.
// if terminal width >= 120 columns use 120 columns
// if terminal width >= 100 columns use 100 columns
// if terminal width >= 80 columns use 80 columns
// In case we're not in a terminal or if it's smaller than 80 columns width,
// doesn't do any wrapping.
func NewResponsiveWriter(w io.Writer) io.Writer {
file, ok := w.(*os.File)
if !ok {
return w
}
fd := file.Fd()
if !term.IsTerminal(fd) {
return w
}
terminalSize := GetSize(fd)
if terminalSize == nil {
return w
}
var limit uint
switch {
case terminalSize.Width >= 120:
limit = 120
case terminalSize.Width >= 100:
limit = 100
case terminalSize.Width >= 80:
limit = 80
}
return NewWordWrapWriter(w, limit)
}
// NewWordWrapWriter is a Writer that supports a limit of characters on every line
// and does auto word wrapping that respects that limit.
func NewWordWrapWriter(w io.Writer, limit uint) io.Writer {
return &wordWrapWriter{
limit: limit,
writer: w,
}
}
func (w wordWrapWriter) Write(p []byte) (nn int, err error) {
if w.limit == 0 {
return w.writer.Write(p)
}
original := string(p)
wrapped := wordwrap.WrapString(original, w.limit)
return w.writer.Write([]byte(wrapped))
}
// NewPunchCardWriter is a NewWordWrapWriter that limits the line width to 80 columns.
func NewPunchCardWriter(w io.Writer) io.Writer {
return NewWordWrapWriter(w, 80)
}
type maxWidthWriter struct {
maxWidth uint
currentWidth uint
written uint
writer io.Writer
}
// NewMaxWidthWriter is a Writer that supports a limit of characters on every
// line, but doesn't do any word wrapping automatically.
func NewMaxWidthWriter(w io.Writer, maxWidth uint) io.Writer {
return &maxWidthWriter{
maxWidth: maxWidth,
writer: w,
}
}
func (m maxWidthWriter) Write(p []byte) (nn int, err error) {
for _, b := range p {
if m.currentWidth == m.maxWidth {
m.writer.Write([]byte{'\n'})
m.currentWidth = 0
}
if b == '\n' {
m.currentWidth = 0
}
_, err := m.writer.Write([]byte{b})
if err != nil {
return int(m.written), err
}
m.written++
m.currentWidth++
}
return len(p), nil
}

View File

@ -0,0 +1,98 @@
/*
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 term
import (
"bytes"
"strings"
"testing"
)
const test = "Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube Kube"
func TestWordWrapWriter(t *testing.T) {
testcases := map[string]struct {
input string
maxWidth uint
}{
"max 10": {input: test, maxWidth: 10},
"max 80": {input: test, maxWidth: 80},
"max 120": {input: test, maxWidth: 120},
"max 5000": {input: test, maxWidth: 5000},
}
for k, tc := range testcases {
b := bytes.NewBufferString("")
w := NewWordWrapWriter(b, tc.maxWidth)
_, err := w.Write([]byte(tc.input))
if err != nil {
t.Errorf("%s: Unexpected error: %v", k, err)
}
result := b.String()
if !strings.Contains(result, "Kube") {
t.Errorf("%s: Expected to contain \"Kube\"", k)
}
if len(result) < len(tc.input) {
t.Errorf("%s: Unexpectedly short string, got %d wanted at least %d chars: %q", k, len(result), len(tc.input), result)
}
for _, line := range strings.Split(result, "\n") {
if len(line) > int(tc.maxWidth) {
t.Errorf("%s: Every line must be at most %d chars long, got %d: %q", k, tc.maxWidth, len(line), line)
}
}
for _, word := range strings.Split(result, " ") {
if !strings.Contains(word, "Kube") {
t.Errorf("%s: Unexpected broken word: %q", k, word)
}
}
}
}
func TestMaxWidthWriter(t *testing.T) {
testcases := map[string]struct {
input string
maxWidth uint
}{
"max 10": {input: test, maxWidth: 10},
"max 80": {input: test, maxWidth: 80},
"max 120": {input: test, maxWidth: 120},
"max 5000": {input: test, maxWidth: 5000},
}
for k, tc := range testcases {
b := bytes.NewBufferString("")
w := NewMaxWidthWriter(b, tc.maxWidth)
_, err := w.Write([]byte(tc.input))
if err != nil {
t.Errorf("%s: Unexpected error: %v", k, err)
}
result := b.String()
if !strings.Contains(result, "Kube") {
t.Errorf("%s: Expected to contain \"Kube\"", k)
}
if len(result) < len(tc.input) {
t.Errorf("%s: Unexpectedly short string, got %d wanted at least %d chars: %q", k, len(result), len(tc.input), result)
}
lines := strings.Split(result, "\n")
for i, line := range lines {
if len(line) > int(tc.maxWidth) {
t.Errorf("%s: Every line must be at most %d chars long, got %d: %q", k, tc.maxWidth, len(line), line)
}
if i < len(lines)-1 && len(line) != int(tc.maxWidth) {
t.Errorf("%s: Lines except the last one are expected to be exactly %d chars long, got %d: %q", k, tc.maxWidth, len(line), line)
}
}
}
}

27
vendor/k8s.io/kubernetes/pkg/kubectl/util/umask.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
// +build !windows
/*
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 util
import (
"golang.org/x/sys/unix"
)
func Umask(mask int) (old int, err error) {
return unix.Umask(mask), nil
}

View File

@ -0,0 +1,27 @@
// +build windows
/*
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 util
import (
"errors"
)
func Umask(mask int) (int, error) {
return 0, errors.New("platform and architecture is not supported")
}

91
vendor/k8s.io/kubernetes/pkg/kubectl/util/util.go generated vendored Normal file
View File

@ -0,0 +1,91 @@
/*
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 util
import (
"crypto/md5"
"errors"
"fmt"
"path"
"strings"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// ParseRFC3339 parses an RFC3339 date in either RFC3339Nano or RFC3339 format.
func ParseRFC3339(s string, nowFn func() metav1.Time) (metav1.Time, error) {
if t, timeErr := time.Parse(time.RFC3339Nano, s); timeErr == nil {
return metav1.Time{Time: t}, nil
}
t, err := time.Parse(time.RFC3339, s)
if err != nil {
return metav1.Time{}, err
}
return metav1.Time{Time: t}, nil
}
func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) {
data, err := runtime.Encode(codec, obj)
if err != nil {
return "", err
}
return fmt.Sprintf("%x", md5.Sum(data)), nil
}
// ParseFileSource parses the source given.
//
// Acceptable formats include:
// 1. source-path: the basename will become the key name
// 2. source-name=source-path: the source-name will become the key name and
// source-path is the path to the key file.
//
// Key names cannot include '='.
func ParseFileSource(source string) (keyName, filePath string, err error) {
numSeparators := strings.Count(source, "=")
switch {
case numSeparators == 0:
return path.Base(source), source, nil
case numSeparators == 1 && strings.HasPrefix(source, "="):
return "", "", fmt.Errorf("key name for file path %v missing.", strings.TrimPrefix(source, "="))
case numSeparators == 1 && strings.HasSuffix(source, "="):
return "", "", fmt.Errorf("file path for key name %v missing.", strings.TrimSuffix(source, "="))
case numSeparators > 1:
return "", "", errors.New("Key names or file paths cannot contain '='.")
default:
components := strings.Split(source, "=")
return components[0], components[1], nil
}
}
// ParseLiteralSource parses the source key=val pair into its component pieces.
// This functionality is distinguished from strings.SplitN(source, "=", 2) since
// it returns an error in the case of empty keys, values, or a missing equals sign.
func ParseLiteralSource(source string) (keyName, value string, err error) {
// leading equal is invalid
if strings.Index(source, "=") == 0 {
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
}
// split after the first equal (so values can have the = character)
items := strings.SplitN(source, "=", 2)
if len(items) != 2 {
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
}
return items[0], items[1], nil
}

198
vendor/k8s.io/kubernetes/pkg/kubectl/util/util_test.go generated vendored Normal file
View File

@ -0,0 +1,198 @@
/*
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 util
import "testing"
func TestParseFileSource(t *testing.T) {
cases := []struct {
name string
input string
key string
filepath string
err bool
}{
{
name: "success 1",
input: "boo=zoo",
key: "boo",
filepath: "zoo",
err: false,
},
{
name: "success 2",
input: "boo=/path/to/zoo",
key: "boo",
filepath: "/path/to/zoo",
err: false,
},
{
name: "success 3",
input: "boo-2=/1/2/3/4/5/zab.txt",
key: "boo-2",
filepath: "/1/2/3/4/5/zab.txt",
err: false,
},
{
name: "success 4",
input: "boo-=this/seems/weird.txt",
key: "boo-",
filepath: "this/seems/weird.txt",
err: false,
},
{
name: "success 5",
input: "-key=some/path",
key: "-key",
filepath: "some/path",
err: false,
},
{
name: "invalid 1",
input: "key==some/path",
err: true,
},
{
name: "invalid 2",
input: "=key=some/path",
err: true,
},
{
name: "invalid 3",
input: "==key=/some/other/path",
err: true,
},
{
name: "invalid 4",
input: "=key",
err: true,
},
{
name: "invalid 5",
input: "key=",
err: true,
},
}
for _, tc := range cases {
key, filepath, err := ParseFileSource(tc.input)
if err != nil {
if tc.err {
continue
}
t.Errorf("%v: unexpected error: %v", tc.name, err)
continue
}
if tc.err {
t.Errorf("%v: unexpected success", tc.name)
continue
}
if e, a := tc.key, key; e != a {
t.Errorf("%v: expected key %v; got %v", tc.name, e, a)
continue
}
if e, a := tc.filepath, filepath; e != a {
t.Errorf("%v: expected filepath %v; got %v", tc.name, e, a)
}
}
}
func TestParseLiteralSource(t *testing.T) {
cases := []struct {
name string
input string
key string
value string
err bool
}{
{
name: "success 1",
input: "key=value",
key: "key",
value: "value",
err: false,
},
{
name: "success 2",
input: "key=value/with/slashes",
key: "key",
value: "value/with/slashes",
err: false,
},
{
name: "err 1",
input: "key==value",
key: "key",
value: "=value",
err: false,
},
{
name: "err 2",
input: "key=value=",
key: "key",
value: "value=",
err: false,
},
{
name: "err 3",
input: "key2=value==",
key: "key2",
value: "value==",
err: false,
},
{
name: "err 4",
input: "==key",
err: true,
},
{
name: "err 5",
input: "=key=",
err: true,
},
}
for _, tc := range cases {
key, value, err := ParseLiteralSource(tc.input)
if err != nil {
if tc.err {
continue
}
t.Errorf("%v: unexpected error: %v", tc.name, err)
continue
}
if tc.err {
t.Errorf("%v: unexpected success", tc.name)
continue
}
if e, a := tc.key, key; e != a {
t.Errorf("%v: expected key %v; got %v", tc.name, e, a)
continue
}
if e, a := tc.value, value; e != a {
t.Errorf("%v: expected value %v; got %v", tc.name, e, a)
}
}
}