Can overwrite arrays when merging

This commit is contained in:
Mike Farah 2020-07-17 13:07:32 +10:00
parent ee07edbd88
commit 2fc39b3865
5 changed files with 83 additions and 7 deletions

View File

@ -27,6 +27,7 @@ var indent = 2
var overwriteFlag = false var overwriteFlag = false
var autoCreateFlag = true var autoCreateFlag = true
var appendFlag = false var appendFlag = false
var overwriteArrays = false
var verbose = false var verbose = false
var version = false var version = false
var docIndex = "0" var docIndex = "0"

View File

@ -34,6 +34,7 @@ If append flag is set then existing arrays will be merged with the arrays from e
cmdMerge.PersistentFlags().BoolVarP(&autoCreateFlag, "autocreate", "c", true, "automatically create any missing entries") cmdMerge.PersistentFlags().BoolVarP(&autoCreateFlag, "autocreate", "c", true, "automatically create any missing entries")
cmdMerge.PersistentFlags().BoolVarP(&appendFlag, "append", "a", false, "update the yaml file by appending array values") cmdMerge.PersistentFlags().BoolVarP(&appendFlag, "append", "a", false, "update the yaml file by appending array values")
cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
cmdMerge.PersistentFlags().BoolVarP(&overwriteArrays, "overwriteArrays", "", false, "overwrite arrays rather than update recursively")
return cmdMerge return cmdMerge
} }
@ -43,7 +44,7 @@ If append flag is set then existing arrays will be merged with the arrays from e
*/ */
func createReadFunctionForMerge() func(*yaml.Node) ([]*yqlib.NodeContext, error) { func createReadFunctionForMerge() func(*yaml.Node) ([]*yqlib.NodeContext, error) {
return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) { return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) {
return lib.GetForMerge(dataBucket, "**", !appendFlag) return lib.GetForMerge(dataBucket, "**", !appendFlag, overwriteArrays)
} }
} }
@ -76,7 +77,7 @@ func mergeProperties(cmd *cobra.Command, args []string) error {
Value: matchingNode.Node, Value: matchingNode.Node,
Overwrite: overwriteFlag, Overwrite: overwriteFlag,
// dont update the content for nodes midway, only leaf nodes // dont update the content for nodes midway, only leaf nodes
DontUpdateNodeContent: matchingNode.IsMiddleNode, DontUpdateNodeContent: matchingNode.IsMiddleNode && (!overwriteArrays || matchingNode.Node.Kind != yaml.SequenceNode),
}) })
} }
} }

View File

