field_lookup.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. "fmt"
  16. "k8s.io/kube-openapi/pkg/util/proto"
  17. )
  18. // fieldLookup walks through a schema by following a path, and returns
  19. // the final schema.
  20. type fieldLookup struct {
  21. // Path to walk
  22. Path []string
  23. // Return information: Schema found, or error.
  24. Schema proto.Schema
  25. Error error
  26. }
  27. // SaveLeafSchema is used to detect if we are done walking the path, and
  28. // saves the schema as a match.
  29. func (f *fieldLookup) SaveLeafSchema(schema proto.Schema) bool {
  30. if len(f.Path) != 0 {
  31. return false
  32. }
  33. f.Schema = schema
  34. return true
  35. }
  36. // VisitArray is mostly a passthrough.
  37. func (f *fieldLookup) VisitArray(a *proto.Array) {
  38. if f.SaveLeafSchema(a) {
  39. return
  40. }
  41. // Passthrough arrays.
  42. a.SubType.Accept(f)
  43. }
  44. // VisitMap is mostly a passthrough.
  45. func (f *fieldLookup) VisitMap(m *proto.Map) {
  46. if f.SaveLeafSchema(m) {
  47. return
  48. }
  49. // Passthrough maps.
  50. m.SubType.Accept(f)
  51. }
  52. // VisitPrimitive stops the operation and returns itself as the found
  53. // schema, even if it had more path to walk.
  54. func (f *fieldLookup) VisitPrimitive(p *proto.Primitive) {
  55. // Even if Path is not empty (we're not expecting a leaf),
  56. // return that primitive.
  57. f.Schema = p
  58. }
  59. // VisitKind unstacks fields as it finds them.
  60. func (f *fieldLookup) VisitKind(k *proto.Kind) {
  61. if f.SaveLeafSchema(k) {
  62. return
  63. }
  64. subSchema, ok := k.Fields[f.Path[0]]
  65. if !ok {
  66. f.Error = fmt.Errorf("field %q does not exist", f.Path[0])
  67. return
  68. }
  69. f.Path = f.Path[1:]
  70. subSchema.Accept(f)
  71. }
  72. func (f *fieldLookup) VisitArbitrary(a *proto.Arbitrary) {
  73. f.Schema = a
  74. }
  75. // VisitReference is mostly a passthrough.
  76. func (f *fieldLookup) VisitReference(r proto.Reference) {
  77. if f.SaveLeafSchema(r) {
  78. return
  79. }
  80. // Passthrough references.
  81. r.SubSchema().Accept(f)
  82. }
  83. // LookupSchemaForField looks for the schema of a given path in a base schema.
  84. func LookupSchemaForField(schema proto.Schema, path []string) (proto.Schema, error) {
  85. f := &fieldLookup{Path: path}
  86. schema.Accept(f)
  87. return f.Schema, f.Error
  88. }