github.com/pachyderm/pachyderm@v1.13.4/src/server/pkg/serde/yaml_decoder.go (about) 1 // yaml_decoder.go implements the structfmt.Decoder interfaces for the yaml text 2 // format 3 4 package serde 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "io" 10 11 "github.com/gogo/protobuf/jsonpb" 12 "github.com/gogo/protobuf/proto" 13 "github.com/pachyderm/pachyderm/src/client/pkg/errors" 14 "gopkg.in/pachyderm/yaml.v3" 15 ) 16 17 // DecodeYAML is a convenience function that decodes yaml data using a 18 // YAMLDecoder, but can be called inline 19 func DecodeYAML(yamlData []byte, v interface{}) error { 20 d := NewYAMLDecoder(bytes.NewReader(yamlData)) 21 return d.Decode(v) 22 } 23 24 // YAMLDecoder is an implementation of serde.Decoder that operates on yaml data 25 type YAMLDecoder struct { 26 d *yaml.Decoder 27 } 28 29 // NewYAMLDecoder returns a new YAMLDecoder that reads from 'r' 30 func NewYAMLDecoder(r io.Reader) *YAMLDecoder { 31 return &YAMLDecoder{d: yaml.NewDecoder(r)} 32 } 33 34 // Decode implements the corresponding method of serde.Decoder 35 func (d *YAMLDecoder) Decode(v interface{}) error { 36 return d.DecodeTransform(v, nil) 37 } 38 39 // DecodeTransform implements the corresponding method of serde.Decoder 40 func (d *YAMLDecoder) DecodeTransform(v interface{}, f func(map[string]interface{}) error) error { 41 jsonData, err := d.yamlToJSONTransform(f) 42 if err != nil { 43 return err 44 } 45 46 // parse transformed JSON into 'v' 47 if err := json.Unmarshal(jsonData, v); err != nil { 48 return errors.Wrapf(err, "parse error while canonicalizing yaml") 49 } 50 return nil 51 } 52 53 // DecodeProto implements the corresponding method of serde.Decoder 54 func (d *YAMLDecoder) DecodeProto(v proto.Message) error { 55 return d.DecodeProtoTransform(v, nil) 56 } 57 58 // DecodeProtoTransform implements the corresponding method of serde.Decoder 59 func (d *YAMLDecoder) DecodeProtoTransform(v proto.Message, f func(map[string]interface{}) error) error { 60 jsonData, err := d.yamlToJSONTransform(f) 61 if err != nil { 62 return err 63 } 64 65 // parse transformed JSON into 'v' 66 decoder := json.NewDecoder(bytes.NewReader(jsonData)) 67 if err := jsonpb.UnmarshalNext(decoder, v); err != nil { 68 return errors.Wrapf(err, "error canonicalizing yaml while parsing to proto") 69 } 70 return nil 71 } 72 73 func (d *YAMLDecoder) yamlToJSONTransform(f func(map[string]interface{}) error) ([]byte, error) { 74 // deserialize yaml into 'holder' 75 holder := map[string]interface{}{} 76 if err := d.d.Decode(&holder); err != nil { 77 if errors.Is(err, io.EOF) { 78 return nil, err 79 } 80 return nil, errors.Wrapf(err, "could not parse yaml") 81 } 82 83 // transform 'holder' (e.g. stringifying TFJob) 84 if f != nil { 85 if err := f(holder); err != nil { 86 return nil, err 87 } 88 } 89 90 // serialize 'holder' to json 91 jsonData, err := json.Marshal(holder) 92 if err != nil { 93 return nil, errors.Wrapf(err, "serialization error while canonicalizing yaml") 94 } 95 return jsonData, nil 96 }