diff --git a/README.md b/README.md index 3ff693f7..cbcb99af 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ yq() { - [List matching paths of a given path expression](https://mikefarah.gitbook.io/yq/commands/read#path-only) - Update a yaml file given a [path expression](https://mikefarah.gitbook.io/yq/commands/write-update#basic) or [script file](https://mikefarah.gitbook.io/yq/commands/write-update#basic) - Update creates any missing entries in the path on the fly +- Deeply compare yaml files - Keeps yaml formatting and comments when updating - [Validate a yaml file](https://mikefarah.gitbook.io/yq/commands/validate) - Create a yaml file given a [deep path and value](https://mikefarah.gitbook.io/yq/commands/create#creating-a-simple-yaml-file) or a [script file](https://mikefarah.gitbook.io/yq/commands/create#creating-using-a-create-script) diff --git a/cmd/compare.go b/cmd/compare.go index 459991f7..9c0bbf68 100644 --- a/cmd/compare.go +++ b/cmd/compare.go @@ -14,11 +14,13 @@ func createCompareCmd() *cobra.Command { var cmdCompare = &cobra.Command{ Use: "compare [yaml_file_a] [yaml_file_b]", Aliases: []string{"x"}, - Short: "yq x data1.yml data2.yml ", + Short: "yq x [--prettyPrint/-P] dataA.yaml dataB.yaml 'b.e(name==fr*).value'", Example: ` yq x - data2.yml # reads from stdin +yq x -pp dataA.yaml dataB.yaml '**' # compare paths +yq x -d1 dataA.yaml dataB.yaml 'a.b.c' `, - Long: "Compares two yaml files, prints the difference. same ", + Long: "Deeply compares two yaml files, prints the difference. Use with prettyPrint flag to ignore formatting differences.", RunE: compareDocuments, } cmdCompare.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") @@ -44,17 +46,17 @@ func compareDocuments(cmd *cobra.Command, args []string) error { var matchingNodesA []*yqlib.NodeContext var matchingNodesB []*yqlib.NodeContext - var errorReadingStream error + var errorDoingThings error - matchingNodesA, errorReadingStream = readYamlFile(args[0], path, updateAll, docIndexInt) + matchingNodesA, errorDoingThings = readYamlFile(args[0], path, updateAll, docIndexInt) - if errorReadingStream != nil { - return errorReadingStream + if errorDoingThings != nil { + return errorDoingThings } - matchingNodesB, errorReadingStream = readYamlFile(args[1], path, updateAll, docIndexInt) - if errorReadingStream != nil { - return errorReadingStream + matchingNodesB, errorDoingThings = readYamlFile(args[1], path, updateAll, docIndexInt) + if errorDoingThings != nil { + return errorDoingThings } if prettyPrint { @@ -64,8 +66,14 @@ func compareDocuments(cmd *cobra.Command, args []string) error { var dataBufferA bytes.Buffer var dataBufferB bytes.Buffer - printResults(matchingNodesA, bufio.NewWriter(&dataBufferA)) - printResults(matchingNodesB, bufio.NewWriter(&dataBufferB)) + errorDoingThings = printResults(matchingNodesA, bufio.NewWriter(&dataBufferA)) + if errorDoingThings != nil { + return errorDoingThings + } + errorDoingThings = printResults(matchingNodesB, bufio.NewWriter(&dataBufferB)) + if errorDoingThings != nil { + return errorDoingThings + } cmd.Print(diff.Diff(dataBufferA.String(), dataBufferB.String())) return nil diff --git a/cmd/utils.go b/cmd/utils.go index 0e5ef75f..7cd5f662 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -67,8 +67,8 @@ func appendDocument(originalMatchingNodes []*yqlib.NodeContext, dataBucket yaml. func printValue(node *yaml.Node, writer io.Writer) error { if node.Kind == yaml.ScalarNode { - writer.Write([]byte(node.Value)) - return nil + _, errorWriting := writer.Write([]byte(node.Value)) + return errorWriting } return printNode(node, writer) } @@ -97,6 +97,11 @@ func updateStyleOfNode(node *yaml.Node, style yaml.Style) { } } +func writeString(writer io.Writer, txt string) error { + _, errorWriting := writer.Write([]byte(txt)) + return errorWriting +} + func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error { bufferedWriter := bufio.NewWriter(writer) defer safelyFlush(bufferedWriter) @@ -104,17 +109,23 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error { if len(matchingNodes) == 0 { log.Debug("no matching results, nothing to print") if defaultValue != "" { - bufferedWriter.Write([]byte(defaultValue)) + return writeString(bufferedWriter, defaultValue) } return nil } - + var errorWriting error for index, mappedDoc := range matchingNodes { switch printMode { case "p": - bufferedWriter.Write([]byte(lib.PathStackToString(mappedDoc.PathStack))) + errorWriting = writeString(bufferedWriter, lib.PathStackToString(mappedDoc.PathStack)) + if errorWriting != nil { + return errorWriting + } if index < len(matchingNodes)-1 { - bufferedWriter.Write([]byte("\n")) + errorWriting = writeString(bufferedWriter, "\n") + if errorWriting != nil { + return errorWriting + } } case "pv", "vp": // put it into a node and print that. @@ -132,7 +143,10 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error { // Printing our Scalars does not print a new line at the end // we only want to do that if there are more values (so users can easily script extraction of values in the yaml) if index < len(matchingNodes)-1 && mappedDoc.Node.Kind == yaml.ScalarNode { - bufferedWriter.Write([]byte("\n")) + errorWriting = writeString(bufferedWriter, "\n") + if errorWriting != nil { + return errorWriting + } } } }