/
yaml_helpers.go
91 lines (76 loc) · 2.93 KB
/
yaml_helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package secret
import (
"bytes"
"fmt"
yaml_v3 "gopkg.in/yaml.v3"
)
func MergeEncodedYaml(oldData, newData, oldEncodedData, newEncodedData []byte) ([]byte, error) {
var oldConfig, newConfig, oldEncodedConfig, newEncodedConfig yaml_v3.Node
for _, d := range []struct {
Data []byte
Node *yaml_v3.Node
}{
{Data: oldData, Node: &oldConfig},
{Data: newData, Node: &newConfig},
{Data: oldEncodedData, Node: &oldEncodedConfig},
{Data: newEncodedData, Node: &newEncodedConfig},
} {
if err := yaml_v3.Unmarshal(d.Data, d.Node); err != nil {
return nil, fmt.Errorf("unable to unmarshal yaml data: %w", err)
}
}
mergedNode, err := MergeEncodedYamlNode(&oldConfig, &newConfig, &oldEncodedConfig, &newEncodedConfig)
if err != nil {
return nil, err
}
var resultData bytes.Buffer
yamlEncoder := yaml_v3.NewEncoder(&resultData)
yamlEncoder.SetIndent(2)
if err := yamlEncoder.Encode(mergedNode); err != nil {
return nil, fmt.Errorf("unable to marshal merged encoded data: %w", err)
}
return resultData.Bytes(), nil
}
func MergeEncodedYamlNode(oldConfig, newConfig, oldEncodedConfig, newEncodedConfig *yaml_v3.Node) (*yaml_v3.Node, error) {
if newConfig.Kind != oldConfig.Kind {
return newEncodedConfig, nil
}
switch newEncodedConfig.Kind {
case yaml_v3.DocumentNode:
for pos := 0; pos < len(newEncodedConfig.Content); pos += 1 {
newValueNode, err := MergeEncodedYamlNode(oldConfig.Content[pos], newConfig.Content[pos], oldEncodedConfig.Content[pos], newEncodedConfig.Content[pos])
if err != nil {
return nil, fmt.Errorf("unable to process document key %d: %w", pos, err)
}
newEncodedConfig.Content[pos] = newValueNode
}
case yaml_v3.MappingNode:
for pos := 0; pos < len(newEncodedConfig.Content); pos += 2 {
newValueNode, err := MergeEncodedYamlNode(oldConfig.Content[pos+1], newConfig.Content[pos+1], oldEncodedConfig.Content[pos+1], newEncodedConfig.Content[pos+1])
if err != nil {
return nil, fmt.Errorf("unable to process map key %q: %w", newEncodedConfig.Content[pos].Value, err)
}
newEncodedConfig.Content[pos+1] = newValueNode
}
case yaml_v3.SequenceNode:
for pos := 0; pos < len(newEncodedConfig.Content); pos += 1 {
newValueNode, err := MergeEncodedYamlNode(oldConfig.Content[pos], newConfig.Content[pos], oldEncodedConfig.Content[pos], newEncodedConfig.Content[pos])
if err != nil {
return nil, fmt.Errorf("unable to process array key %d: %w", pos, err)
}
newEncodedConfig.Content[pos] = newValueNode
}
case yaml_v3.AliasNode:
newAliasNode, err := MergeEncodedYamlNode(oldConfig.Alias, newConfig.Alias, oldEncodedConfig.Alias, newEncodedConfig.Alias)
if err != nil {
return nil, fmt.Errorf("unable to process an alias node %q: %w", newEncodedConfig.Value, err)
}
newEncodedConfig.Alias = newAliasNode
case yaml_v3.ScalarNode:
if oldConfig.Value == newConfig.Value {
return oldEncodedConfig, nil
}
return newEncodedConfig, nil
}
return newEncodedConfig, nil
}