recognizer.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. Copyright 2014 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 recognizer
  14. import (
  15. "fmt"
  16. "k8s.io/apimachinery/pkg/runtime"
  17. "k8s.io/apimachinery/pkg/runtime/schema"
  18. )
  19. type RecognizingDecoder interface {
  20. runtime.Decoder
  21. // RecognizesData should return true if the input provided in the provided reader
  22. // belongs to this decoder, or an error if the data could not be read or is ambiguous.
  23. // Unknown is true if the data could not be determined to match the decoder type.
  24. // Decoders should assume that they can read as much of peek as they need (as the caller
  25. // provides) and may return unknown if the data provided is not sufficient to make a
  26. // a determination. When peek returns EOF that may mean the end of the input or the
  27. // end of buffered input - recognizers should return the best guess at that time.
  28. RecognizesData(peek []byte) (ok, unknown bool, err error)
  29. }
  30. // NewDecoder creates a decoder that will attempt multiple decoders in an order defined
  31. // by:
  32. //
  33. // 1. The decoder implements RecognizingDecoder and identifies the data
  34. // 2. All other decoders, and any decoder that returned true for unknown.
  35. //
  36. // The order passed to the constructor is preserved within those priorities.
  37. func NewDecoder(decoders ...runtime.Decoder) runtime.Decoder {
  38. return &decoder{
  39. decoders: decoders,
  40. }
  41. }
  42. type decoder struct {
  43. decoders []runtime.Decoder
  44. }
  45. var _ RecognizingDecoder = &decoder{}
  46. func (d *decoder) RecognizesData(data []byte) (bool, bool, error) {
  47. var (
  48. lastErr error
  49. anyUnknown bool
  50. )
  51. for _, r := range d.decoders {
  52. switch t := r.(type) {
  53. case RecognizingDecoder:
  54. ok, unknown, err := t.RecognizesData(data)
  55. if err != nil {
  56. lastErr = err
  57. continue
  58. }
  59. anyUnknown = anyUnknown || unknown
  60. if !ok {
  61. continue
  62. }
  63. return true, false, nil
  64. }
  65. }
  66. return false, anyUnknown, lastErr
  67. }
  68. func (d *decoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
  69. var (
  70. lastErr error
  71. skipped []runtime.Decoder
  72. )
  73. // try recognizers, record any decoders we need to give a chance later
  74. for _, r := range d.decoders {
  75. switch t := r.(type) {
  76. case RecognizingDecoder:
  77. ok, unknown, err := t.RecognizesData(data)
  78. if err != nil {
  79. lastErr = err
  80. continue
  81. }
  82. if unknown {
  83. skipped = append(skipped, t)
  84. continue
  85. }
  86. if !ok {
  87. continue
  88. }
  89. return r.Decode(data, gvk, into)
  90. default:
  91. skipped = append(skipped, t)
  92. }
  93. }
  94. // try recognizers that returned unknown or didn't recognize their data
  95. for _, r := range skipped {
  96. out, actual, err := r.Decode(data, gvk, into)
  97. if err != nil {
  98. // if we got an object back from the decoder, and the
  99. // error was a strict decoding error (e.g. unknown or
  100. // duplicate fields), we still consider the recognizer
  101. // to have understood the object
  102. if out == nil || !runtime.IsStrictDecodingError(err) {
  103. lastErr = err
  104. continue
  105. }
  106. }
  107. return out, actual, err
  108. }
  109. if lastErr == nil {
  110. lastErr = fmt.Errorf("no serialization format matched the provided data")
  111. }
  112. return nil, nil, lastErr
  113. }