-
Notifications
You must be signed in to change notification settings - Fork 136
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #550 from vmware-tanzu/map-key-override-in-plain-yml
(re)enable map key override for plain YAML
- Loading branch information
Showing
7 changed files
with
212 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright 2020 VMware, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package yamlmeta | ||
|
||
import ( | ||
"github.com/k14s/ytt/pkg/orderedmap" | ||
) | ||
|
||
type overrideMapKeys struct{} | ||
|
||
// Visit if `node` is a Map, among its MapItem's that have duplicate keys, removes all but the last. | ||
// This visitor always returns `nil` | ||
func (r *overrideMapKeys) Visit(node Node) error { | ||
mapNode, isMap := node.(*Map) | ||
if !isMap { | ||
return nil | ||
} | ||
|
||
lastItems := orderedmap.NewMap() | ||
for _, item := range mapNode.Items { | ||
lastItems.Set(item.Key, item) | ||
} | ||
|
||
var newItems []*MapItem | ||
lastItems.Iterate(func(_, value interface{}) { | ||
newItems = append(newItems, value.(*MapItem)) | ||
}) | ||
mapNode.Items = newItems | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Copyright 2020 VMware, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package yamlmeta_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/k14s/ytt/pkg/yamlmeta" | ||
) | ||
|
||
func TestMapKeyOverridePlainYAML(t *testing.T) { | ||
t.Run("when no maps have duplicate keys, is a no op", func(t *testing.T) { | ||
docSet := &yamlmeta.DocumentSet{ | ||
Items: []*yamlmeta.Document{{ | ||
Value: &yamlmeta.Map{ | ||
Items: []*yamlmeta.MapItem{ | ||
{Key: "foo", Value: 1}, | ||
{Key: "bar", Value: 2}, | ||
}, | ||
}, | ||
}}, | ||
} | ||
expectedDocSet := docSet.DeepCopyAsNode() | ||
docSet.OverrideMapKeys() | ||
|
||
printer := yamlmeta.NewPrinterWithOpts(nil, yamlmeta.PrinterOpts{ExcludeRefs: true}) | ||
|
||
result := printer.PrintStr(docSet) | ||
expected := printer.PrintStr(expectedDocSet) | ||
assertEqual(t, result, expected) | ||
}) | ||
t.Run("when there are duplicates, last map item overrides", func(t *testing.T) { | ||
docSet := &yamlmeta.DocumentSet{ | ||
Items: []*yamlmeta.Document{{ | ||
Value: &yamlmeta.Map{ | ||
Items: []*yamlmeta.MapItem{ | ||
{Key: "foo", Value: 1}, | ||
{Key: "foo", Value: 2}, | ||
{Key: "foo", Value: 3}, | ||
{Key: "foo", Value: 4}, | ||
}, | ||
}, | ||
}}, | ||
} | ||
expectedDocSet := &yamlmeta.DocumentSet{ | ||
Items: []*yamlmeta.Document{{ | ||
Value: &yamlmeta.Map{ | ||
Items: []*yamlmeta.MapItem{ | ||
{Key: "foo", Value: 4}, | ||
}, | ||
}, | ||
}}, | ||
} | ||
docSet.OverrideMapKeys() | ||
|
||
printer := yamlmeta.NewPrinterWithOpts(nil, yamlmeta.PrinterOpts{ExcludeRefs: true}) | ||
|
||
result := printer.PrintStr(docSet) | ||
expected := printer.PrintStr(expectedDocSet) | ||
assertEqual(t, result, expected) | ||
}) | ||
t.Run("when there are multiple keys with duplicates, last map item for each key overrides the others", func(t *testing.T) { | ||
docSet := &yamlmeta.DocumentSet{ | ||
Items: []*yamlmeta.Document{{ | ||
Value: &yamlmeta.Map{ | ||
Items: []*yamlmeta.MapItem{ | ||
{Key: "foo", Value: 1}, | ||
{Key: "bar", Value: 2}, | ||
{Key: "ree", Value: 3}, | ||
{Key: "ree", Value: 4}, | ||
{Key: "foo", Value: 5}, | ||
{Key: "bar", Value: 6}, | ||
}, | ||
}, | ||
}}, | ||
} | ||
expectedDocSet := &yamlmeta.DocumentSet{ | ||
Items: []*yamlmeta.Document{{ | ||
Value: &yamlmeta.Map{ | ||
Items: []*yamlmeta.MapItem{ | ||
{Key: "foo", Value: 5}, | ||
{Key: "bar", Value: 6}, | ||
{Key: "ree", Value: 4}, | ||
}, | ||
}, | ||
}}, | ||
} | ||
docSet.OverrideMapKeys() | ||
|
||
printer := yamlmeta.NewPrinterWithOpts(nil, yamlmeta.PrinterOpts{ExcludeRefs: true}) | ||
|
||
result := printer.PrintStr(docSet) | ||
expected := printer.PrintStr(expectedDocSet) | ||
assertEqual(t, result, expected) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2020 VMware, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package yamlmeta | ||
|
||
// Visitor performs an operation on the given Node while traversing the AST. | ||
// Typically defines the action taken during a Walk(). | ||
type Visitor interface { | ||
Visit(Node) error | ||
} | ||
|
||
// Walk traverses the tree starting at `n`, recursively, depth-first, invoking `v` on each node. | ||
// if `v` returns non-nil error, the traversal is aborted. | ||
func Walk(n Node, v Visitor) error { | ||
err := v.Visit(n) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, c := range n.GetValues() { | ||
if cn, ok := c.(Node); ok { | ||
err := Walk(cn, v) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
return nil | ||
} |