yq/pkg/yqlib/operator_anchors_aliases.go

264 lines
7.3 KiB
Go
Raw Permalink Normal View History

2020-11-03 23:48:43 +00:00
package yqlib
2020-11-02 00:20:38 +00:00
import (
"container/list"
2021-01-06 09:30:48 +00:00
yaml "gopkg.in/yaml.v3"
2020-11-02 00:20:38 +00:00
)
func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("AssignAlias operator!")
aliasName := ""
2021-01-12 23:18:53 +00:00
if !expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
2021-01-06 09:30:48 +00:00
if err != nil {
return Context{}, err
2021-01-06 09:30:48 +00:00
}
if rhs.MatchingNodes.Front() != nil {
aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value
2021-01-06 09:30:48 +00:00
}
}
lhs, err := d.GetMatchingNodes(context, expressionNode.Lhs)
if err != nil {
return Context{}, err
}
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
log.Debugf("Setting aliasName : %v", candidate.GetKey())
2021-01-06 09:30:48 +00:00
2021-01-12 23:18:53 +00:00
if expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
2021-01-06 09:30:48 +00:00
if err != nil {
return Context{}, err
2021-01-06 09:30:48 +00:00
}
if rhs.MatchingNodes.Front() != nil {
aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value
2021-01-06 09:30:48 +00:00
}
}
if aliasName != "" {
candidate.Node.Kind = yaml.AliasNode
candidate.Node.Value = aliasName
}
}
return context, nil
}
func getAliasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("GetAlias operator!")
var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
node := &yaml.Node{Kind: yaml.ScalarNode, Value: candidate.Node.Value, Tag: "!!str"}
result := candidate.CreateChild(nil, node)
results.PushBack(result)
}
return context.ChildContext(results), nil
}
func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("AssignAnchor operator!")
anchorName := ""
2021-01-12 23:18:53 +00:00
if !expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
2021-01-06 09:30:48 +00:00
if err != nil {
return Context{}, err
2021-01-06 09:30:48 +00:00
}
if rhs.MatchingNodes.Front() != nil {
anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value
2021-01-06 09:30:48 +00:00
}
}
lhs, err := d.GetMatchingNodes(context, expressionNode.Lhs)
if err != nil {
return Context{}, err
}
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
log.Debugf("Setting anchorName of : %v", candidate.GetKey())
2021-01-06 09:30:48 +00:00
2021-01-12 23:18:53 +00:00
if expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
2021-01-06 09:30:48 +00:00
if err != nil {
return Context{}, err
2021-01-06 09:30:48 +00:00
}
if rhs.MatchingNodes.Front() != nil {
anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value
2021-01-06 09:30:48 +00:00
}
}
candidate.Node.Anchor = anchorName
}
return context, nil
}
func getAnchorOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("GetAnchor operator!")
var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
anchor := candidate.Node.Anchor
node := &yaml.Node{Kind: yaml.ScalarNode, Value: anchor, Tag: "!!str"}
result := candidate.CreateChild(nil, node)
results.PushBack(result)
}
return context.ChildContext(results), nil
}
func explodeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
2020-11-02 00:20:38 +00:00
log.Debugf("-- ExplodeOperation")
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
2020-11-02 00:20:38 +00:00
candidate := el.Value.(*CandidateNode)
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs)
2020-11-02 00:20:38 +00:00
if err != nil {
return Context{}, err
2020-11-02 00:20:38 +00:00
}
for childEl := rhs.MatchingNodes.Front(); childEl != nil; childEl = childEl.Next() {
err = explodeNode(childEl.Value.(*CandidateNode).Node, context)
2020-11-13 03:07:11 +00:00
if err != nil {
return Context{}, err
2020-11-13 03:07:11 +00:00
}
2020-11-02 00:20:38 +00:00
}
}
return context, nil
2020-11-02 00:20:38 +00:00
}
func explodeNode(node *yaml.Node, context Context) error {
2020-11-02 00:20:38 +00:00
node.Anchor = ""
switch node.Kind {
case yaml.SequenceNode, yaml.DocumentNode:
for index, contentNode := range node.Content {
log.Debugf("exploding index %v", index)
errorInContent := explodeNode(contentNode, context)
2020-11-02 00:20:38 +00:00
if errorInContent != nil {
return errorInContent
}
}
return nil
case yaml.AliasNode:
log.Debugf("its an alias!")
if node.Alias != nil {
node.Kind = node.Alias.Kind
node.Style = node.Alias.Style
node.Tag = node.Alias.Tag
node.Content = node.Alias.Content
node.Value = node.Alias.Value
node.Alias = nil
}
return nil
case yaml.MappingNode:
2020-11-02 02:43:45 +00:00
var newContent = list.New()
2020-11-02 00:20:38 +00:00
for index := 0; index < len(node.Content); index = index + 2 {
keyNode := node.Content[index]
valueNode := node.Content[index+1]
log.Debugf("traversing %v", keyNode.Value)
if keyNode.Value != "<<" {
err := overrideEntry(node, keyNode, valueNode, index, context.ChildContext(newContent))
2020-11-02 02:43:45 +00:00
if err != nil {
return err
2020-11-02 00:20:38 +00:00
}
} else {
if valueNode.Kind == yaml.SequenceNode {
log.Debugf("an alias merge list!")
2021-05-09 03:26:02 +00:00
for index := len(valueNode.Content) - 1; index >= 0; index = index - 1 {
2020-11-02 00:20:38 +00:00
aliasNode := valueNode.Content[index]
err := applyAlias(node, aliasNode.Alias, index, context.ChildContext(newContent))
2020-11-13 03:07:11 +00:00
if err != nil {
return err
}
2020-11-02 00:20:38 +00:00
}
} else {
log.Debugf("an alias merge!")
err := applyAlias(node, valueNode.Alias, index, context.ChildContext(newContent))
2020-11-13 03:07:11 +00:00
if err != nil {
return err
}
2020-11-02 00:20:38 +00:00
}
}
}
2020-11-02 02:43:45 +00:00
node.Content = make([]*yaml.Node, newContent.Len())
index := 0
for newEl := newContent.Front(); newEl != nil; newEl = newEl.Next() {
node.Content[index] = newEl.Value.(*yaml.Node)
index++
}
2020-11-02 00:20:38 +00:00
return nil
default:
return nil
}
}
func applyAlias(node *yaml.Node, alias *yaml.Node, aliasIndex int, newContent Context) error {
2020-11-02 00:20:38 +00:00
if alias == nil {
2020-11-02 02:43:45 +00:00
return nil
2020-11-02 00:20:38 +00:00
}
for index := 0; index < len(alias.Content); index = index + 2 {
keyNode := alias.Content[index]
log.Debugf("applying alias key %v", keyNode.Value)
valueNode := alias.Content[index+1]
2020-11-02 02:43:45 +00:00
err := overrideEntry(node, keyNode, valueNode, aliasIndex, newContent)
if err != nil {
return err
}
2020-11-02 00:20:38 +00:00
}
2020-11-02 02:43:45 +00:00
return nil
2020-11-02 00:20:38 +00:00
}
func overrideEntry(node *yaml.Node, key *yaml.Node, value *yaml.Node, startIndex int, newContent Context) error {
2020-11-02 02:43:45 +00:00
err := explodeNode(value, newContent)
2020-11-02 02:43:45 +00:00
if err != nil {
return err
}
for newEl := newContent.MatchingNodes.Front(); newEl != nil; newEl = newEl.Next() {
2020-11-02 02:43:45 +00:00
valueEl := newEl.Next() // move forward twice
keyNode := newEl.Value.(*yaml.Node)
log.Debugf("checking new content %v:%v", keyNode.Value, valueEl.Value.(*yaml.Node).Value)
if keyNode.Value == key.Value && keyNode.Alias == nil && key.Alias == nil {
log.Debugf("overridign new content")
valueEl.Value = value
return nil
}
newEl = valueEl // move forward twice
}
for index := startIndex + 2; index < len(node.Content); index = index + 2 {
2020-11-02 00:20:38 +00:00
keyNode := node.Content[index]
2020-11-02 02:43:45 +00:00
if keyNode.Value == key.Value && keyNode.Alias == nil {
log.Debugf("content will be overridden at index %v", index)
return nil
2020-11-02 00:20:38 +00:00
}
}
2020-11-02 02:43:45 +00:00
err = explodeNode(key, newContent)
2020-11-02 02:43:45 +00:00
if err != nil {
return err
}
log.Debugf("adding %v:%v", key.Value, value.Value)
newContent.MatchingNodes.PushBack(key)
newContent.MatchingNodes.PushBack(value)
2020-11-02 02:43:45 +00:00
return nil
2020-11-02 00:20:38 +00:00
}