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

57
vendor/k8s.io/kubernetes/pkg/kubectl/explain/BUILD generated vendored Normal file
View File

@ -0,0 +1,57 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"explain.go",
"field_lookup.go",
"fields_printer.go",
"fields_printer_builder.go",
"formatter.go",
"model_printer.go",
"recursive_fields_printer.go",
"typename.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/explain",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"explain_test.go",
"field_lookup_test.go",
"fields_printer_test.go",
"formatter_test.go",
"model_printer_test.go",
"recursive_fields_printer_test.go",
"typename_test.go",
],
data = ["test-swagger.json"],
importpath = "k8s.io/kubernetes/pkg/kubectl/explain",
library = ":go_default_library",
deps = [
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util/openapi/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)

4
vendor/k8s.io/kubernetes/pkg/kubectl/explain/OWNERS generated vendored Normal file
View File

@ -0,0 +1,4 @@
approvers:
- apelisse
reviewers:
- apelisse

View File

@ -0,0 +1,68 @@
/*
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 explain
import (
"io"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/kube-openapi/pkg/util/proto"
)
type fieldsPrinter interface {
PrintFields(proto.Schema) error
}
func splitDotNotation(model string) (string, []string) {
var fieldsPath []string
// ignore trailing period
model = strings.TrimSuffix(model, ".")
dotModel := strings.Split(model, ".")
if len(dotModel) >= 1 {
fieldsPath = dotModel[1:]
}
return dotModel[0], fieldsPath
}
// SplitAndParseResourceRequest separates the users input into a model and fields
func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (string, []string, error) {
inResource, fieldsPath := splitDotNotation(inResource)
inResource, _ = mapper.ResourceSingularizer(inResource)
return inResource, fieldsPath, nil
}
// PrintModelDescription prints the description of a specific model or dot path.
// If recursive, all components nested within the fields of the schema will be
// printed.
func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema, recursive bool) error {
fieldName := ""
if len(fieldsPath) != 0 {
fieldName = fieldsPath[len(fieldsPath)-1]
}
// Go down the fieldsPath to find what we're trying to explain
schema, err := LookupSchemaForField(schema, fieldsPath)
if err != nil {
return err
}
b := fieldsPrinterBuilder{Recursive: recursive}
f := &Formatter{Writer: w, Wrap: 80}
return PrintModel(fieldName, f, b, schema)
}

View File

@ -0,0 +1,81 @@
/*
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 explain
import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/api/meta"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
)
func TestSplitAndParseResourceRequest(t *testing.T) {
tests := []struct {
name string
inresource string
expectedInResource string
expectedFieldsPath []string
expectedErr bool
}{
{
name: "no trailing period",
inresource: "field1.field2.field3",
expectedInResource: "field1",
expectedFieldsPath: []string{"field2", "field3"},
},
{
name: "trailing period with correct fieldsPath",
inresource: "field1.field2.field3.",
expectedInResource: "field1",
expectedFieldsPath: []string{"field2", "field3"},
},
{
name: "trailing period with incorrect fieldsPath",
inresource: "field1.field2.field3.",
expectedInResource: "field1",
expectedFieldsPath: []string{"field2", "field3", ""},
expectedErr: true,
},
}
mapper := getMapper()
for _, test := range tests {
gotInResource, gotFieldsPath, err := SplitAndParseResourceRequest(test.inresource, mapper)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(test.expectedInResource, gotInResource) && !test.expectedErr {
t.Errorf("%s: expected inresource: %s, got: %s", test.name, test.expectedInResource, gotInResource)
}
if !reflect.DeepEqual(test.expectedFieldsPath, gotFieldsPath) && !test.expectedErr {
t.Errorf("%s: expected fieldsPath: %s, got: %s", test.name, test.expectedFieldsPath, gotFieldsPath)
}
}
}
func getMapper() meta.RESTMapper {
f, _, _, _ := cmdtesting.NewTestFactory()
mapper, _ := f.Object()
return mapper
}

View File

@ -0,0 +1,107 @@
/*
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 explain
import (
"fmt"
"k8s.io/kube-openapi/pkg/util/proto"
)
// fieldLookup walks through a schema by following a path, and returns
// the final schema.
type fieldLookup struct {
// Path to walk
Path []string
// Return information: Schema found, or error.
Schema proto.Schema
Error error
}
// SaveLeafSchema is used to detect if we are done walking the path, and
// saves the schema as a match.
func (f *fieldLookup) SaveLeafSchema(schema proto.Schema) bool {
if len(f.Path) != 0 {
return false
}
f.Schema = schema
return true
}
// VisitArray is mostly a passthrough.
func (f *fieldLookup) VisitArray(a *proto.Array) {
if f.SaveLeafSchema(a) {
return
}
// Passthrough arrays.
a.SubType.Accept(f)
}
// VisitMap is mostly a passthrough.
func (f *fieldLookup) VisitMap(m *proto.Map) {
if f.SaveLeafSchema(m) {
return
}
// Passthrough maps.
m.SubType.Accept(f)
}
// VisitPrimitive stops the operation and returns itself as the found
// schema, even if it had more path to walk.
func (f *fieldLookup) VisitPrimitive(p *proto.Primitive) {
// Even if Path is not empty (we're not expecting a leaf),
// return that primitive.
f.Schema = p
}
// VisitKind unstacks fields as it finds them.
func (f *fieldLookup) VisitKind(k *proto.Kind) {
if f.SaveLeafSchema(k) {
return
}
subSchema, ok := k.Fields[f.Path[0]]
if !ok {
f.Error = fmt.Errorf("field %q does not exist", f.Path[0])
return
}
f.Path = f.Path[1:]
subSchema.Accept(f)
}
// VisitReference is mostly a passthrough.
func (f *fieldLookup) VisitReference(r proto.Reference) {
if f.SaveLeafSchema(r) {
return
}
// Passthrough references.
r.SubSchema().Accept(f)
}
// LookupSchemaForField looks for the schema of a given path in a base schema.
func LookupSchemaForField(schema proto.Schema, path []string) (proto.Schema, error) {
f := &fieldLookup{Path: path}
schema.Accept(f)
return f.Schema, f.Error
}

View File

@ -0,0 +1,81 @@
/*
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 explain
import (
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestFindField(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "OneKind",
})
if schema == nil {
t.Fatal("Counldn't find schema v1.OneKind")
}
tests := []struct {
path []string
err string
expectedPath string
}{
{
path: []string{},
expectedPath: "OneKind",
},
{
path: []string{"field1"},
expectedPath: "OneKind.field1",
},
{
path: []string{"field1", "array"},
expectedPath: "OtherKind.array",
},
{
path: []string{"field1", "what?"},
err: `field "what?" does not exist`,
},
{
path: []string{"field1", ""},
err: `field "" does not exist`,
},
}
for _, test := range tests {
path, err := LookupSchemaForField(schema, test.path)
gotErr := ""
if err != nil {
gotErr = err.Error()
}
gotPath := ""
if path != nil {
gotPath = path.GetPath().String()
}
if gotErr != test.err || gotPath != test.expectedPath {
t.Errorf("LookupSchemaForField(schema, %v) = (path: %q, err: %q), expected (path: %q, err: %q)",
test.path, gotPath, gotErr, test.expectedPath, test.err)
}
}
}

View File

@ -0,0 +1,82 @@
/*
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 explain
import "k8s.io/kube-openapi/pkg/util/proto"
// indentDesc is the level of indentation for descriptions.
const indentDesc = 2
// regularFieldsPrinter prints fields with their type and description.
type regularFieldsPrinter struct {
Writer *Formatter
Error error
}
var _ proto.SchemaVisitor = &regularFieldsPrinter{}
var _ fieldsPrinter = &regularFieldsPrinter{}
// VisitArray prints a Array type. It is just a passthrough.
func (f *regularFieldsPrinter) VisitArray(a *proto.Array) {
a.SubType.Accept(f)
}
// VisitKind prints a Kind type. It prints each key in the kind, with
// the type, the required flag, and the description.
func (f *regularFieldsPrinter) VisitKind(k *proto.Kind) {
for _, key := range k.Keys() {
v := k.Fields[key]
required := ""
if k.IsRequired(key) {
required = " -required-"
}
if err := f.Writer.Write("%s\t<%s>%s", key, GetTypeName(v), required); err != nil {
f.Error = err
return
}
if err := f.Writer.Indent(indentDesc).WriteWrapped("%s", v.GetDescription()); err != nil {
f.Error = err
return
}
if err := f.Writer.Write(""); err != nil {
f.Error = err
return
}
}
}
// VisitMap prints a Map type. It is just a passthrough.
func (f *regularFieldsPrinter) VisitMap(m *proto.Map) {
m.SubType.Accept(f)
}
// VisitPrimitive prints a Primitive type. It stops the recursion.
func (f *regularFieldsPrinter) VisitPrimitive(p *proto.Primitive) {
// Nothing to do. Shouldn't really happen.
}
// VisitReference prints a Reference type. It is just a passthrough.
func (f *regularFieldsPrinter) VisitReference(r proto.Reference) {
r.SubSchema().Accept(f)
}
// PrintFields will write the types from schema.
func (f *regularFieldsPrinter) PrintFields(schema proto.Schema) error {
schema.Accept(f)
return f.Error
}

View File

@ -0,0 +1,36 @@
/*
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 explain
// fieldsPrinterBuilder builds either a regularFieldsPrinter or a
// recursiveFieldsPrinter based on the argument.
type fieldsPrinterBuilder struct {
Recursive bool
}
// BuildFieldsPrinter builds the appropriate fieldsPrinter.
func (f fieldsPrinterBuilder) BuildFieldsPrinter(writer *Formatter) fieldsPrinter {
if f.Recursive {
return &recursiveFieldsPrinter{
Writer: writer,
}
}
return &regularFieldsPrinter{
Writer: writer,
}
}

View File

@ -0,0 +1,66 @@
/*
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 explain
import (
"bytes"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestFields(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "OneKind",
})
if schema == nil {
t.Fatal("Couldn't find schema v1.OneKind")
}
want := `field1 <Object> -required-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac
enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus.
Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci
nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante at
lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit amet
lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum dictum,
vel ullamcorper lorem egestas.
field2 <[]map[string]string>
This is an array of object of PrimitiveDef
`
buf := bytes.Buffer{}
f := Formatter{
Writer: &buf,
Wrap: 80,
}
s, err := LookupSchemaForField(schema, []string{})
if err != nil {
t.Fatalf("Invalid path %v: %v", []string{}, err)
}
if err := (fieldsPrinterBuilder{Recursive: false}).BuildFieldsPrinter(&f).PrintFields(s); err != nil {
t.Fatalf("Failed to print fields: %v", err)
}
got := buf.String()
if got != want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want)
}
}

View File

@ -0,0 +1,120 @@
/*
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 explain
import (
"fmt"
"io"
"strings"
)
// Formatter helps you write with indentation, and can wrap text as needed.
type Formatter struct {
IndentLevel int
Wrap int
Writer io.Writer
}
// Indent creates a new Formatter that will indent the code by that much more.
func (f Formatter) Indent(indent int) *Formatter {
f.IndentLevel = f.IndentLevel + indent
return &f
}
// Write writes a string with the indentation set for the
// Formatter. This is not wrapping text.
func (f *Formatter) Write(str string, a ...interface{}) error {
// Don't indent empty lines
if str == "" {
_, err := io.WriteString(f.Writer, "\n")
return err
}
indent := ""
for i := 0; i < f.IndentLevel; i++ {
indent = indent + " "
}
_, err := io.WriteString(f.Writer, indent+fmt.Sprintf(str, a...)+"\n")
return err
}
// WriteWrapped writes a string with the indentation set for the
// Formatter, and wraps as needed.
func (f *Formatter) WriteWrapped(str string, a ...interface{}) error {
if f.Wrap == 0 {
return f.Write(str, a...)
}
text := fmt.Sprintf(str, a...)
strs := wrapString(text, f.Wrap-f.IndentLevel)
for _, substr := range strs {
if err := f.Write(substr); err != nil {
return err
}
}
return nil
}
type line struct {
wrap int
words []string
}
func (l *line) String() string {
return strings.Join(l.words, " ")
}
func (l *line) Empty() bool {
return len(l.words) == 0
}
func (l *line) Len() int {
return len(l.String())
}
// Add adds the word to the line, returns true if we could, false if we
// didn't have enough room. It's always possible to add to an empty line.
func (l *line) Add(word string) bool {
newLine := line{
wrap: l.wrap,
words: append(l.words, word),
}
if newLine.Len() <= l.wrap || len(l.words) == 0 {
l.words = newLine.words
return true
}
return false
}
func wrapString(str string, wrap int) []string {
words := strings.Fields(str)
wrapped := []string{}
l := line{wrap: wrap}
for _, word := range words {
if l.Add(word) == false {
wrapped = append(wrapped, l.String())
l = line{wrap: wrap}
if l.Add(word) == false {
panic("Couldn't add to empty line.")
}
}
}
if !l.Empty() {
wrapped = append(wrapped, l.String())
}
return wrapped
}

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 explain
import (
"bytes"
"testing"
)
func TestFormatterWrite(t *testing.T) {
buf := bytes.Buffer{}
f := Formatter{
Writer: &buf,
}
f.Write("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
// Indent creates a new Formatter
f.Indent(5).Write("Morbi at turpis faucibus, gravida dolor ut, fringilla velit.")
// So Indent(2) doesn't indent to 7 here.
f.Indent(2).Write("Etiam maximus urna at tellus faucibus mattis.")
want := `Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Morbi at turpis faucibus, gravida dolor ut, fringilla velit.
Etiam maximus urna at tellus faucibus mattis.
`
if buf.String() != want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want)
}
}
func TestFormatterWrappedWrite(t *testing.T) {
buf := bytes.Buffer{}
f := Formatter{
Writer: &buf,
Wrap: 50,
}
f.WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.")
f.Indent(10).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.")
// Test long words (especially urls) on their own line.
f.Indent(20).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ThisIsAVeryLongWordThatDoesn'tFitOnALineOnItsOwn. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.")
want := `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Morbi at turpis faucibus, gravida dolor ut,
fringilla velit.
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Morbi at turpis
faucibus, gravida dolor ut, fringilla
velit.
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
ThisIsAVeryLongWordThatDoesn'tFitOnALineOnItsOwn.
Morbi at turpis faucibus,
gravida dolor ut, fringilla
velit.
`
if buf.String() != want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want)
}
}
func TestDefaultWrap(t *testing.T) {
buf := bytes.Buffer{}
f := Formatter{
Writer: &buf,
// Wrap is not set
}
f.WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit. Etiam maximus urna at tellus faucibus mattis.")
want := `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit. Etiam maximus urna at tellus faucibus mattis.
`
if buf.String() != want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want)
}
}

View File

@ -0,0 +1,127 @@
/*
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 explain
import "k8s.io/kube-openapi/pkg/util/proto"
// fieldIndentLevel is the level of indentation for fields.
const fieldIndentLevel = 3
// descriptionIndentLevel is the level of indentation for the
// description.
const descriptionIndentLevel = 5
// modelPrinter prints a schema in Writer. Its "Builder" will decide if
// it's recursive or not.
type modelPrinter struct {
Name string
Type string
Descriptions []string
Writer *Formatter
Builder fieldsPrinterBuilder
Error error
}
var _ proto.SchemaVisitor = &modelPrinter{}
// PrintDescription prints the description for a given schema. There
// might be multiple description, since we collect descriptions when we
// go through references, arrays and maps.
func (m *modelPrinter) PrintDescription(schema proto.Schema) error {
if err := m.Writer.Write("DESCRIPTION:"); err != nil {
return err
}
for i, desc := range append(m.Descriptions, schema.GetDescription()) {
if desc == "" {
continue
}
if i != 0 {
if err := m.Writer.Write(""); err != nil {
return err
}
}
if err := m.Writer.Indent(descriptionIndentLevel).WriteWrapped(desc); err != nil {
return err
}
}
return nil
}
// VisitArray recurses inside the subtype, while collecting the type if
// not done yet, and the description.
func (m *modelPrinter) VisitArray(a *proto.Array) {
m.Descriptions = append(m.Descriptions, a.GetDescription())
if m.Type == "" {
m.Type = GetTypeName(a)
}
a.SubType.Accept(m)
}
// VisitKind prints a full resource with its fields.
func (m *modelPrinter) VisitKind(k *proto.Kind) {
if m.Type == "" {
m.Type = GetTypeName(k)
}
if m.Name != "" {
m.Writer.Write("RESOURCE: %s <%s>\n", m.Name, m.Type)
}
if err := m.PrintDescription(k); err != nil {
m.Error = err
return
}
if err := m.Writer.Write("\nFIELDS:"); err != nil {
m.Error = err
return
}
m.Error = m.Builder.BuildFieldsPrinter(m.Writer.Indent(fieldIndentLevel)).PrintFields(k)
}
// VisitMap recurses inside the subtype, while collecting the type if
// not done yet, and the description.
func (m *modelPrinter) VisitMap(om *proto.Map) {
m.Descriptions = append(m.Descriptions, om.GetDescription())
if m.Type == "" {
m.Type = GetTypeName(om)
}
om.SubType.Accept(m)
}
// VisitPrimitive prints a field type and its description.
func (m *modelPrinter) VisitPrimitive(p *proto.Primitive) {
if m.Type == "" {
m.Type = GetTypeName(p)
}
if err := m.Writer.Write("FIELD: %s <%s>\n", m.Name, m.Type); err != nil {
m.Error = err
return
}
m.Error = m.PrintDescription(p)
}
// VisitReference recurses inside the subtype, while collecting the description.
func (m *modelPrinter) VisitReference(r proto.Reference) {
m.Descriptions = append(m.Descriptions, r.GetDescription())
r.SubSchema().Accept(m)
}
// PrintModel prints the description of a schema in writer.
func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema) error {
m := &modelPrinter{Name: name, Writer: writer, Builder: builder}
schema.Accept(m)
return m.Error
}

View File

@ -0,0 +1,122 @@
/*
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 explain
import (
"bytes"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestModel(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "OneKind",
})
if schema == nil {
t.Fatal("Couldn't find schema v1.OneKind")
}
tests := []struct {
path []string
want string
}{
{
want: `DESCRIPTION:
OneKind has a short description
FIELDS:
field1 <Object> -required-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac
enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus.
Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci
nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante
at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit
amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum
dictum, vel ullamcorper lorem egestas.
field2 <[]map[string]string>
This is an array of object of PrimitiveDef
`,
path: []string{},
},
{
want: `RESOURCE: field1 <Object>
DESCRIPTION:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac
enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus.
Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci
nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante
at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit
amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum
dictum, vel ullamcorper lorem egestas.
This is another kind of Kind
FIELDS:
array <[]integer>
This array must be an array of int
int <integer>
This int must be an int
object <map[string]string>
This is an object of string
primitive <string>
string <string> -required-
This string must be a string
`,
path: []string{"field1"},
},
{
want: `FIELD: string <string>
DESCRIPTION:
This string must be a string
`,
path: []string{"field1", "string"},
},
{
want: `FIELD: array <[]integer>
DESCRIPTION:
This array must be an array of int
This is an int in an array
`,
path: []string{"field1", "array"},
},
}
for _, test := range tests {
buf := bytes.Buffer{}
if err := PrintModelDescription(test.path, &buf, schema, false); err != nil {
t.Fatalf("Failed to PrintModelDescription for path %v: %v", test.path, err)
}
got := buf.String()
if got != test.want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), test.want)
}
}
}

View File

@ -0,0 +1,75 @@
/*
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 explain
import "k8s.io/kube-openapi/pkg/util/proto"
// indentPerLevel is the level of indentation for each field recursion.
const indentPerLevel = 3
// recursiveFieldsPrinter recursively prints all the fields for a given
// schema.
type recursiveFieldsPrinter struct {
Writer *Formatter
Error error
}
var _ proto.SchemaVisitor = &recursiveFieldsPrinter{}
var _ fieldsPrinter = &recursiveFieldsPrinter{}
// VisitArray is just a passthrough.
func (f *recursiveFieldsPrinter) VisitArray(a *proto.Array) {
a.SubType.Accept(f)
}
// VisitKind prints all its fields with their type, and then recurses
// inside each of these (pre-order).
func (f *recursiveFieldsPrinter) VisitKind(k *proto.Kind) {
for _, key := range k.Keys() {
v := k.Fields[key]
f.Writer.Write("%s\t<%s>", key, GetTypeName(v))
subFields := &recursiveFieldsPrinter{
Writer: f.Writer.Indent(indentPerLevel),
}
if err := subFields.PrintFields(v); err != nil {
f.Error = err
return
}
}
}
// VisitMap is just a passthrough.
func (f *recursiveFieldsPrinter) VisitMap(m *proto.Map) {
m.SubType.Accept(f)
}
// VisitPrimitive does nothing, since it doesn't have sub-fields.
func (f *recursiveFieldsPrinter) VisitPrimitive(p *proto.Primitive) {
// Nothing to do.
}
// VisitReference is just a passthrough.
func (f *recursiveFieldsPrinter) VisitReference(r proto.Reference) {
r.SubSchema().Accept(f)
}
// PrintFields will recursively print all the fields for the given
// schema.
func (f *recursiveFieldsPrinter) PrintFields(schema proto.Schema) error {
schema.Accept(f)
return f.Error
}

View File

@ -0,0 +1,61 @@
/*
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 explain
import (
"bytes"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestRecursiveFields(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "OneKind",
})
if schema == nil {
t.Fatal("Couldn't find schema v1.OneKind")
}
want := `field1 <Object>
array <[]integer>
int <integer>
object <map[string]string>
primitive <string>
string <string>
field2 <[]map[string]string>
`
buf := bytes.Buffer{}
f := Formatter{
Writer: &buf,
Wrap: 80,
}
s, err := LookupSchemaForField(schema, []string{})
if err != nil {
t.Fatalf("Invalid path %v: %v", []string{}, err)
}
if err := (fieldsPrinterBuilder{Recursive: true}).BuildFieldsPrinter(&f).PrintFields(s); err != nil {
t.Fatalf("Failed to print fields: %v", err)
}
got := buf.String()
if got != want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want)
}
}

View File

@ -0,0 +1,78 @@
{
"swagger": "2.0",
"info": {
"title": "Kubernetes",
"version": "v1.9.0"
},
"paths": {},
"definitions": {
"PrimitiveDef": {
"type": "string"
},
"OneKind": {
"description": "OneKind has a short description",
"required": [
"field1",
],
"properties": {
"field1": {
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus. Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum dictum, vel ullamcorper lorem egestas.",
"$ref": "#/definitions/OtherKind"
},
"field2": {
"description": "This is an array of object of PrimitiveDef",
"type": "array",
"items": {
"description": "This is an object of PrimitiveDef",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/PrimitiveDef"
}
}
}
},
"x-kubernetes-group-version-kind": [
{
"group": "",
"kind": "OneKind",
"version": "v1"
}
]
},
"OtherKind": {
"description": "This is another kind of Kind",
"required": [
"string",
],
"properties": {
"string": {
"description": "This string must be a string",
"type": "string",
},
"int": {
"description": "This int must be an int",
"type": "integer",
},
"array": {
"description": "This array must be an array of int",
"type": "array",
"items": {
"description": "This is an int in an array",
"type": "integer",
}
},
"object": {
"description": "This is an object of string",
"type": "object",
"additionalProperties": {
"description": "this is a string in an object",
"type": "string",
}
},
"primitive": {
"$ref": "#/definitions/PrimitiveDef"
}
}
}
}
}

View File

@ -0,0 +1,66 @@
/*
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 explain
import (
"fmt"
"k8s.io/kube-openapi/pkg/util/proto"
)
// typeName finds the name of a schema
type typeName struct {
Name string
}
var _ proto.SchemaVisitor = &typeName{}
// VisitArray adds the [] prefix and recurses.
func (t *typeName) VisitArray(a *proto.Array) {
s := &typeName{}
a.SubType.Accept(s)
t.Name = fmt.Sprintf("[]%s", s.Name)
}
// VisitKind just returns "Object".
func (t *typeName) VisitKind(k *proto.Kind) {
t.Name = "Object"
}
// VisitMap adds the map[string] prefix and recurses.
func (t *typeName) VisitMap(m *proto.Map) {
s := &typeName{}
m.SubType.Accept(s)
t.Name = fmt.Sprintf("map[string]%s", s.Name)
}
// VisitPrimitive returns the name of the primitive.
func (t *typeName) VisitPrimitive(p *proto.Primitive) {
t.Name = p.Type
}
// VisitReference is just a passthrough.
func (t *typeName) VisitReference(r proto.Reference) {
r.SubSchema().Accept(t)
}
// GetTypeName returns the type of a schema.
func GetTypeName(schema proto.Schema) string {
t := &typeName{}
schema.Accept(t)
return t.Name
}

View File

@ -0,0 +1,80 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package explain
import (
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
tst "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/testing"
)
var resources = tst.NewFakeResources("test-swagger.json")
func TestReferenceTypename(t *testing.T) {
schema := resources.LookupResource(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "OneKind",
})
if schema == nil {
t.Fatal("Couldn't find schema v1.OneKind")
}
tests := []struct {
path []string
expected string
}{
{
// Kind is "Object"
path: []string{},
expected: "Object",
},
{
// Reference is equal to pointed type "Object"
path: []string{"field1"},
expected: "Object",
},
{
// Reference is equal to pointed type "string"
path: []string{"field1", "primitive"},
expected: "string",
},
{
// Array of object of reference to string
path: []string{"field2"},
expected: "[]map[string]string",
},
{
// Array of integer
path: []string{"field1", "array"},
expected: "[]integer",
},
}
for _, test := range tests {
s, err := LookupSchemaForField(schema, test.path)
if err != nil {
t.Fatalf("Invalid test.path %v: %v", test.path, err)
}
got := GetTypeName(s)
if got != test.expected {
t.Errorf("Got %q, expected %q", got, test.expected)
}
}
}