Merge can allow empty merges!

This commit is contained in:
Mike Farah 2020-01-06 16:22:24 +13:00
parent e3f4eedd51
commit d8c29b26c1
2 changed files with 49 additions and 122 deletions

View File

@ -243,7 +243,7 @@ func TestReadBadDocumentIndexCmd(t *testing.T) {
if result.Error == nil {
t.Error("Expected command to fail due to invalid path")
}
expectedOutput := `asked to process document index 1 but there are only 1 document(s)`
expectedOutput := `Could not process document index 1 as there are only 1 document(s)`
test.AssertResult(t, expectedOutput, result.Error.Error())
}
@ -829,18 +829,6 @@ func TestNewCmd_Error(t *testing.T) {
test.AssertResult(t, expectedOutput, result.Error.Error())
}
func TestNewCmd_Verbose(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "-v new b.c 3")
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `b:
c: 3
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestWriteCmd(t *testing.T) {
content := `b:
c: 3
@ -998,24 +986,6 @@ func TestWriteCmd_ErrorUnreadableFile(t *testing.T) {
test.AssertResult(t, expectedOutput, result.Error.Error())
}
func TestWriteCmd_Verbose(t *testing.T) {
content := `b:
c: 3
`
filename := test.WriteTempYamlFile(content)
defer test.RemoveTempYamlFile(filename)
cmd := getRootCommand()
result := test.RunCmd(cmd, fmt.Sprintf("-v write %s b.c 7", filename))
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `b:
c: 7
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestWriteCmd_Inplace(t *testing.T) {
content := `b:
c: 3
@ -1193,7 +1163,7 @@ b:
defer test.RemoveTempYamlFile(filename)
cmd := getRootCommand()
result := test.RunCmd(cmd, fmt.Sprintf("delete -v %s b.hi[*].thing", filename))
result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.hi[*].thing", filename))
if result.Error != nil {
t.Error(result.Error)
}
@ -1224,7 +1194,7 @@ b:
defer test.RemoveTempYamlFile(filename)
cmd := getRootCommand()
result := test.RunCmd(cmd, fmt.Sprintf("delete -v %s b.there*.c", filename))
result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.there*.c", filename))
if result.Error != nil {
t.Error(result.Error)
}
@ -1315,7 +1285,7 @@ func TestMergeCmd(t *testing.T) {
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `a: simple
expectedOutput := `a: simple # just the best
b: [1, 2]
c:
test: 1
@ -1332,7 +1302,7 @@ func TestMergeNoAutoCreateCmd(t *testing.T) {
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `a: simple
expectedOutput := `a: simple # just the best
b: [1, 2]
c:
test: 1
@ -1401,7 +1371,7 @@ c:
test.AssertResult(t, expectedOutput, result.Output)
}
func xTestMergeYamlMultiAllCmd(t *testing.T) {
func TestMergeYamlMultiAllCmd(t *testing.T) {
content := `b:
c: 3
apples: green
@ -1420,17 +1390,18 @@ something: good`
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `apples: green
b:
expectedOutput := `b:
c: 3
apples: green
something: good
---
something: else
apples: red
something: else`
test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
`
test.AssertResult(t, expectedOutput, result.Output)
}
func xTestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
func TestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
content := `b:
c: 3
apples: green
@ -1449,17 +1420,18 @@ something: good`
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `apples: red
b:
expectedOutput := `b:
c: 3
apples: red
something: good
---
something: good
apples: red
something: good`
test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
`
test.AssertResult(t, expectedOutput, result.Output)
}
func xTestMergeCmd_Error(t *testing.T) {
func TestMergeCmd_Error(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "merge examples/data1.yaml")
if result.Error == nil {
@ -1469,7 +1441,7 @@ func xTestMergeCmd_Error(t *testing.T) {
test.AssertResult(t, expectedOutput, result.Error.Error())
}
func xTestMergeCmd_ErrorUnreadableFile(t *testing.T) {
func TestMergeCmd_ErrorUnreadableFile(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "merge examples/data1.yaml fake-unknown")
if result.Error == nil {
@ -1477,30 +1449,14 @@ func xTestMergeCmd_ErrorUnreadableFile(t *testing.T) {
}
var expectedOutput string
if runtime.GOOS == "windows" {
expectedOutput = `Error updating document at index 0: open fake-unknown: The system cannot find the file specified.`
expectedOutput = `open fake-unknown: The system cannot find the file specified.`
} else {
expectedOutput = `Error updating document at index 0: open fake-unknown: no such file or directory`
expectedOutput = `open fake-unknown: no such file or directory`
}
test.AssertResult(t, expectedOutput, result.Error.Error())
}
func xTestMergeCmd_Verbose(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "-v merge examples/data1.yaml examples/data2.yaml")
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `a: simple
b:
- 1
- 2
c:
test: 1
`
test.AssertResult(t, expectedOutput, result.Output)
}
func xTestMergeCmd_Inplace(t *testing.T) {
func TestMergeCmd_Inplace(t *testing.T) {
filename := test.WriteTempYamlFile(test.ReadTempYamlFile("examples/data1.yaml"))
err := os.Chmod(filename, os.FileMode(int(0666)))
if err != nil {
@ -1515,26 +1471,35 @@ func xTestMergeCmd_Inplace(t *testing.T) {
}
info, _ := os.Stat(filename)
gotOutput := test.ReadTempYamlFile(filename)
expectedOutput := `a: simple
b:
- 1
- 2
expectedOutput := `a: simple # just the best
b: [1, 2]
c:
test: 1`
test.AssertResult(t, expectedOutput, strings.Trim(gotOutput, "\n "))
test: 1
toast: leave
tell: 1
taco: cool
`
test.AssertResult(t, expectedOutput, gotOutput)
test.AssertResult(t, os.FileMode(int(0666)), info.Mode())
}
func xTestMergeAllowEmptyCmd(t *testing.T) {
func TestMergeAllowEmptyCmd(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "merge --allow-empty examples/data1.yaml examples/empty.yaml")
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `a: simple
b:
- 1
- 2
expectedOutput := `a: simple # just the best
b: [1, 2]
c:
test: 1
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestMergeDontAllowEmptyCmd(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "merge examples/data1.yaml examples/empty.yaml")
expectedOutput := `Could not process document index 0 as there are only 0 document(s)`
test.AssertResult(t, expectedOutput, result.Error.Error())
}

52
yq.go
View File

@ -7,6 +7,7 @@ import (
"io/ioutil"
"os"
"strconv"
"strings"
"github.com/mikefarah/yq/v3/pkg/yqlib"
@ -239,7 +240,7 @@ Note that if you set both flags only overwrite will take effect.
cmdMerge.PersistentFlags().BoolVarP(&overwriteFlag, "overwrite", "x", false, "update the yaml file by overwriting existing values")
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(&allowEmptyFlag, "allow-empty", "e", false, "allow empty yaml files")
cmdMerge.PersistentFlags().BoolVarP(&allowEmptyFlag, "allow-empty", "e", false, "allow empty yaml files")
cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
return cmdMerge
}
@ -293,7 +294,7 @@ func readYamlFile(filename string, path string, updateAll bool, docIndexInt int)
func handleEOF(updateAll bool, docIndexInt int, currentIndex int) error {
log.Debugf("done %v / %v", currentIndex, docIndexInt)
if !updateAll && currentIndex <= docIndexInt {
return fmt.Errorf("asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
return fmt.Errorf("Could not process document index %v as there are only %v document(s)", docIndex, currentIndex)
}
return nil
}
@ -425,13 +426,16 @@ func writeProperty(cmd *cobra.Command, args []string) error {
}
func mergeProperties(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return errors.New("Must provide at least 2 yaml files")
}
// first generate update commands from the file
var filesToMerge = args[1:]
var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
for _, fileToMerge := range filesToMerge {
matchingNodes, errorProcessingFile := readYamlFile(fileToMerge, "**", false, 0)
if errorProcessingFile != nil {
if errorProcessingFile != nil && (allowEmptyFlag == false || !strings.HasPrefix(errorProcessingFile.Error(), "Could not process document index")) {
return errorProcessingFile
}
for _, matchingNode := range matchingNodes {
@ -569,48 +573,6 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn)
return readStream(inputFile, mapYamlDecoder(updateData, encoder))
}
// func mergeProperties(cmd *cobra.Command, args []string) error {
// if len(args) < 2 {
// return errors.New("Must provide at least 2 yaml files")
// }
// var input = args[0]
// var filesToMerge = args[1:]
// var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
// if errorParsingDocIndex != nil {
// return errorParsingDocIndex
// }
// var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
// if updateAll || currentIndex == docIndexInt {
// log.Debugf("Merging doc %v", currentIndex)
// var mergedData map[interface{}]interface{}
// // merge only works for maps, so put everything in a temporary
// // map
// var mapDataBucket = make(map[interface{}]interface{})
// mapDataBucket["root"] = dataBucket
// if err := lib.Merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil {
// return nil, err
// }
// for _, f := range filesToMerge {
// var fileToMerge interface{}
// if err := readData(f, 0, &fileToMerge); err != nil {
// if allowEmptyFlag && err == io.EOF {
// continue
// }
// return nil, err
// }
// mapDataBucket["root"] = fileToMerge
// if err := lib.Merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil {
// return nil, err
// }
// }
// return mergedData["root"], nil
// }
// return dataBucket, nil
// }
// return readAndUpdate(cmd.OutOrStdout(), input, updateData)
// }
type updateCommandParsed struct {
Command string
Path string