From d828b214cc2af2685c0714c796963879e79ce7cc Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 3 Feb 2020 14:15:12 +1100 Subject: [PATCH] More powerful compare --- cmd/compare.go | 44 ++++++++++++++++++++++---------------------- cmd/read.go | 2 +- cmd/utils.go | 31 +++++++++++++++---------------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/cmd/compare.go b/cmd/compare.go index 211c668e..459991f7 100644 --- a/cmd/compare.go +++ b/cmd/compare.go @@ -5,67 +5,67 @@ import ( "bytes" "github.com/kylelemons/godebug/diff" + "github.com/mikefarah/yq/v3/pkg/yqlib" errors "github.com/pkg/errors" "github.com/spf13/cobra" - yaml "gopkg.in/yaml.v3" ) 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 data1.yml data2.yml ", Example: ` yq x - data2.yml # reads from stdin `, - Long: "Compares two yaml files, prints the difference", + Long: "Compares two yaml files, prints the difference. same ", RunE: compareDocuments, } - cmdCompare.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based)") + cmdCompare.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") + cmdCompare.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)") cmdCompare.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print (does not have an affect with json output)") + cmdCompare.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results") return cmdCompare } func compareDocuments(cmd *cobra.Command, args []string) error { - if len(args) != 2 { + var path = "" + + if len(args) < 2 { return errors.New("Must provide at 2 yaml files") - } - if docIndex == "*" { - return errors.New("Document splat for compare not yet supported") + } else if len(args) > 2 { + path = args[2] } - var _, docIndexInt, errorParsingDocIndex = parseDocumentIndex() + var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex() if errorParsingDocIndex != nil { return errorParsingDocIndex } - var dataBucketA yaml.Node - var dataBucketB yaml.Node + var matchingNodesA []*yqlib.NodeContext + var matchingNodesB []*yqlib.NodeContext var errorReadingStream error - errorReadingStream = readData(args[0], docIndexInt, &dataBucketA) + + matchingNodesA, errorReadingStream = readYamlFile(args[0], path, updateAll, docIndexInt) + if errorReadingStream != nil { return errorReadingStream } - errorReadingStream = readData(args[1], docIndexInt, &dataBucketB) + matchingNodesB, errorReadingStream = readYamlFile(args[1], path, updateAll, docIndexInt) if errorReadingStream != nil { return errorReadingStream } if prettyPrint { - updateStyleOfNode(&dataBucketA, 0) - updateStyleOfNode(&dataBucketB, 0) - } - - if errorReadingStream != nil { - return errorReadingStream + setStyle(matchingNodesA, 0) + setStyle(matchingNodesB, 0) } var dataBufferA bytes.Buffer - printNode(&dataBucketA, bufio.NewWriter(&dataBufferA)) - var dataBufferB bytes.Buffer - printNode(&dataBucketB, bufio.NewWriter(&dataBufferB)) + printResults(matchingNodesA, bufio.NewWriter(&dataBufferA)) + printResults(matchingNodesB, bufio.NewWriter(&dataBufferB)) cmd.Print(diff.Diff(dataBufferA.String(), dataBufferB.String())) return nil diff --git a/cmd/read.go b/cmd/read.go index f8a392e6..1a60c9db 100644 --- a/cmd/read.go +++ b/cmd/read.go @@ -54,5 +54,5 @@ func readProperty(cmd *cobra.Command, args []string) error { setStyle(matchingNodes, 0) } - return printResults(matchingNodes, cmd) + return printResults(matchingNodes, cmd.OutOrStdout()) } diff --git a/cmd/utils.go b/cmd/utils.go index ed6cf532..0e5ef75f 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -10,7 +10,6 @@ import ( "github.com/mikefarah/yq/v3/pkg/yqlib" errors "github.com/pkg/errors" - "github.com/spf13/cobra" yaml "gopkg.in/yaml.v3" ) @@ -66,23 +65,20 @@ func appendDocument(originalMatchingNodes []*yqlib.NodeContext, dataBucket yaml. return append(originalMatchingNodes, matchingNodes...), nil } -func printValue(node *yaml.Node, cmd *cobra.Command) error { +func printValue(node *yaml.Node, writer io.Writer) error { if node.Kind == yaml.ScalarNode { - cmd.Print(node.Value) + writer.Write([]byte(node.Value)) return nil } - return printNode(node, cmd.OutOrStdout()) + return printNode(node, writer) } func printNode(node *yaml.Node, writer io.Writer) error { - bufferedWriter := bufio.NewWriter(writer) - defer safelyFlush(bufferedWriter) - var encoder yqlib.Encoder if outputToJSON { - encoder = yqlib.NewJsonEncoder(bufferedWriter) + encoder = yqlib.NewJsonEncoder(writer) } else { - encoder = yqlib.NewYamlEncoder(bufferedWriter) + encoder = yqlib.NewYamlEncoder(writer) } return encoder.Encode(node) } @@ -101,11 +97,14 @@ func updateStyleOfNode(node *yaml.Node, style yaml.Style) { } } -func printResults(matchingNodes []*yqlib.NodeContext, cmd *cobra.Command) error { +func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error { + bufferedWriter := bufio.NewWriter(writer) + defer safelyFlush(bufferedWriter) + if len(matchingNodes) == 0 { log.Debug("no matching results, nothing to print") if defaultValue != "" { - cmd.Print(defaultValue) + bufferedWriter.Write([]byte(defaultValue)) } return nil } @@ -113,9 +112,9 @@ func printResults(matchingNodes []*yqlib.NodeContext, cmd *cobra.Command) error for index, mappedDoc := range matchingNodes { switch printMode { case "p": - cmd.Print(lib.PathStackToString(mappedDoc.PathStack)) + bufferedWriter.Write([]byte(lib.PathStackToString(mappedDoc.PathStack))) if index < len(matchingNodes)-1 { - cmd.Print("\n") + bufferedWriter.Write([]byte("\n")) } case "pv", "vp": // put it into a node and print that. @@ -123,17 +122,17 @@ func printResults(matchingNodes []*yqlib.NodeContext, cmd *cobra.Command) error parentNode.Content = make([]*yaml.Node, 2) parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: lib.PathStackToString(mappedDoc.PathStack)} parentNode.Content[1] = mappedDoc.Node - if err := printValue(&parentNode, cmd); err != nil { + if err := printValue(&parentNode, bufferedWriter); err != nil { return err } default: - if err := printValue(mappedDoc.Node, cmd); err != nil { + if err := printValue(mappedDoc.Node, bufferedWriter); err != nil { return err } // 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 { - cmd.Print("\n") + bufferedWriter.Write([]byte("\n")) } } }