@ -68,6 +68,33 @@ c:
test.AssertResult(t, expectedOutput, result.Output) test.AssertResult(t, expectedOutput, result.Output)
} }
func TestMergeOverwriteDeepExampleCmd(t *testing.T) {
content := `c:
test: 1
thing: whatever
`
filename := test.WriteTempYamlFile(content)
defer test.RemoveTempYamlFile(filename)
mergeContent := `c:
test: 5
`
mergeFilename := test.WriteTempYamlFile(mergeContent)
defer test.RemoveTempYamlFile(mergeFilename)
cmd := getRootCommand()
result := test.RunCmd(cmd, fmt.Sprintf("merge --autocreate=false --overwrite %s %s", filename, mergeFilename))
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `c:
test: 5
thing: whatever
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestMergeAppendCmd(t *testing.T) { func TestMergeAppendCmd(t *testing.T) {
cmd := getRootCommand() cmd := getRootCommand()
result := test.RunCmd(cmd, "merge --autocreate=false --append ../examples/data1.yaml ../examples/data2.yaml") result := test.RunCmd(cmd, "merge --autocreate=false --append ../examples/data1.yaml ../examples/data2.yaml")
@ -166,7 +193,35 @@ c:
test.AssertResult(t, expectedOutput, result.Output) test.AssertResult(t, expectedOutput, result.Output)
} }
func TestMergeArraysCmd(t *testing.T) { func TestMergeOverwriteArraysTooCmd(t *testing.T) {
content := `a: simple # just the best
b: [1, 2]
c:
test: 1
`
filename := test.WriteTempYamlFile(content)
defer test.RemoveTempYamlFile(filename)
mergeContent := `a: things
b: [6]`
mergeFilename := test.WriteTempYamlFile(mergeContent)
defer test.RemoveTempYamlFile(mergeFilename)
cmd := getRootCommand()
result := test.RunCmd(cmd, fmt.Sprintf("merge --autocreate=false --overwriteArrays --overwrite %s %s", filename, mergeFilename))
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `a: things
b: [6]
c:
test: 1
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestMergeRootArraysCmd(t *testing.T) {
cmd := getRootCommand() cmd := getRootCommand()
result := test.RunCmd(cmd, "merge --append ../examples/sample_array.yaml ../examples/sample_array_2.yaml") result := test.RunCmd(cmd, "merge --append ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
if result.Error != nil { if result.Error != nil {
@ -181,6 +236,18 @@ func TestMergeArraysCmd(t *testing.T) {
test.AssertResult(t, expectedOutput, result.Output) test.AssertResult(t, expectedOutput, result.Output)
} }
func TestMergeOverwriteArraysCmd(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "merge --overwriteArrays ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `- 4
- 5
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestMergeCmd_Multi(t *testing.T) { func TestMergeCmd_Multi(t *testing.T) {
cmd := getRootCommand() cmd := getRootCommand()
result := test.RunCmd(cmd, "merge -d1 ../examples/multiple_docs_small.yaml ../examples/data1.yaml") result := test.RunCmd(cmd, "merge -d1 ../examples/multiple_docs_small.yaml ../examples/data1.yaml")

View File

@ -136,7 +136,7 @@ func guessKind(head interface{}, tail []interface{}, guess yaml.Kind) yaml.Kind
type YqLib interface { type YqLib interface {
Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error)
GetForMerge(rootNode *yaml.Node, path string, deeplyTraverseArrays bool) ([]*NodeContext, error) GetForMerge(rootNode *yaml.Node, path string, deeplyTraverseArrays bool, overwriteArray bool) ([]*NodeContext, error)
Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error
New(path string) yaml.Node New(path string) yaml.Node
@ -162,9 +162,9 @@ func (l *lib) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) {
return navigationStrategy.GetVisitedNodes(), error return navigationStrategy.GetVisitedNodes(), error
} }
func (l *lib) GetForMerge(rootNode *yaml.Node, path string, deeplyTraverseArrays bool) ([]*NodeContext, error) { func (l *lib) GetForMerge(rootNode *yaml.Node, path string, deeplyTraverseArrays bool, overwriteArray bool) ([]*NodeContext, error) {
var paths = l.parser.ParsePath(path) var paths = l.parser.ParsePath(path)
navigationStrategy := ReadForMergeNavigationStrategy(deeplyTraverseArrays) navigationStrategy := ReadForMergeNavigationStrategy(deeplyTraverseArrays, overwriteArray)
navigator := NewDataNavigator(navigationStrategy) navigator := NewDataNavigator(navigationStrategy)
error := navigator.Traverse(rootNode, paths) error := navigator.Traverse(rootNode, paths)
return navigationStrategy.GetVisitedNodes(), error return navigationStrategy.GetVisitedNodes(), error

View File

@ -1,6 +1,8 @@
package yqlib package yqlib
func ReadForMergeNavigationStrategy(deeplyTraverseArrays bool) NavigationStrategy { import "gopkg.in/yaml.v3"
func ReadForMergeNavigationStrategy(deeplyTraverseArrays bool, overwriteArray bool) NavigationStrategy {
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: NewPathParser(), pathParser: NewPathParser(),
@ -14,6 +16,11 @@ func ReadForMergeNavigationStrategy(deeplyTraverseArrays bool) NavigationStrateg
return nil return nil
}, },
shouldDeeplyTraverse: func(nodeContext NodeContext) bool { shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
if nodeContext.Node.Kind == yaml.SequenceNode && overwriteArray {
nodeContext.IsMiddleNode = false
return false
}
var isInArray = false var isInArray = false
if len(nodeContext.PathStack) > 0 { if len(nodeContext.PathStack) > 0 {
var lastElement = nodeContext.PathStack[len(nodeContext.PathStack)-1] var lastElement = nodeContext.PathStack[len(nodeContext.PathStack)-1]