diff --git a/pkg/runtime/codec.go b/pkg/runtime/codec.go index 585df98924..640d6c3eb3 100644 --- a/pkg/runtime/codec.go +++ b/pkg/runtime/codec.go @@ -16,11 +16,47 @@ limitations under the License. package runtime +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml" +) + // CodecFor returns a Codec that invokes Encode with the provided version. func CodecFor(scheme *Scheme, version string) Codec { return &codecWrapper{scheme, version} } +// yamlCodec converts YAML passed to the Decoder methods to JSON. +type yamlCodec struct { + // a Codec for JSON + Codec +} + +// yamlCodec implements Codec +var _ Codec = yamlCodec{} + +// YAMLDecoder adds YAML decoding support to a codec that supports JSON. +func YAMLDecoder(codec Codec) Codec { + return &yamlCodec{codec} +} + +func (c yamlCodec) Decode(data []byte) (Object, error) { + out, err := yaml.ToJSON(data) + if err != nil { + return nil, err + } + data = out + return c.Codec.Decode(data) +} + +func (c yamlCodec) DecodeInto(data []byte, obj Object) error { + out, err := yaml.ToJSON(data) + if err != nil { + return err + } + data = out + return c.Codec.DecodeInto(data, obj) +} + // EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests. func EncodeOrDie(codec Codec, obj Object) string { bytes, err := codec.Encode(obj) diff --git a/pkg/util/yaml/decoder.go b/pkg/util/yaml/decoder.go index e6e281b1c3..8dfc56cd82 100644 --- a/pkg/util/yaml/decoder.go +++ b/pkg/util/yaml/decoder.go @@ -27,6 +27,17 @@ import ( "github.com/golang/glog" ) +// ToJSON converts a single YAML document into a JSON document +// or returns an error. If the document appears to be JSON the +// YAML decoding path is not used (so that error messages are) +// JSON specific. +func ToJSON(data []byte) ([]byte, error) { + if hasJSONPrefix(data) { + return data, nil + } + return yaml.YAMLToJSON(data) +} + // YAMLToJSONDecoder decodes YAML documents from an io.Reader by // separating individual documents. It first converts the YAML // body to JSON, then unmarshals the JSON. @@ -143,11 +154,19 @@ func (d *YAMLOrJSONDecoder) Decode(into interface{}) error { func guessJSONStream(r io.Reader, size int) (io.Reader, bool) { buffer := bufio.NewReaderSize(r, size) b, _ := buffer.Peek(size) - return buffer, hasPrefix(b, []byte("{")) + return buffer, hasJSONPrefix(b) +} + +var jsonPrefix = []byte("{") + +// hasJSONPrefix returns true if the provided buffer appears to start with +// a JSON open brace. +func hasJSONPrefix(buf []byte) bool { + return hasPrefix(buf, jsonPrefix) } // Return true if the first non-whitespace bytes in buf is -// prefix +// prefix. func hasPrefix(buf []byte, prefix []byte) bool { trim := bytes.TrimLeftFunc(buf, unicode.IsSpace) return bytes.HasPrefix(trim, prefix)