model_printer.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package explain
  14. import (
  15. "k8s.io/apimachinery/pkg/runtime/schema"
  16. "k8s.io/kube-openapi/pkg/util/proto"
  17. )
  18. const (
  19. // fieldIndentLevel is the level of indentation for fields.
  20. fieldIndentLevel = 3
  21. // descriptionIndentLevel is the level of indentation for the
  22. // description.
  23. descriptionIndentLevel = 5
  24. )
  25. // modelPrinter prints a schema in Writer. Its "Builder" will decide if
  26. // it's recursive or not.
  27. type modelPrinter struct {
  28. Name string
  29. Type string
  30. Descriptions []string
  31. Writer *Formatter
  32. Builder fieldsPrinterBuilder
  33. GVK schema.GroupVersionKind
  34. Error error
  35. }
  36. var _ proto.SchemaVisitor = &modelPrinter{}
  37. func (m *modelPrinter) PrintKindAndVersion() error {
  38. if err := m.Writer.Write("KIND: %s", m.GVK.Kind); err != nil {
  39. return err
  40. }
  41. return m.Writer.Write("VERSION: %s\n", m.GVK.GroupVersion())
  42. }
  43. // PrintDescription prints the description for a given schema. There
  44. // might be multiple description, since we collect descriptions when we
  45. // go through references, arrays and maps.
  46. func (m *modelPrinter) PrintDescription(schema proto.Schema) error {
  47. if err := m.Writer.Write("DESCRIPTION:"); err != nil {
  48. return err
  49. }
  50. empty := true
  51. for i, desc := range append(m.Descriptions, schema.GetDescription()) {
  52. if desc == "" {
  53. continue
  54. }
  55. empty = false
  56. if i != 0 {
  57. if err := m.Writer.Write(""); err != nil {
  58. return err
  59. }
  60. }
  61. if err := m.Writer.Indent(descriptionIndentLevel).WriteWrapped(desc); err != nil {
  62. return err
  63. }
  64. }
  65. if empty {
  66. return m.Writer.Indent(descriptionIndentLevel).WriteWrapped("<empty>")
  67. }
  68. return nil
  69. }
  70. // VisitArray recurses inside the subtype, while collecting the type if
  71. // not done yet, and the description.
  72. func (m *modelPrinter) VisitArray(a *proto.Array) {
  73. m.Descriptions = append(m.Descriptions, a.GetDescription())
  74. if m.Type == "" {
  75. m.Type = GetTypeName(a)
  76. }
  77. a.SubType.Accept(m)
  78. }
  79. // VisitKind prints a full resource with its fields.
  80. func (m *modelPrinter) VisitKind(k *proto.Kind) {
  81. if err := m.PrintKindAndVersion(); err != nil {
  82. m.Error = err
  83. return
  84. }
  85. if m.Type == "" {
  86. m.Type = GetTypeName(k)
  87. }
  88. if m.Name != "" {
  89. m.Writer.Write("RESOURCE: %s <%s>\n", m.Name, m.Type)
  90. }
  91. if err := m.PrintDescription(k); err != nil {
  92. m.Error = err
  93. return
  94. }
  95. if err := m.Writer.Write("\nFIELDS:"); err != nil {
  96. m.Error = err
  97. return
  98. }
  99. m.Error = m.Builder.BuildFieldsPrinter(m.Writer.Indent(fieldIndentLevel)).PrintFields(k)
  100. }
  101. // VisitMap recurses inside the subtype, while collecting the type if
  102. // not done yet, and the description.
  103. func (m *modelPrinter) VisitMap(om *proto.Map) {
  104. m.Descriptions = append(m.Descriptions, om.GetDescription())
  105. if m.Type == "" {
  106. m.Type = GetTypeName(om)
  107. }
  108. om.SubType.Accept(m)
  109. }
  110. // VisitPrimitive prints a field type and its description.
  111. func (m *modelPrinter) VisitPrimitive(p *proto.Primitive) {
  112. if err := m.PrintKindAndVersion(); err != nil {
  113. m.Error = err
  114. return
  115. }
  116. if m.Type == "" {
  117. m.Type = GetTypeName(p)
  118. }
  119. if err := m.Writer.Write("FIELD: %s <%s>\n", m.Name, m.Type); err != nil {
  120. m.Error = err
  121. return
  122. }
  123. m.Error = m.PrintDescription(p)
  124. }
  125. func (m *modelPrinter) VisitArbitrary(a *proto.Arbitrary) {
  126. if err := m.PrintKindAndVersion(); err != nil {
  127. m.Error = err
  128. return
  129. }
  130. m.Error = m.PrintDescription(a)
  131. }
  132. // VisitReference recurses inside the subtype, while collecting the description.
  133. func (m *modelPrinter) VisitReference(r proto.Reference) {
  134. m.Descriptions = append(m.Descriptions, r.GetDescription())
  135. r.SubSchema().Accept(m)
  136. }
  137. // PrintModel prints the description of a schema in writer.
  138. func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema, gvk schema.GroupVersionKind) error {
  139. m := &modelPrinter{Name: name, Writer: writer, Builder: builder, GVK: gvk}
  140. schema.Accept(m)
  141. return m.Error
  142. }