Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(!local): local nodes must be removed from source before merge #172

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 35 additions & 29 deletions internal/yml/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ func Merge(dst, src *yaml.Node) *yaml.Node {
}()

dst = unwrapDocument(dst)
src = markLockedValuesAsTodo(unwrapDocument(src), false)

src = unwrapDocument(src)
src = markLockedValuesAsTodo(src, false)
src = purgeLocalContent(src)

result := merge(dst, src)
if result == nil {
Expand Down Expand Up @@ -79,39 +82,14 @@ func mergeMap(dst, src *yaml.Node) *yaml.Node {

func mergeSeq(dst, src *yaml.Node) *yaml.Node {
var (
srcIdx int
dstIdx int
maxLen = max(len(dst.Content), len(src.Content))
content []*yaml.Node
)
for {
// If we have moved past both the source and dst length we must end the loop unless
// we want to go to infinity and beyond!
if srcIdx >= len(src.Content) && dstIdx >= len(dst.Content) {
break
}

// For the destination if the item is local we want to add it to the result, but move the dstIdx
// forward until we find a non local element to merge with.
for {
item := at(dst, dstIdx)
if !isLocal(item) {
break
}
content = append(content, item)
dstIdx++
}

// ignore local source elements and find the first non local idx.
for isLocal(at(src, srcIdx)) {
srcIdx++
}

if value := merge(at(dst, dstIdx), at(src, srcIdx)); value != nil {
for i := 0; i < maxLen; i++ {
if value := merge(at(dst, i), at(src, i)); value != nil {
content = append(content, value)
}

srcIdx++
dstIdx++
}

dst.Content = content
Expand Down Expand Up @@ -236,3 +214,31 @@ func firstNonNil(nodes ...*yaml.Node) *yaml.Node {
}
return nil
}

func purgeLocalContent(node *yaml.Node) *yaml.Node {
if node == nil || isLocal(node) {
return nil
}

copy := *node
copy.Content = nil

switch node.Kind {
case yaml.MappingNode:
for i := 0; i < len(node.Content); i += 2 {
if isLocal(node.Content[i+1]) {
continue
}
copy.Content = append(copy.Content, node.Content[i], purgeLocalContent(node.Content[i+1]))
}
case yaml.SequenceNode:
for _, item := range node.Content {
if isLocal(item) {
continue
}
copy.Content = append(copy.Content, purgeLocalContent(item))
}
}

return &copy
}
6 changes: 6 additions & 0 deletions internal/yml/merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,12 @@ func TestYmlMerge(t *testing.T) {
Dst: "[4, 5, 6, !local 7]",
Expected: "[1, 3, !local 7]",
},
{
Name: "nested local must not be ported",
Src: "{ outer: { inner: !local value } }",
Dst: "{}",
Expected: "{outer: {}}",
},
}

for _, tc := range cases {
Expand Down
Loading