2019-10-18 00:00:58 +09:00
|
|
|
package yaml
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/base64"
|
2019-10-18 15:20:09 +09:00
|
|
|
"fmt"
|
2019-10-18 00:00:58 +09:00
|
|
|
"io"
|
|
|
|
|
"io/ioutil"
|
2019-10-18 15:20:09 +09:00
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
2019-10-18 00:00:58 +09:00
|
|
|
"reflect"
|
|
|
|
|
|
|
|
|
|
"github.com/goccy/go-yaml/ast"
|
2019-10-24 11:07:40 +09:00
|
|
|
"github.com/goccy/go-yaml/internal/errors"
|
2019-10-18 00:00:58 +09:00
|
|
|
"github.com/goccy/go-yaml/lexer"
|
|
|
|
|
"github.com/goccy/go-yaml/parser"
|
|
|
|
|
"github.com/goccy/go-yaml/token"
|
2019-10-24 23:54:17 +09:00
|
|
|
"golang.org/x/xerrors"
|
2019-10-18 00:00:58 +09:00
|
|
|
)
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// Decoder reads and decodes YAML values from an input stream.
|
2019-10-18 00:00:58 +09:00
|
|
|
type Decoder struct {
|
2019-10-18 15:20:09 +09:00
|
|
|
reader io.Reader
|
|
|
|
|
referenceReaders []io.Reader
|
2019-10-24 23:54:17 +09:00
|
|
|
anchorMap map[string]ast.Node
|
2019-10-18 15:20:09 +09:00
|
|
|
opts []DecodeOption
|
|
|
|
|
referenceFiles []string
|
|
|
|
|
referenceDirs []string
|
|
|
|
|
isRecursiveDir bool
|
|
|
|
|
isResolvedReference bool
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// NewDecoder returns a new decoder that reads from r.
|
2019-10-18 15:20:09 +09:00
|
|
|
func NewDecoder(r io.Reader, opts ...DecodeOption) *Decoder {
|
2019-10-18 14:27:49 +09:00
|
|
|
return &Decoder{
|
2019-10-18 15:20:09 +09:00
|
|
|
reader: r,
|
2019-10-24 23:54:17 +09:00
|
|
|
anchorMap: map[string]ast.Node{},
|
2019-10-18 15:20:09 +09:00
|
|
|
opts: opts,
|
|
|
|
|
referenceReaders: []io.Reader{},
|
|
|
|
|
referenceFiles: []string{},
|
|
|
|
|
referenceDirs: []string{},
|
|
|
|
|
isRecursiveDir: false,
|
|
|
|
|
isResolvedReference: false,
|
2019-10-18 14:27:49 +09:00
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) nodeToValue(node ast.Node) interface{} {
|
|
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.NullNode:
|
|
|
|
|
return nil
|
|
|
|
|
case *ast.StringNode:
|
|
|
|
|
return n.GetValue()
|
|
|
|
|
case *ast.IntegerNode:
|
|
|
|
|
return n.GetValue()
|
|
|
|
|
case *ast.FloatNode:
|
|
|
|
|
return n.GetValue()
|
|
|
|
|
case *ast.BoolNode:
|
|
|
|
|
return n.GetValue()
|
|
|
|
|
case *ast.InfinityNode:
|
|
|
|
|
return n.GetValue()
|
|
|
|
|
case *ast.NanNode:
|
|
|
|
|
return n.GetValue()
|
|
|
|
|
case *ast.TagNode:
|
|
|
|
|
switch n.Start.Value {
|
|
|
|
|
case token.BinaryTag:
|
|
|
|
|
b, _ := base64.StdEncoding.DecodeString(d.nodeToValue(n.Value).(string))
|
|
|
|
|
return b
|
|
|
|
|
}
|
2019-10-18 14:27:49 +09:00
|
|
|
case *ast.AnchorNode:
|
|
|
|
|
anchorName := n.Name.GetToken().Value
|
|
|
|
|
anchorValue := d.nodeToValue(n.Value)
|
2019-10-24 23:54:17 +09:00
|
|
|
d.anchorMap[anchorName] = n.Value
|
2019-10-18 14:27:49 +09:00
|
|
|
return anchorValue
|
|
|
|
|
case *ast.AliasNode:
|
|
|
|
|
aliasName := n.Value.GetToken().Value
|
2019-10-24 23:54:17 +09:00
|
|
|
return d.nodeToValue(d.anchorMap[aliasName])
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.LiteralNode:
|
|
|
|
|
return n.Value.GetValue()
|
|
|
|
|
case *ast.FlowMappingNode:
|
|
|
|
|
m := map[string]interface{}{}
|
|
|
|
|
for _, value := range n.Values {
|
|
|
|
|
key := value.Key.GetToken().Value
|
|
|
|
|
m[key] = d.nodeToValue(value.Value)
|
|
|
|
|
}
|
|
|
|
|
return m
|
|
|
|
|
case *ast.MappingValueNode:
|
|
|
|
|
m := map[string]interface{}{}
|
2019-10-21 14:54:26 +09:00
|
|
|
if n.Key.Type() == ast.MergeKeyType {
|
|
|
|
|
mapValue := d.nodeToValue(n.Value).(map[string]interface{})
|
|
|
|
|
for k, v := range mapValue {
|
|
|
|
|
m[k] = v
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
key := n.Key.GetToken().Value
|
|
|
|
|
m[key] = d.nodeToValue(n.Value)
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
return m
|
|
|
|
|
case *ast.MappingCollectionNode:
|
|
|
|
|
m := map[string]interface{}{}
|
|
|
|
|
for _, value := range n.Values {
|
|
|
|
|
subMap := d.nodeToValue(value).(map[string]interface{})
|
|
|
|
|
for k, v := range subMap {
|
|
|
|
|
m[k] = v
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return m
|
|
|
|
|
case *ast.FlowSequenceNode:
|
|
|
|
|
v := []interface{}{}
|
|
|
|
|
for _, value := range n.Values {
|
|
|
|
|
v = append(v, d.nodeToValue(value))
|
|
|
|
|
}
|
|
|
|
|
return v
|
|
|
|
|
case *ast.SequenceNode:
|
|
|
|
|
v := []interface{}{}
|
|
|
|
|
for _, value := range n.Values {
|
|
|
|
|
v = append(v, d.nodeToValue(value))
|
|
|
|
|
}
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) getMapNode(node ast.Node) (ast.MapNode, error) {
|
|
|
|
|
if anchor, ok := node.(*ast.AnchorNode); ok {
|
|
|
|
|
mapNode, ok := anchor.Value.(ast.MapNode)
|
|
|
|
|
if ok {
|
|
|
|
|
return mapNode, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, xerrors.Errorf("%s node doesn't MapNode", anchor.Value.Type())
|
|
|
|
|
}
|
|
|
|
|
if alias, ok := node.(*ast.AliasNode); ok {
|
|
|
|
|
aliasName := alias.Value.GetToken().Value
|
|
|
|
|
anchorNode := d.anchorMap[aliasName]
|
|
|
|
|
mapNode, ok := anchorNode.(ast.MapNode)
|
|
|
|
|
if ok {
|
|
|
|
|
return mapNode, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, xerrors.Errorf("%s node doesn't MapNode", anchorNode.Type())
|
|
|
|
|
}
|
|
|
|
|
mapNode, ok := node.(ast.MapNode)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, xerrors.Errorf("%s node doesn't MapNode", node.Type())
|
|
|
|
|
}
|
|
|
|
|
return mapNode, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) getArrayNode(node ast.Node) (ast.ArrayNode, error) {
|
|
|
|
|
if anchor, ok := node.(*ast.AnchorNode); ok {
|
|
|
|
|
arrayNode, ok := anchor.Value.(ast.ArrayNode)
|
|
|
|
|
if ok {
|
|
|
|
|
return arrayNode, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, xerrors.Errorf("%s node doesn't ArrayNode", anchor.Value.Type())
|
|
|
|
|
}
|
|
|
|
|
if alias, ok := node.(*ast.AliasNode); ok {
|
|
|
|
|
aliasName := alias.Value.GetToken().Value
|
|
|
|
|
anchorNode := d.anchorMap[aliasName]
|
|
|
|
|
arrayNode, ok := anchorNode.(ast.ArrayNode)
|
|
|
|
|
if ok {
|
|
|
|
|
return arrayNode, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, xerrors.Errorf("%s node doesn't ArrayNode", anchorNode.Type())
|
|
|
|
|
}
|
|
|
|
|
arrayNode, ok := node.(ast.ArrayNode)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, xerrors.Errorf("%s node doesn't ArrayNode", node.Type())
|
|
|
|
|
}
|
|
|
|
|
return arrayNode, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) docToNode(doc *ast.Document) ast.Node {
|
2019-10-18 00:00:58 +09:00
|
|
|
for _, node := range doc.Nodes {
|
2019-10-18 13:05:36 +09:00
|
|
|
if v := d.nodeToValue(node); v != nil {
|
2019-10-24 23:54:17 +09:00
|
|
|
return node
|
2019-10-18 13:05:36 +09:00
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
|
2019-10-24 17:18:03 +09:00
|
|
|
valueType := dst.Type()
|
|
|
|
|
if unmarshaler, ok := dst.Addr().Interface().(Unmarshaler); ok {
|
2019-10-24 23:54:17 +09:00
|
|
|
b := fmt.Sprintf("%v", src)
|
|
|
|
|
if err := unmarshaler.UnmarshalYAML([]byte(b)); err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
} else if unmarshaler, ok := dst.Addr().Interface().(ReserveUnmarshaler); ok {
|
2019-10-24 17:18:03 +09:00
|
|
|
if err := unmarshaler.UnmarshalYAML(func(v interface{}) error {
|
|
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
|
if rv.Type().Kind() != reflect.Ptr {
|
|
|
|
|
return errors.ErrDecodeRequiredPointerType
|
|
|
|
|
}
|
|
|
|
|
if err := d.decodeValue(rv.Elem(), src); err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to decode value")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}); err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to UnmarshalYAML")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
switch valueType.Kind() {
|
|
|
|
|
case reflect.Ptr:
|
2019-10-24 17:18:03 +09:00
|
|
|
if dst.IsNil() {
|
|
|
|
|
return nil
|
2019-10-21 14:54:26 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
v := d.createDecodableValue(dst.Type())
|
|
|
|
|
if err := d.decodeValue(v, src); err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to decode ptr value")
|
|
|
|
|
}
|
|
|
|
|
dst.Set(d.castToAssignableValue(v, dst.Type()))
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Interface:
|
2019-10-24 23:54:17 +09:00
|
|
|
v := reflect.ValueOf(d.nodeToValue(src))
|
2019-10-24 17:18:03 +09:00
|
|
|
if v.IsValid() {
|
|
|
|
|
dst.Set(v)
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Map:
|
2019-10-24 17:18:03 +09:00
|
|
|
return d.decodeMap(dst, src)
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Array, reflect.Slice:
|
2019-10-24 17:18:03 +09:00
|
|
|
return d.decodeSlice(dst, src)
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Struct:
|
2019-10-24 17:18:03 +09:00
|
|
|
return d.decodeStruct(dst, src)
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
v := reflect.ValueOf(d.nodeToValue(src))
|
2019-10-24 17:18:03 +09:00
|
|
|
if v.IsValid() {
|
|
|
|
|
dst.Set(v.Convert(dst.Type()))
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 17:18:03 +09:00
|
|
|
func (d *Decoder) createDecodableValue(typ reflect.Type) reflect.Value {
|
|
|
|
|
for {
|
|
|
|
|
if typ.Kind() == reflect.Ptr {
|
|
|
|
|
typ = typ.Elem()
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
return reflect.New(typ).Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) castToAssignableValue(value reflect.Value, target reflect.Type) reflect.Value {
|
|
|
|
|
if target.Kind() != reflect.Ptr {
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
maxTryCount := 5
|
|
|
|
|
tryCount := 0
|
|
|
|
|
for {
|
|
|
|
|
if tryCount > maxTryCount {
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
if value.Type().AssignableTo(target) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
value = value.Addr()
|
|
|
|
|
tryCount++
|
|
|
|
|
}
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) keyToNodeMap(node ast.Node) (map[string]ast.Node, error) {
|
|
|
|
|
mapNode, err := d.getMapNode(node)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "failed to get map node")
|
|
|
|
|
}
|
|
|
|
|
mapIter := mapNode.MapRange()
|
|
|
|
|
keyToNodeMap := map[string]ast.Node{}
|
|
|
|
|
for mapIter.Next() {
|
|
|
|
|
keyNode := mapIter.Key()
|
|
|
|
|
if keyNode.Type() == ast.MergeKeyType {
|
|
|
|
|
mergeMap, err := d.keyToNodeMap(mapIter.Value())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "failed to get keyToNodeMap by MergeKey node")
|
|
|
|
|
}
|
|
|
|
|
for k, v := range mergeMap {
|
|
|
|
|
keyToNodeMap[k] = v
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
key, ok := d.nodeToValue(keyNode).(string)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, errors.Wrapf(err, "failed to decode map key")
|
|
|
|
|
}
|
|
|
|
|
keyToNodeMap[key] = mapIter.Value()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return keyToNodeMap, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
|
2019-10-24 17:18:03 +09:00
|
|
|
if src == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
structType := dst.Type()
|
2019-10-18 12:55:38 +09:00
|
|
|
structValue := reflect.New(structType)
|
2019-10-19 18:28:36 +09:00
|
|
|
structFieldMap, err := structFieldMap(structType)
|
2019-10-18 12:55:38 +09:00
|
|
|
if err != nil {
|
2019-10-24 17:18:03 +09:00
|
|
|
return errors.Wrapf(err, "failed to create struct field map")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
keyToNodeMap, err := d.keyToNodeMap(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to get keyToNodeMap")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
|
|
|
|
for i := 0; i < structType.NumField(); i++ {
|
|
|
|
|
field := structType.Field(i)
|
2019-10-19 18:28:36 +09:00
|
|
|
if isIgnoredStructField(field) {
|
2019-10-18 12:55:38 +09:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
structField := structFieldMap[field.Name]
|
2019-10-24 23:54:17 +09:00
|
|
|
v, exists := keyToNodeMap[structField.RenderName]
|
2019-10-18 12:55:38 +09:00
|
|
|
if !exists {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fieldValue := structValue.Elem().FieldByName(field.Name)
|
2019-10-24 17:18:03 +09:00
|
|
|
newFieldValue := d.createDecodableValue(fieldValue.Type())
|
|
|
|
|
if err := d.decodeValue(newFieldValue, v); err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to decode value")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
fieldValue.Set(d.castToAssignableValue(newFieldValue, fieldValue.Type()))
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
dst.Set(structValue.Elem())
|
|
|
|
|
return nil
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) decodeSlice(dst reflect.Value, src ast.Node) error {
|
|
|
|
|
arrayNode, err := d.getArrayNode(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to get array node")
|
|
|
|
|
}
|
|
|
|
|
iter := arrayNode.ArrayRange()
|
2019-10-24 17:18:03 +09:00
|
|
|
sliceType := dst.Type()
|
2019-10-24 23:54:17 +09:00
|
|
|
sliceValue := reflect.MakeSlice(sliceType, 0, iter.Len())
|
2019-10-24 17:18:03 +09:00
|
|
|
elemType := sliceType.Elem()
|
2019-10-24 23:54:17 +09:00
|
|
|
for iter.Next() {
|
|
|
|
|
v := iter.Value()
|
2019-10-24 17:18:03 +09:00
|
|
|
dstValue := d.createDecodableValue(elemType)
|
|
|
|
|
if err := d.decodeValue(dstValue, v); err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to decode value")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
sliceValue = reflect.Append(sliceValue, d.castToAssignableValue(dstValue, elemType))
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
dst.Set(sliceValue)
|
|
|
|
|
return nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) decodeMap(dst reflect.Value, src ast.Node) error {
|
|
|
|
|
mapNode, err := d.getMapNode(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrapf(err, "failed to get map node")
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
mapType := dst.Type()
|
2019-10-18 00:00:58 +09:00
|
|
|
mapValue := reflect.MakeMap(mapType)
|
|
|
|
|
keyType := mapValue.Type().Key()
|
|
|
|
|
valueType := mapValue.Type().Elem()
|
2019-10-24 23:54:17 +09:00
|
|
|
mapIter := mapNode.MapRange()
|
|
|
|
|
for mapIter.Next() {
|
|
|
|
|
key := mapIter.Key()
|
|
|
|
|
value := mapIter.Value()
|
2019-10-24 17:18:03 +09:00
|
|
|
dstValue := d.createDecodableValue(valueType)
|
2019-10-24 23:54:17 +09:00
|
|
|
if err := d.decodeValue(dstValue, value); err != nil {
|
2019-10-24 17:18:03 +09:00
|
|
|
return errors.Wrapf(err, "failed to decode value")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
castedKey := reflect.ValueOf(d.nodeToValue(key)).Convert(keyType)
|
2019-10-24 17:18:03 +09:00
|
|
|
mapValue.SetMapIndex(castedKey, d.castToAssignableValue(dstValue, valueType))
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
dst.Set(mapValue)
|
|
|
|
|
return nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-18 15:20:09 +09:00
|
|
|
func (d *Decoder) fileToReader(file string) (io.Reader, error) {
|
|
|
|
|
reader, err := os.Open(file)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return nil, errors.Wrapf(err, "failed to open file")
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-18 15:20:09 +09:00
|
|
|
return reader, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) isYAMLFile(file string) bool {
|
|
|
|
|
ext := filepath.Ext(file)
|
|
|
|
|
if ext == ".yml" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if ext == ".yaml" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) readersUnderDir(dir string) ([]io.Reader, error) {
|
|
|
|
|
pattern := fmt.Sprintf("%s/*", dir)
|
|
|
|
|
matches, err := filepath.Glob(pattern)
|
2019-10-18 00:00:58 +09:00
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return nil, errors.Wrapf(err, "failed to get files by %s", pattern)
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
readers := []io.Reader{}
|
|
|
|
|
for _, match := range matches {
|
|
|
|
|
if !d.isYAMLFile(match) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
reader, err := d.fileToReader(match)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return nil, errors.Wrapf(err, "failed to get reader")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
readers = append(readers, reader)
|
|
|
|
|
}
|
|
|
|
|
return readers, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) readersUnderDirRecursive(dir string) ([]io.Reader, error) {
|
|
|
|
|
readers := []io.Reader{}
|
|
|
|
|
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
|
|
|
if !d.isYAMLFile(path) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
reader, err := d.fileToReader(path)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to get reader")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
readers = append(readers, reader)
|
|
|
|
|
return nil
|
|
|
|
|
}); err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return nil, errors.Wrapf(err, "interrupt walk in %s", dir)
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
return readers, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) resolveReference() error {
|
|
|
|
|
for _, opt := range d.opts {
|
|
|
|
|
if err := opt(d); err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to exec option")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, file := range d.referenceFiles {
|
|
|
|
|
reader, err := d.fileToReader(file)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to get reader")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
d.referenceReaders = append(d.referenceReaders, reader)
|
|
|
|
|
}
|
|
|
|
|
for _, dir := range d.referenceDirs {
|
|
|
|
|
if !d.isRecursiveDir {
|
|
|
|
|
readers, err := d.readersUnderDir(dir)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to get readers from under the %s", dir)
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
d.referenceReaders = append(d.referenceReaders, readers...)
|
|
|
|
|
} else {
|
|
|
|
|
readers, err := d.readersUnderDirRecursive(dir)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to get readers from under the %s", dir)
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
d.referenceReaders = append(d.referenceReaders, readers...)
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-18 15:20:09 +09:00
|
|
|
for _, reader := range d.referenceReaders {
|
|
|
|
|
bytes, err := ioutil.ReadAll(reader)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to read buffer")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assign new anchor definition to anchorMap
|
|
|
|
|
if _, err := d.decode(bytes); err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to decode")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
d.isResolvedReference = true
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) decode(bytes []byte) (ast.Node, error) {
|
2019-10-18 00:00:58 +09:00
|
|
|
var (
|
|
|
|
|
parser parser.Parser
|
|
|
|
|
)
|
2019-10-21 12:53:30 +09:00
|
|
|
tokens := lexer.Tokenize(string(bytes))
|
2019-10-18 00:00:58 +09:00
|
|
|
doc, err := parser.Parse(tokens)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return nil, errors.Wrapf(err, "failed to parse yaml")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
return d.docToNode(doc), nil
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// Decode reads the next YAML-encoded value from its input
|
|
|
|
|
// and stores it in the value pointed to by v.
|
|
|
|
|
//
|
|
|
|
|
// See the documentation for Unmarshal for details about the
|
|
|
|
|
// conversion of YAML into a Go value.
|
2019-10-18 15:20:09 +09:00
|
|
|
func (d *Decoder) Decode(v interface{}) error {
|
|
|
|
|
if !d.isResolvedReference {
|
|
|
|
|
if err := d.resolveReference(); err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to resolve reference")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
|
if rv.Type().Kind() != reflect.Ptr {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.ErrDecodeRequiredPointerType
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
bytes, err := ioutil.ReadAll(d.reader)
|
|
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to read buffer")
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
node, err := d.decode(bytes)
|
2019-10-18 15:20:09 +09:00
|
|
|
if err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to decode")
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
if node == nil {
|
2019-10-18 00:00:58 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
if err := d.decodeValue(rv.Elem(), node); err != nil {
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to decode value")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
return nil
|
|
|
|
|
}
|