yq/pkg/yqlib/treeops/lib.go

160 lines
4.5 KiB
Go
Raw Normal View History

2020-10-08 23:59:03 +00:00
package treeops
import (
"bytes"
"fmt"
2020-10-10 11:42:09 +00:00
"github.com/elliotchance/orderedmap"
2020-10-08 23:59:03 +00:00
"gopkg.in/op/go-logging.v1"
"gopkg.in/yaml.v3"
)
2020-10-10 04:00:39 +00:00
var log = logging.MustGetLogger("yq-treeops")
2020-10-11 23:44:33 +00:00
type PathElementType uint32
const (
PathKey PathElementType = 1 << iota
Operation
SelfReference
OpenBracket
CloseBracket
2020-10-16 01:29:26 +00:00
OpenCollect
CloseCollect
Value // e.g. string, int
2020-10-11 23:44:33 +00:00
)
type OperationType struct {
Type string
NumArgs uint // number of arguments to the op
Precedence uint
Handler OperatorHandler
}
var None = &OperationType{Type: "NONE", NumArgs: 0, Precedence: 0}
2020-10-16 01:29:26 +00:00
2020-10-17 11:10:47 +00:00
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator}
var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOperator}
var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
var Intersection = &OperationType{Type: "INTERSECTION", NumArgs: 2, Precedence: 20, Handler: IntersectionOperator}
2020-10-16 01:29:26 +00:00
2020-10-13 03:37:01 +00:00
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignOperator}
2020-10-16 01:29:26 +00:00
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: EqualsOperator}
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: LengthOperator}
2020-10-17 11:10:47 +00:00
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
2020-10-11 23:44:33 +00:00
2020-10-16 01:29:26 +00:00
// not sure yet
2020-10-17 11:10:47 +00:00
var Select = &OperationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: SelectOperator}
2020-10-16 01:29:26 +00:00
var DeleteChild = &OperationType{Type: "DELETE", NumArgs: 2, Precedence: 40, Handler: DeleteChildOperator}
2020-10-12 01:24:59 +00:00
2020-10-16 01:29:26 +00:00
// var Splat = &OperationType{Type: "SPLAT", NumArgs: 0, Precedence: 40, Handler: SplatOperator}
2020-10-12 01:24:59 +00:00
// var Exists = &OperationType{Type: "Length", NumArgs: 2, Precedence: 35}
// filters matches if they have the existing path
2020-10-11 23:44:33 +00:00
type PathElement struct {
PathElementType PathElementType
OperationType *OperationType
Value interface{}
StringValue string
}
// debugging purposes only
func (p *PathElement) toString() string {
var result string = ``
switch p.PathElementType {
case PathKey:
2020-10-17 11:10:47 +00:00
result = result + fmt.Sprintf("%v", p.Value)
2020-10-11 23:44:33 +00:00
case SelfReference:
2020-10-16 01:29:26 +00:00
result = result + fmt.Sprintf("SELF")
2020-10-11 23:44:33 +00:00
case Operation:
2020-10-17 11:10:47 +00:00
result = result + fmt.Sprintf("%v", p.OperationType.Type)
2020-10-16 01:29:26 +00:00
case Value:
2020-10-17 11:10:47 +00:00
result = result + fmt.Sprintf("%v (%T)", p.Value, p.Value)
2020-10-16 01:29:26 +00:00
default:
result = result + "I HAVENT GOT A STRATEGY"
2020-10-11 23:44:33 +00:00
}
return result
}
2020-10-10 04:00:39 +00:00
type YqTreeLib interface {
2020-10-13 01:51:37 +00:00
Get(document int, documentNode *yaml.Node, path string) ([]*CandidateNode, error)
2020-10-10 04:00:39 +00:00
// GetForMerge(rootNode *yaml.Node, path string, arrayMergeStrategy ArrayMergeStrategy) ([]*NodeContext, error)
// Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error
// New(path string) yaml.Node
// PathStackToString(pathStack []interface{}) string
// MergePathStackToString(pathStack []interface{}, arrayMergeStrategy ArrayMergeStrategy) string
}
2020-10-13 01:51:37 +00:00
func NewYqTreeLib() YqTreeLib {
return &lib{treeCreator: NewPathTreeCreator()}
}
2020-10-10 04:00:39 +00:00
type lib struct {
treeCreator PathTreeCreator
}
2020-10-08 23:59:03 +00:00
2020-10-13 01:51:37 +00:00
func (l *lib) Get(document int, documentNode *yaml.Node, path string) ([]*CandidateNode, error) {
nodes := []*CandidateNode{&CandidateNode{Node: documentNode.Content[0], Document: 0}}
navigator := NewDataTreeNavigator(NavigationPrefs{})
pathNode, errPath := l.treeCreator.ParsePath(path)
if errPath != nil {
return nil, errPath
}
return navigator.GetMatchingNodes(nodes, pathNode)
}
2020-10-10 11:42:09 +00:00
//use for debugging only
func NodesToString(collection *orderedmap.OrderedMap) string {
if !log.IsEnabledFor(logging.DEBUG) {
return ""
}
result := ""
for el := collection.Front(); el != nil; el = el.Next() {
result = result + "\n" + NodeToString(el.Value.(*CandidateNode))
}
return result
}
2020-10-08 23:59:03 +00:00
func NodeToString(node *CandidateNode) string {
if !log.IsEnabledFor(logging.DEBUG) {
return ""
}
value := node.Node
if value == nil {
2020-10-17 11:10:47 +00:00
return "-- nil --"
2020-10-08 23:59:03 +00:00
}
buf := new(bytes.Buffer)
encoder := yaml.NewEncoder(buf)
errorEncoding := encoder.Encode(value)
if errorEncoding != nil {
log.Error("Error debugging node, %v", errorEncoding.Error())
}
encoder.Close()
2020-10-17 11:10:47 +00:00
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.Path, value.Tag, buf.String())
2020-10-08 23:59:03 +00:00
}
func KindString(kind yaml.Kind) string {
switch kind {
case yaml.ScalarNode:
return "ScalarNode"
case yaml.SequenceNode:
return "SequenceNode"
case yaml.MappingNode:
return "MappingNode"
case yaml.DocumentNode:
return "DocumentNode"
case yaml.AliasNode:
return "AliasNode"
default:
return "unknown!"
}
}