mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-05 15:37:24 +00:00
Rewrite kubectl explain to use openapi
This removes all dependencies on swagger 1.2 for explain.
This commit is contained in:
34
pkg/kubectl/explain/BUILD
Normal file
34
pkg/kubectl/explain/BUILD
Normal file
@@ -0,0 +1,34 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
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",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta: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"],
|
||||
)
|
||||
64
pkg/kubectl/explain/explain.go
Normal file
64
pkg/kubectl/explain/explain.go
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
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/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
type fieldsPrinter interface {
|
||||
PrintFields(openapi.Schema) error
|
||||
}
|
||||
|
||||
func splitDotNotation(model string) (string, []string) {
|
||||
var fieldsPath []string
|
||||
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 openapi.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)
|
||||
}
|
||||
107
pkg/kubectl/explain/field_lookup.go
Normal file
107
pkg/kubectl/explain/field_lookup.go
Normal 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/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
// 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 openapi.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 openapi.Schema) bool {
|
||||
if len(f.Path) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
f.Schema = schema
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// VisitArray is mostly a passthrough.
|
||||
func (f *fieldLookup) VisitArray(a *openapi.Array) {
|
||||
if f.SaveLeafSchema(a) {
|
||||
return
|
||||
}
|
||||
|
||||
// Passthrough arrays.
|
||||
a.SubType.Accept(f)
|
||||
}
|
||||
|
||||
// VisitMap is mostly a passthrough.
|
||||
func (f *fieldLookup) VisitMap(m *openapi.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 *openapi.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 *openapi.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 openapi.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 openapi.Schema, path []string) (openapi.Schema, error) {
|
||||
f := &fieldLookup{Path: path}
|
||||
schema.Accept(f)
|
||||
return f.Schema, f.Error
|
||||
}
|
||||
84
pkg/kubectl/explain/fields_printer.go
Normal file
84
pkg/kubectl/explain/fields_printer.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
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/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
// 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 _ openapi.SchemaVisitor = ®ularFieldsPrinter{}
|
||||
var _ fieldsPrinter = ®ularFieldsPrinter{}
|
||||
|
||||
// VisitArray prints a Array type. It is just a passthrough.
|
||||
func (f *regularFieldsPrinter) VisitArray(a *openapi.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 *openapi.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 *openapi.Map) {
|
||||
m.SubType.Accept(f)
|
||||
}
|
||||
|
||||
// VisitPrimitive prints a Primitive type. It stops the recursion.
|
||||
func (f *regularFieldsPrinter) VisitPrimitive(p *openapi.Primitive) {
|
||||
// Nothing to do. Shouldn't really happen.
|
||||
}
|
||||
|
||||
// VisitReference prints a Reference type. It is just a passthrough.
|
||||
func (f *regularFieldsPrinter) VisitReference(r openapi.Reference) {
|
||||
r.SubSchema().Accept(f)
|
||||
}
|
||||
|
||||
// PrintFields will write the types from schema.
|
||||
func (f *regularFieldsPrinter) PrintFields(schema openapi.Schema) error {
|
||||
schema.Accept(f)
|
||||
return f.Error
|
||||
}
|
||||
36
pkg/kubectl/explain/fields_printer_builder.go
Normal file
36
pkg/kubectl/explain/fields_printer_builder.go
Normal 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 ®ularFieldsPrinter{
|
||||
Writer: writer,
|
||||
}
|
||||
}
|
||||
120
pkg/kubectl/explain/formatter.go
Normal file
120
pkg/kubectl/explain/formatter.go
Normal 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
|
||||
}
|
||||
129
pkg/kubectl/explain/model_printer.go
Normal file
129
pkg/kubectl/explain/model_printer.go
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
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/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
// 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 _ openapi.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 openapi.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 *openapi.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 *openapi.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 *openapi.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 *openapi.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 openapi.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 openapi.Schema) error {
|
||||
m := &modelPrinter{Name: name, Writer: writer, Builder: builder}
|
||||
schema.Accept(m)
|
||||
return m.Error
|
||||
}
|
||||
77
pkg/kubectl/explain/recursive_fields_printer.go
Normal file
77
pkg/kubectl/explain/recursive_fields_printer.go
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
// 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 _ openapi.SchemaVisitor = &recursiveFieldsPrinter{}
|
||||
var _ fieldsPrinter = &recursiveFieldsPrinter{}
|
||||
|
||||
// VisitArray is just a passthrough.
|
||||
func (f *recursiveFieldsPrinter) VisitArray(a *openapi.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 *openapi.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 *openapi.Map) {
|
||||
m.SubType.Accept(f)
|
||||
}
|
||||
|
||||
// VisitPrimitive does nothing, since it doesn't have sub-fields.
|
||||
func (f *recursiveFieldsPrinter) VisitPrimitive(p *openapi.Primitive) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
// VisitReference is just a passthrough.
|
||||
func (f *recursiveFieldsPrinter) VisitReference(r openapi.Reference) {
|
||||
r.SubSchema().Accept(f)
|
||||
}
|
||||
|
||||
// PrintFields will recursively print all the fields for the given
|
||||
// schema.
|
||||
func (f *recursiveFieldsPrinter) PrintFields(schema openapi.Schema) error {
|
||||
schema.Accept(f)
|
||||
return f.Error
|
||||
}
|
||||
66
pkg/kubectl/explain/typename.go
Normal file
66
pkg/kubectl/explain/typename.go
Normal 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/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
// typeName finds the name of a schema
|
||||
type typeName struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
var _ openapi.SchemaVisitor = &typeName{}
|
||||
|
||||
// VisitArray adds the [] prefix and recurses.
|
||||
func (t *typeName) VisitArray(a *openapi.Array) {
|
||||
s := &typeName{}
|
||||
a.SubType.Accept(s)
|
||||
t.Name = fmt.Sprintf("[]%s", s.Name)
|
||||
}
|
||||
|
||||
// VisitKind just returns "Object".
|
||||
func (t *typeName) VisitKind(k *openapi.Kind) {
|
||||
t.Name = "Object"
|
||||
}
|
||||
|
||||
// VisitMap adds the map[string] prefix and recurses.
|
||||
func (t *typeName) VisitMap(m *openapi.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 *openapi.Primitive) {
|
||||
t.Name = p.Type
|
||||
}
|
||||
|
||||
// VisitReference is just a passthrough.
|
||||
func (t *typeName) VisitReference(r openapi.Reference) {
|
||||
r.SubSchema().Accept(t)
|
||||
}
|
||||
|
||||
// GetTypeName returns the type of a schema.
|
||||
func GetTypeName(schema openapi.Schema) string {
|
||||
t := &typeName{}
|
||||
schema.Accept(t)
|
||||
return t.Name
|
||||
}
|
||||
Reference in New Issue
Block a user