mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
first cli
This commit is contained in:
parent
badd476730
commit
85d059340b
@ -1,83 +1,83 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
// import (
|
||||
// "strings"
|
||||
// "testing"
|
||||
|
||||
"github.com/mikefarah/yq/v3/test"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// "github.com/spf13/cobra"
|
||||
// )
|
||||
|
||||
func getRootCommand() *cobra.Command {
|
||||
return New()
|
||||
}
|
||||
// func getRootCommand() *cobra.Command {
|
||||
// return New()
|
||||
// }
|
||||
|
||||
func TestRootCmd(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
// func TestRootCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
if !strings.Contains(result.Output, "Usage:") {
|
||||
t.Error("Expected usage message to be printed out, but the usage message was not found.")
|
||||
}
|
||||
}
|
||||
// if !strings.Contains(result.Output, "Usage:") {
|
||||
// t.Error("Expected usage message to be printed out, but the usage message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestRootCmd_Help(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "--help")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
// func TestRootCmd_Help(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "--help")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
if !strings.Contains(result.Output, "yq is a lightweight and portable command-line YAML processor. It aims to be the jq or sed of yaml files.") {
|
||||
t.Error("Expected usage message to be printed out, but the usage message was not found.")
|
||||
}
|
||||
}
|
||||
// if !strings.Contains(result.Output, "yq is a lightweight and portable command-line YAML processor. It aims to be the jq or sed of yaml files.") {
|
||||
// t.Error("Expected usage message to be printed out, but the usage message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestRootCmd_VerboseLong(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "--verbose")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
// func TestRootCmd_VerboseLong(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "--verbose")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
if !verbose {
|
||||
t.Error("Expected verbose to be true")
|
||||
}
|
||||
}
|
||||
// if !verbose {
|
||||
// t.Error("Expected verbose to be true")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestRootCmd_VerboseShort(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "-v")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
// func TestRootCmd_VerboseShort(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "-v")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
if !verbose {
|
||||
t.Error("Expected verbose to be true")
|
||||
}
|
||||
}
|
||||
// if !verbose {
|
||||
// t.Error("Expected verbose to be true")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestRootCmd_VersionShort(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "-V")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
if !strings.Contains(result.Output, "yq version") {
|
||||
t.Error("expected version message to be printed out, but the message was not found.")
|
||||
}
|
||||
}
|
||||
// func TestRootCmd_VersionShort(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "-V")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// if !strings.Contains(result.Output, "yq version") {
|
||||
// t.Error("expected version message to be printed out, but the message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestRootCmd_VersionLong(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "--version")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
if !strings.Contains(result.Output, "yq version") {
|
||||
t.Error("expected version message to be printed out, but the message was not found.")
|
||||
}
|
||||
}
|
||||
// func TestRootCmd_VersionLong(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "--version")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// if !strings.Contains(result.Output, "yq version") {
|
||||
// t.Error("expected version message to be printed out, but the message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
@ -1,89 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "bufio"
|
||||
// "bytes"
|
||||
// "os"
|
||||
// "strings"
|
||||
|
||||
// "github.com/kylelemons/godebug/diff"
|
||||
// "github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
// errors "github.com/pkg/errors"
|
||||
// "github.com/spf13/cobra"
|
||||
// )
|
||||
|
||||
// // turn off for unit tests :(
|
||||
// var forceOsExit = true
|
||||
|
||||
// func createCompareCmd() *cobra.Command {
|
||||
// var cmdCompare = &cobra.Command{
|
||||
// Use: "compare [yaml_file_a] [yaml_file_b]",
|
||||
// Aliases: []string{"x"},
|
||||
// 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: "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)")
|
||||
// cmdCompare.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
||||
// cmdCompare.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
||||
// cmdCompare.PersistentFlags().BoolVarP(&stripComments, "stripComments", "", false, "strip comments out before comparing")
|
||||
// cmdCompare.PersistentFlags().BoolVarP(&explodeAnchors, "explodeAnchors", "X", false, "explode anchors")
|
||||
// return cmdCompare
|
||||
// }
|
||||
|
||||
// func compareDocuments(cmd *cobra.Command, args []string) error {
|
||||
// var path = ""
|
||||
|
||||
// if len(args) < 2 {
|
||||
// return errors.New("Must provide at 2 yaml files")
|
||||
// } else if len(args) > 2 {
|
||||
// path = args[2]
|
||||
// }
|
||||
|
||||
// var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
// if errorParsingDocIndex != nil {
|
||||
// return errorParsingDocIndex
|
||||
// }
|
||||
|
||||
// var matchingNodesA []*yqlib.NodeContext
|
||||
// var matchingNodesB []*yqlib.NodeContext
|
||||
// var errorDoingThings error
|
||||
|
||||
// matchingNodesA, errorDoingThings = readYamlFile(args[0], path, updateAll, docIndexInt)
|
||||
|
||||
// if errorDoingThings != nil {
|
||||
// return errorDoingThings
|
||||
// }
|
||||
|
||||
// matchingNodesB, errorDoingThings = readYamlFile(args[1], path, updateAll, docIndexInt)
|
||||
// if errorDoingThings != nil {
|
||||
// return errorDoingThings
|
||||
// }
|
||||
|
||||
// var dataBufferA bytes.Buffer
|
||||
// var dataBufferB bytes.Buffer
|
||||
// errorDoingThings = printResults(matchingNodesA, bufio.NewWriter(&dataBufferA))
|
||||
// if errorDoingThings != nil {
|
||||
// return errorDoingThings
|
||||
// }
|
||||
// errorDoingThings = printResults(matchingNodesB, bufio.NewWriter(&dataBufferB))
|
||||
// if errorDoingThings != nil {
|
||||
// return errorDoingThings
|
||||
// }
|
||||
|
||||
// diffString := diff.Diff(strings.TrimSuffix(dataBufferA.String(), "\n"), strings.TrimSuffix(dataBufferB.String(), "\n"))
|
||||
|
||||
// if len(diffString) > 1 {
|
||||
// cmd.Print(diffString)
|
||||
// cmd.Print("\n")
|
||||
// if forceOsExit {
|
||||
// os.Exit(1)
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
@ -1,115 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "testing"
|
||||
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// )
|
||||
|
||||
// func TestCompareSameCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare ../examples/data1.yaml ../examples/data1.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := ``
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestCompareIgnoreCommentsCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare --stripComments ../examples/data1.yaml ../examples/data1-no-comments.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := ``
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestCompareDontIgnoreCommentsCmd(t *testing.T) {
|
||||
// forceOsExit = false
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare ../examples/data1.yaml ../examples/data1-no-comments.yaml")
|
||||
|
||||
// expectedOutput := `-a: simple # just the best
|
||||
// +a: simple
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestCompareExplodeAnchorsCommentsCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare --explodeAnchors ../examples/simple-anchor.yaml ../examples/simple-anchor-exploded.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := ``
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestCompareDontExplodeAnchorsCmd(t *testing.T) {
|
||||
// forceOsExit = false
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare ../examples/simple-anchor.yaml ../examples/simple-anchor-exploded.yaml")
|
||||
|
||||
// expectedOutput := `-foo: &foo
|
||||
// +foo:
|
||||
// a: 1
|
||||
// foobar:
|
||||
// - !!merge <<: *foo
|
||||
// + a: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestCompareDifferentCmd(t *testing.T) {
|
||||
// forceOsExit = false
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare ../examples/data1.yaml ../examples/data3.yaml")
|
||||
|
||||
// expectedOutput := `-a: simple # just the best
|
||||
// -b: [1, 2]
|
||||
// +a: "simple" # just the best
|
||||
// +b: [1, 3]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestComparePrettyCmd(t *testing.T) {
|
||||
// forceOsExit = false
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare -P ../examples/data1.yaml ../examples/data3.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := ` a: simple # just the best
|
||||
// b:
|
||||
// - 1
|
||||
// - - 2
|
||||
// + - 3
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestComparePathsCmd(t *testing.T) {
|
||||
// forceOsExit = false
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "compare -P -ppv ../examples/data1.yaml ../examples/data3.yaml **")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := ` a: simple # just the best
|
||||
// b.[0]: 1
|
||||
// -b.[1]: 2
|
||||
// +b.[1]: 3
|
||||
// c.test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
@ -1,8 +1,6 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
"github.com/mikefarah/yq/v3/pkg/yqlib/treeops"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
@ -14,7 +12,6 @@ var customStyle = ""
|
||||
var anchorName = ""
|
||||
var makeAlias = false
|
||||
var stripComments = false
|
||||
var collectIntoArray = false
|
||||
var writeInplace = false
|
||||
var writeScript = ""
|
||||
var sourceYamlFile = ""
|
||||
@ -22,6 +19,8 @@ var outputToJSON = false
|
||||
var exitStatus = false
|
||||
var prettyPrint = false
|
||||
var explodeAnchors = false
|
||||
var forceColor = false
|
||||
var forceNoColor = false
|
||||
var colorsEnabled = false
|
||||
var defaultValue = ""
|
||||
var indent = 2
|
||||
@ -31,7 +30,5 @@ var arrayMergeStrategyFlag = "update"
|
||||
var commentsMergeStrategyFlag = "setWhenBlank"
|
||||
var verbose = false
|
||||
var version = false
|
||||
var docIndex = "0"
|
||||
var shellCompletion = ""
|
||||
var log = logging.MustGetLogger("yq")
|
||||
var lib = treeops.NewYqTreeLib()
|
||||
var valueParser = yqlib.NewValueParser()
|
||||
|
@ -1,41 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
// errors "github.com/pkg/errors"
|
||||
// "github.com/spf13/cobra"
|
||||
// )
|
||||
|
||||
// func createDeleteCmd() *cobra.Command {
|
||||
// var cmdDelete = &cobra.Command{
|
||||
// Use: "delete [yaml_file] [path_expression]",
|
||||
// Aliases: []string{"d"},
|
||||
// Short: "yq d [--inplace/-i] [--doc/-d index] sample.yaml 'b.e(name==fred)'",
|
||||
// Example: `
|
||||
// yq delete things.yaml 'a.b.c'
|
||||
// yq delete things.yaml 'a.*.c'
|
||||
// yq delete things.yaml 'a.(child.subchild==co*).c'
|
||||
// yq delete things.yaml 'a.**'
|
||||
// yq delete --inplace things.yaml 'a.b.c'
|
||||
// yq delete --inplace -- things.yaml '--key-starting-with-dash' # need to use '--' to stop processing arguments as flags
|
||||
// yq d -i things.yaml 'a.b.c'
|
||||
// `,
|
||||
// Long: `Deletes the nodes matching the given path expression from the YAML file.
|
||||
// Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
|
||||
// `,
|
||||
// RunE: deleteProperty,
|
||||
// }
|
||||
// cmdDelete.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||
// cmdDelete.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
// return cmdDelete
|
||||
// }
|
||||
|
||||
// func deleteProperty(cmd *cobra.Command, args []string) error {
|
||||
// if len(args) < 2 {
|
||||
// return errors.New("Must provide <filename> <path_to_delete>")
|
||||
// }
|
||||
// var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 1)
|
||||
// updateCommands[0] = yqlib.UpdateCommand{Command: "delete", Path: args[1]}
|
||||
|
||||
// return updateDoc(args[0], updateCommands, cmd.OutOrStdout())
|
||||
// }
|
@ -1,246 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "strings"
|
||||
// "testing"
|
||||
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// )
|
||||
|
||||
// func TestDeleteYamlCmd(t *testing.T) {
|
||||
// content := `a: 2
|
||||
// b:
|
||||
// c: things
|
||||
// d: something else
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.c", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: 2
|
||||
// b:
|
||||
// d: something else
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteDeepDoesNotExistCmd(t *testing.T) {
|
||||
// content := `a: 2`
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.c", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: 2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteSplatYaml(t *testing.T) {
|
||||
// content := `a: other
|
||||
// b: [3, 4]
|
||||
// c:
|
||||
// toast: leave
|
||||
// test: 1
|
||||
// tell: 1
|
||||
// tasty.taco: cool
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s c.te*", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: other
|
||||
// b: [3, 4]
|
||||
// c:
|
||||
// toast: leave
|
||||
// tasty.taco: cool
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteSplatArrayYaml(t *testing.T) {
|
||||
// content := `a: 2
|
||||
// b:
|
||||
// hi:
|
||||
// - thing: item1
|
||||
// name: fred
|
||||
// - thing: item2
|
||||
// name: sam
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.hi[*].thing", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: 2
|
||||
// b:
|
||||
// hi:
|
||||
// - name: fred
|
||||
// - name: sam
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteDeepSplatArrayYaml(t *testing.T) {
|
||||
// content := `thing: 123
|
||||
// b:
|
||||
// hi:
|
||||
// - thing: item1
|
||||
// name: fred
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s **.thing", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `b:
|
||||
// hi:
|
||||
// - name: fred
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteSplatPrefixYaml(t *testing.T) {
|
||||
// content := `a: 2
|
||||
// b:
|
||||
// hi:
|
||||
// c: things
|
||||
// d: something else
|
||||
// there:
|
||||
// c: more things
|
||||
// d: more something else
|
||||
// there2:
|
||||
// c: more things also
|
||||
// d: more something else also
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.there*.c", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: 2
|
||||
// b:
|
||||
// hi:
|
||||
// c: things
|
||||
// d: something else
|
||||
// there:
|
||||
// d: more something else
|
||||
// there2:
|
||||
// d: more something else also
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteYamlArrayCmd(t *testing.T) {
|
||||
// content := `- 1
|
||||
// - 2
|
||||
// - 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s [1]", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `- 1
|
||||
// - 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteYamlArrayExpressionCmd(t *testing.T) {
|
||||
// content := `- name: fred
|
||||
// - name: cat
|
||||
// - name: thing
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s (name==cat)", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `- name: fred
|
||||
// - name: thing
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteYamlMulti(t *testing.T) {
|
||||
// content := `apples: great
|
||||
// ---
|
||||
// - 1
|
||||
// - 2
|
||||
// - 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete -d 1 %s [1]", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `apples: great
|
||||
// ---
|
||||
// - 1
|
||||
// - 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestDeleteYamlMultiAllCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// apples: great
|
||||
// ---
|
||||
// apples: great
|
||||
// something: else
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("delete %s -d * apples", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 3
|
||||
// ---
|
||||
// something: else`
|
||||
// test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||
// }
|
124
cmd/merge.go
124
cmd/merge.go
@ -1,124 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
// errors "github.com/pkg/errors"
|
||||
// "github.com/spf13/cobra"
|
||||
// yaml "gopkg.in/yaml.v3"
|
||||
// )
|
||||
|
||||
// func createMergeCmd() *cobra.Command {
|
||||
// var cmdMerge = &cobra.Command{
|
||||
// Use: "merge [initial_yaml_file] [additional_yaml_file]...",
|
||||
// Aliases: []string{"m"},
|
||||
// Short: "yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--arrayMerge/-a strategy] sample.yaml sample2.yaml",
|
||||
// Example: `
|
||||
// yq merge things.yaml other.yaml
|
||||
// yq merge --inplace things.yaml other.yaml
|
||||
// yq m -i things.yaml other.yaml
|
||||
// yq m --overwrite things.yaml other.yaml
|
||||
// yq m -i -x things.yaml other.yaml
|
||||
// yq m -i -a=append things.yaml other.yaml
|
||||
// yq m -i --autocreate=false things.yaml other.yaml
|
||||
// `,
|
||||
// Long: `Updates the yaml file by adding/updating the path(s) and value(s) from additional yaml file(s).
|
||||
// Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
|
||||
|
||||
// If overwrite flag is set then existing values will be overwritten using the values from each additional yaml file.
|
||||
// If append flag is set then existing arrays will be merged with the arrays from each additional yaml file.
|
||||
// `,
|
||||
// RunE: mergeProperties,
|
||||
// }
|
||||
// cmdMerge.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||
// 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().StringVarP(&arrayMergeStrategyFlag, "arrays", "a", "update", `array merge strategy (update/append/overwrite)
|
||||
// update: recursively update arrays by their index
|
||||
// append: concatenate arrays together
|
||||
// overwrite: replace arrays
|
||||
// `)
|
||||
// cmdMerge.PersistentFlags().StringVarP(&commentsMergeStrategyFlag, "comments", "", "setWhenBlank", `comments merge strategy (setWhenBlank/ignore/append/overwrite)
|
||||
// setWhenBlank: set comment if the original document has no comment at that node
|
||||
// ignore: leave comments as-is in the original
|
||||
// append: append comments together
|
||||
// overwrite: overwrite comments completely
|
||||
// `)
|
||||
// cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
// return cmdMerge
|
||||
// }
|
||||
|
||||
// /*
|
||||
// * We don't deeply traverse arrays when appending a merge, instead we want to
|
||||
// * append the entire array element.
|
||||
// */
|
||||
// func createReadFunctionForMerge(arrayMergeStrategy yqlib.ArrayMergeStrategy) func(*yaml.Node) ([]*yqlib.NodeContext, error) {
|
||||
// return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) {
|
||||
// return lib.GetForMerge(dataBucket, "**", arrayMergeStrategy)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func mergeProperties(cmd *cobra.Command, args []string) error {
|
||||
// var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
|
||||
|
||||
// if len(args) < 1 {
|
||||
// return errors.New("Must provide at least 1 yaml file")
|
||||
// }
|
||||
// var arrayMergeStrategy yqlib.ArrayMergeStrategy
|
||||
|
||||
// switch arrayMergeStrategyFlag {
|
||||
// case "update":
|
||||
// arrayMergeStrategy = yqlib.UpdateArrayMergeStrategy
|
||||
// case "append":
|
||||
// arrayMergeStrategy = yqlib.AppendArrayMergeStrategy
|
||||
// case "overwrite":
|
||||
// arrayMergeStrategy = yqlib.OverwriteArrayMergeStrategy
|
||||
// default:
|
||||
// return errors.New("Array merge strategy must be one of: update/append/overwrite")
|
||||
// }
|
||||
|
||||
// var commentsMergeStrategy yqlib.CommentsMergeStrategy
|
||||
|
||||
// switch commentsMergeStrategyFlag {
|
||||
// case "setWhenBlank":
|
||||
// commentsMergeStrategy = yqlib.SetWhenBlankCommentsMergeStrategy
|
||||
// case "ignore":
|
||||
// commentsMergeStrategy = yqlib.IgnoreCommentsMergeStrategy
|
||||
// case "append":
|
||||
// commentsMergeStrategy = yqlib.AppendCommentsMergeStrategy
|
||||
// case "overwrite":
|
||||
// commentsMergeStrategy = yqlib.OverwriteCommentsMergeStrategy
|
||||
// default:
|
||||
// return errors.New("Comments merge strategy must be one of: setWhenBlank/ignore/append/overwrite")
|
||||
// }
|
||||
|
||||
// if len(args) > 1 {
|
||||
// // first generate update commands from the file
|
||||
// var filesToMerge = args[1:]
|
||||
|
||||
// for _, fileToMerge := range filesToMerge {
|
||||
// matchingNodes, errorProcessingFile := doReadYamlFile(fileToMerge, createReadFunctionForMerge(arrayMergeStrategy), false, 0)
|
||||
// if errorProcessingFile != nil {
|
||||
// return errorProcessingFile
|
||||
// }
|
||||
// log.Debugf("finished reading for merge!")
|
||||
// for _, matchingNode := range matchingNodes {
|
||||
// log.Debugf("matched node %v", lib.PathStackToString(matchingNode.PathStack))
|
||||
// yqlib.DebugNode(matchingNode.Node)
|
||||
// }
|
||||
// for _, matchingNode := range matchingNodes {
|
||||
// mergePath := lib.MergePathStackToString(matchingNode.PathStack, arrayMergeStrategy)
|
||||
// updateCommands = append(updateCommands, yqlib.UpdateCommand{
|
||||
// Command: "merge",
|
||||
// Path: mergePath,
|
||||
// Value: matchingNode.Node,
|
||||
// Overwrite: overwriteFlag,
|
||||
// CommentsMergeStrategy: commentsMergeStrategy,
|
||||
// // dont update the content for nodes midway, only leaf nodes
|
||||
// DontUpdateNodeContent: matchingNode.IsMiddleNode && (arrayMergeStrategy != yqlib.OverwriteArrayMergeStrategy || matchingNode.Node.Kind != yaml.SequenceNode),
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return updateDoc(args[0], updateCommands, cmd.OutOrStdout())
|
||||
// }
|
@ -1,551 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "os"
|
||||
// "runtime"
|
||||
// "testing"
|
||||
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// )
|
||||
|
||||
// func TestMergeCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge ../examples/data1.yaml ../examples/data2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// toast: leave
|
||||
// tell: 1
|
||||
// tasty.taco: cool
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeOneFileCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge ../examples/data1.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeNoAutoCreateCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge -c=false ../examples/data1.yaml ../examples/data2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeOverwriteCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge -c=false --overwrite ../examples/data1.yaml ../examples/data2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: other # just the best
|
||||
// b: [3, 4]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// 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) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge --autocreate=false --arrays=append ../examples/data1.yaml ../examples/data2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2, 3, 4]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeAppendArraysCmd(t *testing.T) {
|
||||
// content := `people:
|
||||
// - name: Barry
|
||||
// age: 21`
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeContent := `people:
|
||||
// - name: Roger
|
||||
// age: 44`
|
||||
// mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge --arrays=append -d* %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `people:
|
||||
// - name: Barry
|
||||
// age: 21
|
||||
// - name: Roger
|
||||
// age: 44
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeAliasArraysCmd(t *testing.T) {
|
||||
// content := `
|
||||
// vars:
|
||||
// variable1: &var1 cat
|
||||
|
||||
// usage:
|
||||
// value1: *var1
|
||||
// valueAnother: *var1
|
||||
// valuePlain: thing
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeContent := `
|
||||
// vars:
|
||||
// variable2: &var2 puppy
|
||||
|
||||
// usage:
|
||||
// value2: *var2
|
||||
// valueAnother: *var2
|
||||
// valuePlain: *var2
|
||||
// `
|
||||
|
||||
// mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge -x %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `vars:
|
||||
// variable1: &var1 cat
|
||||
// variable2: &var2 puppy
|
||||
// usage:
|
||||
// value1: *var1
|
||||
// valueAnother: *var2
|
||||
// valuePlain: *var2
|
||||
// value2: *var2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeOverwriteAndAppendCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge --autocreate=false --arrays=append --overwrite ../examples/data1.yaml ../examples/data2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: other # just the best
|
||||
// b: [1, 2, 3, 4]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// var commentContentA = `
|
||||
// a: valueA1 # commentA1
|
||||
// b: valueB1
|
||||
// `
|
||||
|
||||
// var commentContentB = `
|
||||
// a: valueA2 # commentA2
|
||||
// b: valueB2 # commentB2
|
||||
// c: valueC2 # commentC2
|
||||
// `
|
||||
|
||||
// func TestMergeCommentsSetWhenBlankCmd(t *testing.T) {
|
||||
// filename := test.WriteTempYamlFile(commentContentA)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=setWhenBlank %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: valueA1 # commentA1
|
||||
// b: valueB1 # commentB2
|
||||
// c: valueC2 # commentC2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeCommentsIgnoreCmd(t *testing.T) {
|
||||
// filename := test.WriteTempYamlFile(commentContentA)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=ignore %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: valueA1 # commentA1
|
||||
// b: valueB1
|
||||
// c: valueC2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeCommentsAppendCmd(t *testing.T) {
|
||||
// filename := test.WriteTempYamlFile(commentContentA)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=append %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: valueA1 # commentA1 # commentA2
|
||||
// b: valueB1 # commentB2
|
||||
// c: valueC2 # commentC2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeCommentsOverwriteCmd(t *testing.T) {
|
||||
// filename := test.WriteTempYamlFile(commentContentA)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=overwrite %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: valueA1 # commentA2
|
||||
// b: valueB1 # commentB2
|
||||
// c: valueC2 # commentC2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// 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 --arrays=overwrite --overwrite %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// expectedOutput := `a: things # just the best
|
||||
// b: [6]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeRootArraysCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge --arrays=append ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `- 1
|
||||
// - 2
|
||||
// - 3
|
||||
// - 4
|
||||
// - 5
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeOverwriteArraysCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge --arrays=overwrite ../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 TestMergeUpdateArraysCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge -x --arrays=update ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `- 4
|
||||
// - 5
|
||||
// - 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeCmd_Multi(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge -d1 ../examples/multiple_docs_small.yaml ../examples/data1.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: Easy! as one two three
|
||||
// ---
|
||||
// another:
|
||||
// document: here
|
||||
// a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// ---
|
||||
// - 1
|
||||
// - 2
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeYamlMultiAllCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// apples: green
|
||||
// ---
|
||||
// something: else`
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeContent := `apples: red
|
||||
// something: good`
|
||||
// mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge -d* %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 3
|
||||
// apples: green
|
||||
// something: good
|
||||
// ---
|
||||
// something: else
|
||||
// apples: red
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeSpecialCharacterKeysCmd(t *testing.T) {
|
||||
// content := ``
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeContent := `key[bracket]: value
|
||||
// key.bracket: value
|
||||
// key"value": value
|
||||
// key'value': value
|
||||
// `
|
||||
// mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// test.AssertResult(t, mergeContent, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// apples: green
|
||||
// ---
|
||||
// something: else`
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeContent := `apples: red
|
||||
// something: good`
|
||||
// mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge --overwrite -d* %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 3
|
||||
// apples: red
|
||||
// something: good
|
||||
// ---
|
||||
// something: good
|
||||
// apples: red
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeYamlNullMapCmd(t *testing.T) {
|
||||
// content := `b:`
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// mergeContent := `b:
|
||||
// thing: a frog
|
||||
// `
|
||||
// mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||
// defer test.RemoveTempYamlFile(mergeFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge %s %s", filename, mergeFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// test.AssertResult(t, mergeContent, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeCmd_Error(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge")
|
||||
// if result.Error == nil {
|
||||
// t.Error("Expected command to fail due to missing arg")
|
||||
// }
|
||||
// expectedOutput := `Must provide at least 1 yaml file`
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
|
||||
// func TestMergeCmd_ErrorUnreadableFile(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge ../examples/data1.yaml fake-unknown")
|
||||
// if result.Error == nil {
|
||||
// t.Error("Expected command to fail due to unknown file")
|
||||
// }
|
||||
// var expectedOutput string
|
||||
// if runtime.GOOS == "windows" {
|
||||
// expectedOutput = `open fake-unknown: The system cannot find the file specified.`
|
||||
// } else {
|
||||
// expectedOutput = `open fake-unknown: no such file or directory`
|
||||
// }
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
|
||||
// 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 {
|
||||
// t.Error(err)
|
||||
// }
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("merge -i %s ../examples/data2.yaml", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// info, _ := os.Stat(filename)
|
||||
// gotOutput := test.ReadTempYamlFile(filename)
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// toast: leave
|
||||
// tell: 1
|
||||
// tasty.taco: cool
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, gotOutput)
|
||||
// test.AssertResult(t, os.FileMode(int(0666)), info.Mode())
|
||||
// }
|
||||
|
||||
// func TestMergeAllowEmptyTargetCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge ../examples/empty.yaml ../examples/data1.yaml")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestMergeAllowEmptyMergeCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "merge ../examples/data1.yaml ../examples/empty.yaml")
|
||||
// expectedOutput := `a: simple # just the best
|
||||
// b: [1, 2]
|
||||
// c:
|
||||
// test: 1
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
55
cmd/new.go
55
cmd/new.go
@ -1,55 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
// "github.com/spf13/cobra"
|
||||
// )
|
||||
|
||||
// func createNewCmd() *cobra.Command {
|
||||
// var cmdNew = &cobra.Command{
|
||||
// Use: "new [path] [value]",
|
||||
// Aliases: []string{"n"},
|
||||
// Short: "yq n [--script/-s script_file] a.b.c newValue",
|
||||
// Example: `
|
||||
// yq new 'a.b.c' cat
|
||||
// yq n 'a.b.c' --tag '!!str' true # force 'true' to be interpreted as a string instead of bool
|
||||
// yq n 'a.b[+]' cat
|
||||
// yq n -- '--key-starting-with-dash' cat # need to use '--' to stop processing arguments as flags
|
||||
// yq n --script create_script.yaml
|
||||
// `,
|
||||
// Long: `Creates a new yaml w.r.t the given path and value.
|
||||
// Outputs to STDOUT
|
||||
|
||||
// Create Scripts:
|
||||
// Note that you can give a create script to perform more sophisticated yaml. This follows the same format as the update script.
|
||||
// `,
|
||||
// RunE: newProperty,
|
||||
// }
|
||||
// cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for creating yaml")
|
||||
// cmdNew.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)")
|
||||
// cmdNew.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged")
|
||||
// cmdNew.PersistentFlags().StringVarP(&anchorName, "anchorName", "", "", "anchor name")
|
||||
// cmdNew.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name")
|
||||
// return cmdNew
|
||||
// }
|
||||
|
||||
// func newProperty(cmd *cobra.Command, args []string) error {
|
||||
// var badArgsMessage = "Must provide <path_to_update> <value>"
|
||||
// var updateCommands, updateCommandsError = readUpdateCommands(args, 2, badArgsMessage, false)
|
||||
// if updateCommandsError != nil {
|
||||
// return updateCommandsError
|
||||
// }
|
||||
// newNode := lib.New(updateCommands[0].Path)
|
||||
|
||||
// for _, updateCommand := range updateCommands {
|
||||
|
||||
// errorUpdating := lib.Update(&newNode, updateCommand, true)
|
||||
|
||||
// if errorUpdating != nil {
|
||||
// return errorUpdating
|
||||
// }
|
||||
// }
|
||||
|
||||
// var encoder = yqlib.NewYamlEncoder(cmd.OutOrStdout(), indent, colorsEnabled)
|
||||
// return encoder.Encode(&newNode)
|
||||
// }
|
120
cmd/new_test.go
120
cmd/new_test.go
@ -1,120 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "testing"
|
||||
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// )
|
||||
|
||||
// func TestNewCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c 3")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewCmdScript(t *testing.T) {
|
||||
// updateScript := `- command: update
|
||||
// path: b.c
|
||||
// value: 7`
|
||||
// scriptFilename := test.WriteTempYamlFile(updateScript)
|
||||
// defer test.RemoveTempYamlFile(scriptFilename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("new --script %s", scriptFilename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 7
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewAnchorCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c 3 --anchorName=fred")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: &fred 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewAliasCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c foo --makeAlias")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: *foo
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewArrayCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b[0] 3")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// - 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewCmd_Error(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c")
|
||||
// if result.Error == nil {
|
||||
// t.Error("Expected command to fail due to missing arg")
|
||||
// }
|
||||
// expectedOutput := `Must provide <path_to_update> <value>`
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
|
||||
// func TestNewWithTaggedStyleCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c cat --tag=!!str --style=tagged")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: !!str cat
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewWithDoubleQuotedStyleCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c cat --style=double")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: "cat"
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestNewWithSingleQuotedStyleCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "new b.c cat --style=single")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 'cat'
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
@ -1,50 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
// errors "github.com/pkg/errors"
|
||||
// "github.com/spf13/cobra"
|
||||
// yaml "gopkg.in/yaml.v3"
|
||||
// )
|
||||
|
||||
// func createPrefixCmd() *cobra.Command {
|
||||
// var cmdPrefix = &cobra.Command{
|
||||
// Use: "prefix [yaml_file] [path]",
|
||||
// Aliases: []string{"p"},
|
||||
// Short: "yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c",
|
||||
// Example: `
|
||||
// yq prefix things.yaml 'a.b.c'
|
||||
// yq prefix --inplace things.yaml 'a.b.c'
|
||||
// yq prefix --inplace -- things.yaml '--key-starting-with-dash' # need to use '--' to stop processing arguments as flags
|
||||
// yq p -i things.yaml 'a.b.c'
|
||||
// yq p --doc 2 things.yaml 'a.b.d'
|
||||
// yq p -d2 things.yaml 'a.b.d'
|
||||
// `,
|
||||
// Long: `Prefixes w.r.t to the yaml file at the given path.
|
||||
// Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
|
||||
// `,
|
||||
// RunE: prefixProperty,
|
||||
// }
|
||||
// cmdPrefix.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||
// cmdPrefix.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
// return cmdPrefix
|
||||
// }
|
||||
|
||||
// func prefixProperty(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// if len(args) < 2 {
|
||||
// return errors.New("Must provide <filename> <prefixed_path>")
|
||||
// }
|
||||
// updateCommand := yqlib.UpdateCommand{Command: "update", Path: args[1]}
|
||||
// log.Debugf("args %v", args)
|
||||
|
||||
// var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
// if errorParsingDocIndex != nil {
|
||||
// return errorParsingDocIndex
|
||||
// }
|
||||
|
||||
// var updateData = func(dataBucket *yaml.Node, currentIndex int) error {
|
||||
// return prefixDocument(updateAll, docIndexInt, currentIndex, dataBucket, updateCommand)
|
||||
// }
|
||||
// return readAndUpdate(cmd.OutOrStdout(), args[0], updateData)
|
||||
// }
|
@ -1,189 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "runtime"
|
||||
// "strings"
|
||||
// "testing"
|
||||
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// )
|
||||
|
||||
// func TestPrefixCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s d", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `d:
|
||||
// b:
|
||||
// c: 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestPrefixCmdArray(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s [+].d.[+]", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `- d:
|
||||
// - b:
|
||||
// c: 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestPrefixCmd_MultiLayer(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s d.e.f", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `d:
|
||||
// e:
|
||||
// f:
|
||||
// b:
|
||||
// c: 3
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
|
||||
// func TestPrefixMultiCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// ---
|
||||
// apples: great
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -d 1 d", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `b:
|
||||
// c: 3
|
||||
// ---
|
||||
// d:
|
||||
// apples: great
|
||||
// `
|
||||
// test.AssertResult(t, expectedOutput, result.Output)
|
||||
// }
|
||||
// func TestPrefixInvalidDocumentIndexCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -df d", filename))
|
||||
// if result.Error == nil {
|
||||
// t.Error("Expected command to fail due to invalid path")
|
||||
// }
|
||||
// expectedOutput := `Document index f is not a integer or *: strconv.ParseInt: parsing "f": invalid syntax`
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
|
||||
// func TestPrefixBadDocumentIndexCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -d 1 d", filename))
|
||||
// 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)`
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
// func TestPrefixMultiAllCmd(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// ---
|
||||
// apples: great
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -d * d", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// expectedOutput := `d:
|
||||
// b:
|
||||
// c: 3
|
||||
// ---
|
||||
// d:
|
||||
// apples: great`
|
||||
// test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||
// }
|
||||
|
||||
// func TestPrefixCmd_Error(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "prefix")
|
||||
// if result.Error == nil {
|
||||
// t.Error("Expected command to fail due to missing arg")
|
||||
// }
|
||||
// expectedOutput := `Must provide <filename> <prefixed_path>`
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
|
||||
// func TestPrefixCmd_ErrorUnreadableFile(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "prefix fake-unknown a.b")
|
||||
// if result.Error == nil {
|
||||
// t.Error("Expected command to fail due to unknown file")
|
||||
// }
|
||||
// var expectedOutput string
|
||||
// if runtime.GOOS == "windows" {
|
||||
// expectedOutput = `open fake-unknown: The system cannot find the file specified.`
|
||||
// } else {
|
||||
// expectedOutput = `open fake-unknown: no such file or directory`
|
||||
// }
|
||||
// test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
// }
|
||||
|
||||
// func TestPrefixCmd_Inplace(t *testing.T) {
|
||||
// content := `b:
|
||||
// c: 3
|
||||
// `
|
||||
// filename := test.WriteTempYamlFile(content)
|
||||
// defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, fmt.Sprintf("prefix -i %s d", filename))
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// gotOutput := test.ReadTempYamlFile(filename)
|
||||
// expectedOutput := `d:
|
||||
// b:
|
||||
// c: 3`
|
||||
// test.AssertResult(t, expectedOutput, strings.Trim(gotOutput, "\n "))
|
||||
// }
|
65
cmd/read.go
65
cmd/read.go
@ -1,65 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
errors "github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func createReadCmd() *cobra.Command {
|
||||
var cmdRead = &cobra.Command{
|
||||
Use: "read [yaml_file] [path_expression]",
|
||||
Aliases: []string{"r"},
|
||||
Short: "yq r [--printMode/-p pv] sample.yaml 'b.e(name==fr*).value'",
|
||||
Example: `
|
||||
yq read things.yaml 'a.b.c'
|
||||
yq r - 'a.b.c' # reads from stdin
|
||||
yq r things.yaml 'a.*.c'
|
||||
yq r things.yaml 'a.**.c' # deep splat
|
||||
yq r things.yaml 'a.(child.subchild==co*).c'
|
||||
yq r -d1 things.yaml 'a.array[0].blah'
|
||||
yq r things.yaml 'a.array[*].blah'
|
||||
yq r -- things.yaml '--key-starting-with-dashes.blah'
|
||||
`,
|
||||
Long: "Outputs the value of the given path in the yaml file to STDOUT",
|
||||
RunE: readProperty,
|
||||
}
|
||||
cmdRead.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
cmdRead.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
||||
cmdRead.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
||||
cmdRead.PersistentFlags().BoolVarP(&collectIntoArray, "collect", "c", false, "collect results into array")
|
||||
cmdRead.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
|
||||
cmdRead.PersistentFlags().BoolVarP(&stripComments, "stripComments", "", false, "print yaml without any comments")
|
||||
cmdRead.PersistentFlags().BoolVarP(&explodeAnchors, "explodeAnchors", "X", false, "explode anchors")
|
||||
cmdRead.PersistentFlags().BoolVarP(&exitStatus, "exitStatus", "e", false, "set exit status if no matches are found")
|
||||
return cmdRead
|
||||
}
|
||||
|
||||
func readProperty(cmd *cobra.Command, args []string) error {
|
||||
var path = ""
|
||||
|
||||
if len(args) < 1 {
|
||||
return errors.New("Must provide filename")
|
||||
} else if len(args) > 1 {
|
||||
path = args[1]
|
||||
}
|
||||
|
||||
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
if errorParsingDocIndex != nil {
|
||||
return errorParsingDocIndex
|
||||
}
|
||||
|
||||
matchingNodes, errorReadingStream := readYamlFile(args[0], path, updateAll, docIndexInt)
|
||||
|
||||
if exitStatus && len(matchingNodes) == 0 {
|
||||
cmd.SilenceUsage = true
|
||||
return errors.New("No matches found")
|
||||
}
|
||||
|
||||
if errorReadingStream != nil {
|
||||
cmd.SilenceUsage = true
|
||||
return errorReadingStream
|
||||
}
|
||||
out := cmd.OutOrStdout()
|
||||
|
||||
return printResults(matchingNodes, out)
|
||||
}
|
1463
cmd/read_test.go
1463
cmd/read_test.go
File diff suppressed because it is too large
Load Diff
70
cmd/root.go
70
cmd/root.go
@ -1,8 +1,11 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib/treeops"
|
||||
"github.com/spf13/cobra"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
@ -17,9 +20,51 @@ func New() *cobra.Command {
|
||||
cmd.Print(GetVersionDisplay())
|
||||
return nil
|
||||
}
|
||||
cmd.Println(cmd.UsageString())
|
||||
if shellCompletion != "" {
|
||||
switch shellCompletion {
|
||||
case "bash", "":
|
||||
return cmd.GenBashCompletion(os.Stdout)
|
||||
case "zsh":
|
||||
return cmd.GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
return cmd.GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
return cmd.GenPowerShellCompletion(os.Stdout)
|
||||
default:
|
||||
return fmt.Errorf("Unknown variant %v", shellCompletion)
|
||||
}
|
||||
}
|
||||
// if len(args) == 0 {
|
||||
// cmd.Println(cmd.UsageString())
|
||||
// return nil
|
||||
// }
|
||||
cmd.SilenceUsage = true
|
||||
|
||||
return nil
|
||||
var treeCreator = treeops.NewPathTreeCreator()
|
||||
|
||||
expression := ""
|
||||
if len(args) > 0 {
|
||||
expression = args[0]
|
||||
}
|
||||
|
||||
pathNode, err := treeCreator.ParsePath(expression)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
matchingNodes, err := evaluate("-", pathNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exitStatus && matchingNodes.Len() == 0 {
|
||||
cmd.SilenceUsage = true
|
||||
return errors.New("No matches found")
|
||||
}
|
||||
|
||||
out := cmd.OutOrStdout()
|
||||
|
||||
return printResults(matchingNodes, out)
|
||||
},
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
@ -44,18 +89,15 @@ func New() *cobra.Command {
|
||||
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print")
|
||||
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
|
||||
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
|
||||
rootCmd.PersistentFlags().BoolVarP(&colorsEnabled, "colors", "C", false, "print with colors")
|
||||
|
||||
rootCmd.AddCommand(
|
||||
createReadCmd(),
|
||||
// createCompareCmd(),
|
||||
createValidateCmd(),
|
||||
// createWriteCmd(),
|
||||
// createPrefixCmd(),
|
||||
// createDeleteCmd(),
|
||||
// createNewCmd(),
|
||||
// createMergeCmd(),
|
||||
createBashCompletionCmd(rootCmd),
|
||||
)
|
||||
rootCmd.Flags().StringVarP(&shellCompletion, "shellCompletion", "", "", "[bash/zsh/powershell/fish] prints shell completion script")
|
||||
|
||||
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
|
||||
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
|
||||
|
||||
// rootCmd.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
rootCmd.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
||||
rootCmd.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
||||
|
||||
return rootCmd
|
||||
}
|
||||
|
@ -1,57 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var shellVariant = "bash"
|
||||
|
||||
func createBashCompletionCmd(rootCmd *cobra.Command) *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "shell-completion",
|
||||
Short: "Generates shell completion scripts",
|
||||
Long: `To load completion for:
|
||||
bash:
|
||||
Run
|
||||
. <(yq shell-completion)
|
||||
|
||||
To configure your bash shell to load completions for each session add to
|
||||
your bashrc
|
||||
|
||||
# ~/.bashrc or ~/.profile
|
||||
. <(yq shell-completion)
|
||||
|
||||
zsh:
|
||||
The generated completion script should be put somewhere in your $fpath named _yq
|
||||
|
||||
powershell:
|
||||
Users need PowerShell version 5.0 or above, which comes with Windows 10 and
|
||||
can be downloaded separately for Windows 7 or 8.1. They can then write the
|
||||
completions to a file and source this file from their PowerShell profile,
|
||||
which is referenced by the $Profile environment variable.
|
||||
|
||||
fish:
|
||||
Save the output to a fish file and add it to your completions directory.
|
||||
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
switch shellVariant {
|
||||
case "bash", "":
|
||||
return rootCmd.GenBashCompletion(os.Stdout)
|
||||
case "zsh":
|
||||
return rootCmd.GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
return rootCmd.GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
return rootCmd.GenPowerShellCompletion(os.Stdout)
|
||||
default:
|
||||
return fmt.Errorf("Unknown variant %v", shellVariant)
|
||||
}
|
||||
},
|
||||
}
|
||||
completionCmd.PersistentFlags().StringVarP(&shellVariant, "variation", "V", "", "shell variation: bash (default), zsh, fish, powershell")
|
||||
return completionCmd
|
||||
}
|
441
cmd/utils.go
441
cmd/utils.go
@ -2,103 +2,73 @@ package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"container/list"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||
"github.com/mikefarah/yq/v3/pkg/yqlib/treeops"
|
||||
errors "github.com/pkg/errors"
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib/treeops"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type readDataFn func(document int, dataBucket *yaml.Node) ([]*treeops.CandidateNode, error)
|
||||
|
||||
func createReadFunction(path string) func(int, *yaml.Node) ([]*treeops.CandidateNode, error) {
|
||||
return func(document int, dataBucket *yaml.Node) ([]*treeops.CandidateNode, error) {
|
||||
return lib.Get(document, dataBucket, path)
|
||||
func readStream(filename string) (*yaml.Decoder, error) {
|
||||
if filename == "" {
|
||||
return nil, errors.New("Must provide filename")
|
||||
}
|
||||
}
|
||||
|
||||
func readYamlFile(filename string, path string, updateAll bool, docIndexInt int) ([]*treeops.CandidateNode, error) {
|
||||
return doReadYamlFile(filename, createReadFunction(path), updateAll, docIndexInt)
|
||||
}
|
||||
|
||||
func doReadYamlFile(filename string, readFn readDataFn, updateAll bool, docIndexInt int) ([]*treeops.CandidateNode, error) {
|
||||
var matchingNodes []*treeops.CandidateNode
|
||||
|
||||
var currentIndex = 0
|
||||
var errorReadingStream = readStream(filename, func(decoder *yaml.Decoder) error {
|
||||
for {
|
||||
var dataBucket yaml.Node
|
||||
errorReading := decoder.Decode(&dataBucket)
|
||||
|
||||
if errorReading == io.EOF {
|
||||
return handleEOF(updateAll, docIndexInt, currentIndex)
|
||||
} else if errorReading != nil {
|
||||
return errorReading
|
||||
}
|
||||
|
||||
var errorParsing error
|
||||
matchingNodes, errorParsing = appendDocument(matchingNodes, dataBucket, readFn, updateAll, docIndexInt, currentIndex)
|
||||
if errorParsing != nil {
|
||||
return errorParsing
|
||||
}
|
||||
if !updateAll && currentIndex == docIndexInt {
|
||||
log.Debug("all done")
|
||||
return nil
|
||||
}
|
||||
currentIndex = currentIndex + 1
|
||||
var stream io.Reader
|
||||
if filename == "-" {
|
||||
stream = bufio.NewReader(os.Stdin)
|
||||
} else {
|
||||
file, err := os.Open(filename) // nolint gosec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
})
|
||||
return matchingNodes, errorReadingStream
|
||||
defer safelyCloseFile(file)
|
||||
stream = file
|
||||
}
|
||||
return yaml.NewDecoder(stream), nil
|
||||
}
|
||||
|
||||
func handleEOF(updateAll bool, docIndexInt int, currentIndex int) error {
|
||||
log.Debugf("done %v / %v", currentIndex, docIndexInt)
|
||||
if !updateAll && currentIndex <= docIndexInt && docIndexInt != 0 {
|
||||
return fmt.Errorf("Could not process document index %v as there are only %v document(s)", docIndex, currentIndex)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func evaluate(filename string, node *treeops.PathTreeNode) (*list.List, error) {
|
||||
|
||||
func appendDocument(originalMatchingNodes []*treeops.CandidateNode, dataBucket yaml.Node, readFn readDataFn, updateAll bool, docIndexInt int, currentIndex int) ([]*treeops.CandidateNode, error) {
|
||||
log.Debugf("processing document %v - requested index %v", currentIndex, docIndexInt)
|
||||
// yqlib.DebugNode(&dataBucket)
|
||||
if !updateAll && currentIndex != docIndexInt {
|
||||
return originalMatchingNodes, nil
|
||||
}
|
||||
log.Debugf("reading in document %v", currentIndex)
|
||||
matchingNodes, errorParsing := readFn(currentIndex, &dataBucket)
|
||||
if errorParsing != nil {
|
||||
return nil, errors.Wrapf(errorParsing, "Error reading path in document index %v", currentIndex)
|
||||
}
|
||||
return append(originalMatchingNodes, matchingNodes...), nil
|
||||
}
|
||||
var treeNavigator = treeops.NewDataTreeNavigator(treeops.NavigationPrefs{})
|
||||
|
||||
func lengthOf(node *yaml.Node) int {
|
||||
kindToCheck := node.Kind
|
||||
if node.Kind == yaml.DocumentNode && len(node.Content) == 1 {
|
||||
log.Debugf("length of document node, calculating length of child")
|
||||
kindToCheck = node.Content[0].Kind
|
||||
}
|
||||
switch kindToCheck {
|
||||
case yaml.ScalarNode:
|
||||
return len(node.Value)
|
||||
case yaml.MappingNode:
|
||||
return len(node.Content) / 2
|
||||
default:
|
||||
return len(node.Content)
|
||||
}
|
||||
}
|
||||
var matchingNodes = list.New()
|
||||
|
||||
// transforms node before printing, if required
|
||||
func transformNode(node *yaml.Node) *yaml.Node {
|
||||
if printLength {
|
||||
return &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", lengthOf(node))}
|
||||
var currentIndex uint = 0
|
||||
var decoder, err = readStream(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return node
|
||||
|
||||
for {
|
||||
var dataBucket yaml.Node
|
||||
errorReading := decoder.Decode(&dataBucket)
|
||||
|
||||
if errorReading == io.EOF {
|
||||
return matchingNodes, nil
|
||||
} else if errorReading != nil {
|
||||
return nil, errorReading
|
||||
}
|
||||
candidateNode := &treeops.CandidateNode{
|
||||
Document: currentIndex,
|
||||
Filename: filename,
|
||||
Node: &dataBucket,
|
||||
}
|
||||
inputList := list.New()
|
||||
inputList.PushBack(candidateNode)
|
||||
|
||||
newMatches, errorParsing := treeNavigator.GetMatchingNodes(inputList, node)
|
||||
if errorParsing != nil {
|
||||
return nil, errorParsing
|
||||
}
|
||||
matchingNodes.PushBackList(newMatches)
|
||||
currentIndex = currentIndex + 1
|
||||
}
|
||||
|
||||
return matchingNodes, nil
|
||||
}
|
||||
|
||||
func printNode(node *yaml.Node, writer io.Writer) error {
|
||||
@ -114,9 +84,10 @@ func printNode(node *yaml.Node, writer io.Writer) error {
|
||||
return encoder.Encode(node)
|
||||
}
|
||||
|
||||
func removeComments(matchingNodes []*treeops.CandidateNode) {
|
||||
for _, nodeContext := range matchingNodes {
|
||||
removeCommentOfNode(nodeContext.Node)
|
||||
func removeComments(matchingNodes *list.List) {
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*treeops.CandidateNode)
|
||||
removeCommentOfNode(candidate.Node)
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,9 +101,10 @@ func removeCommentOfNode(node *yaml.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func setStyle(matchingNodes []*treeops.CandidateNode, style yaml.Style) {
|
||||
for _, nodeContext := range matchingNodes {
|
||||
updateStyleOfNode(nodeContext.Node, style)
|
||||
func setStyle(matchingNodes *list.List, style yaml.Style) {
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*treeops.CandidateNode)
|
||||
updateStyleOfNode(candidate.Node, style)
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,9 +206,10 @@ func explodeNode(node *yaml.Node) error {
|
||||
}
|
||||
}
|
||||
|
||||
func explode(matchingNodes []*treeops.CandidateNode) error {
|
||||
func explode(matchingNodes *list.List) error {
|
||||
log.Debug("exploding nodes")
|
||||
for _, nodeContext := range matchingNodes {
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
nodeContext := el.Value.(*treeops.CandidateNode)
|
||||
log.Debugf("exploding %v", nodeContext.GetKey())
|
||||
errorExplodingNode := explodeNode(nodeContext.Node)
|
||||
if errorExplodingNode != nil {
|
||||
@ -246,7 +219,7 @@ func explode(matchingNodes []*treeops.CandidateNode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) error {
|
||||
func printResults(matchingNodes *list.List, writer io.Writer) error {
|
||||
if prettyPrint {
|
||||
setStyle(matchingNodes, 0)
|
||||
}
|
||||
@ -255,6 +228,12 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro
|
||||
removeComments(matchingNodes)
|
||||
}
|
||||
|
||||
fileInfo, _ := os.Stdout.Stat()
|
||||
|
||||
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
||||
colorsEnabled = true
|
||||
}
|
||||
|
||||
//always explode anchors when printing json
|
||||
if explodeAnchors || outputToJSON {
|
||||
errorExploding := explode(matchingNodes)
|
||||
@ -266,7 +245,7 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro
|
||||
bufferedWriter := bufio.NewWriter(writer)
|
||||
defer safelyFlush(bufferedWriter)
|
||||
|
||||
if len(matchingNodes) == 0 {
|
||||
if matchingNodes.Len() == 0 {
|
||||
log.Debug("no matching results, nothing to print")
|
||||
if defaultValue != "" {
|
||||
return writeString(bufferedWriter, defaultValue)
|
||||
@ -275,9 +254,9 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro
|
||||
}
|
||||
var errorWriting error
|
||||
|
||||
var arrayCollection = yaml.Node{Kind: yaml.SequenceNode}
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
mappedDoc := el.Value.(*treeops.CandidateNode)
|
||||
|
||||
for _, mappedDoc := range matchingNodes {
|
||||
switch printMode {
|
||||
case "p":
|
||||
errorWriting = writeString(bufferedWriter, mappedDoc.PathStackToString()+"\n")
|
||||
@ -289,251 +268,24 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro
|
||||
var parentNode = yaml.Node{Kind: yaml.MappingNode}
|
||||
parentNode.Content = make([]*yaml.Node, 2)
|
||||
parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: mappedDoc.PathStackToString()}
|
||||
parentNode.Content[1] = transformNode(mappedDoc.Node)
|
||||
if collectIntoArray {
|
||||
arrayCollection.Content = append(arrayCollection.Content, &parentNode)
|
||||
} else if err := printNode(&parentNode, bufferedWriter); err != nil {
|
||||
if mappedDoc.Node.Kind == yaml.DocumentNode {
|
||||
parentNode.Content[1] = mappedDoc.Node.Content[0]
|
||||
} else {
|
||||
parentNode.Content[1] = mappedDoc.Node
|
||||
}
|
||||
if err := printNode(&parentNode, bufferedWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if collectIntoArray {
|
||||
arrayCollection.Content = append(arrayCollection.Content, mappedDoc.Node)
|
||||
} else if err := printNode(transformNode(mappedDoc.Node), bufferedWriter); err != nil {
|
||||
if err := printNode(mappedDoc.Node, bufferedWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if collectIntoArray {
|
||||
if err := printNode(transformNode(&arrayCollection), bufferedWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseDocumentIndex() (bool, int, error) {
|
||||
if docIndex == "*" {
|
||||
return true, -1, nil
|
||||
}
|
||||
docIndexInt64, err := strconv.ParseInt(docIndex, 10, 32)
|
||||
if err != nil {
|
||||
return false, -1, errors.Wrapf(err, "Document index %v is not a integer or *", docIndex)
|
||||
}
|
||||
return false, int(docIndexInt64), nil
|
||||
}
|
||||
|
||||
type updateDataFn func(dataBucket *yaml.Node, currentIndex int) error
|
||||
|
||||
func isNullDocument(dataBucket *yaml.Node) bool {
|
||||
return dataBucket.Kind == yaml.DocumentNode && (len(dataBucket.Content) == 0 ||
|
||||
dataBucket.Content[0].Kind == yaml.ScalarNode && dataBucket.Content[0].Tag == "!!null")
|
||||
}
|
||||
|
||||
func mapYamlDecoder(updateData updateDataFn, encoder yqlib.Encoder) yamlDecoderFn {
|
||||
return func(decoder *yaml.Decoder) error {
|
||||
var dataBucket yaml.Node
|
||||
var errorReading error
|
||||
var errorWriting error
|
||||
var errorUpdating error
|
||||
var currentIndex = 0
|
||||
|
||||
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
if errorParsingDocIndex != nil {
|
||||
return errorParsingDocIndex
|
||||
}
|
||||
|
||||
for {
|
||||
log.Debugf("Read doc %v", currentIndex)
|
||||
errorReading = decoder.Decode(&dataBucket)
|
||||
|
||||
if errorReading == io.EOF && docIndexInt == 0 && currentIndex == 0 {
|
||||
//empty document, lets just make one
|
||||
dataBucket = yaml.Node{Kind: yaml.DocumentNode, Content: make([]*yaml.Node, 1)}
|
||||
child := yaml.Node{Kind: yaml.MappingNode}
|
||||
dataBucket.Content[0] = &child
|
||||
} else if isNullDocument(&dataBucket) && (updateAll || docIndexInt == currentIndex) {
|
||||
child := yaml.Node{Kind: yaml.MappingNode}
|
||||
dataBucket.Content[0] = &child
|
||||
} else if errorReading == io.EOF {
|
||||
if !updateAll && currentIndex <= docIndexInt {
|
||||
return fmt.Errorf("asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
}
|
||||
return nil
|
||||
} else if errorReading != nil {
|
||||
return errors.Wrapf(errorReading, "Error reading document at index %v, %v", currentIndex, errorReading)
|
||||
}
|
||||
errorUpdating = updateData(&dataBucket, currentIndex)
|
||||
if errorUpdating != nil {
|
||||
return errors.Wrapf(errorUpdating, "Error updating document at index %v", currentIndex)
|
||||
}
|
||||
|
||||
if prettyPrint {
|
||||
updateStyleOfNode(&dataBucket, 0)
|
||||
}
|
||||
|
||||
errorWriting = encoder.Encode(&dataBucket)
|
||||
|
||||
if errorWriting != nil {
|
||||
return errors.Wrapf(errorWriting, "Error writing document at index %v, %v", currentIndex, errorWriting)
|
||||
}
|
||||
currentIndex = currentIndex + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func prefixDocument(updateAll bool, docIndexInt int, currentIndex int, dataBucket *yaml.Node, updateCommand yqlib.UpdateCommand) error {
|
||||
// if updateAll || currentIndex == docIndexInt {
|
||||
// log.Debugf("Prefixing document %v", currentIndex)
|
||||
// // yqlib.DebugNode(dataBucket)
|
||||
// updateCommand.Value = dataBucket.Content[0]
|
||||
// dataBucket.Content = make([]*yaml.Node, 1)
|
||||
|
||||
// newNode := lib.New(updateCommand.Path)
|
||||
// dataBucket.Content[0] = &newNode
|
||||
|
||||
// errorUpdating := lib.Update(dataBucket, updateCommand, true)
|
||||
// if errorUpdating != nil {
|
||||
// return errorUpdating
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func updateDoc(inputFile string, updateCommands []yqlib.UpdateCommand, writer io.Writer) error {
|
||||
// var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
// if errorParsingDocIndex != nil {
|
||||
// return errorParsingDocIndex
|
||||
// }
|
||||
|
||||
// var updateData = func(dataBucket *yaml.Node, currentIndex int) error {
|
||||
// if updateAll || currentIndex == docIndexInt {
|
||||
// log.Debugf("Updating doc %v", currentIndex)
|
||||
// for _, updateCommand := range updateCommands {
|
||||
// log.Debugf("Processing update to Path %v", updateCommand.Path)
|
||||
// errorUpdating := lib.Update(dataBucket, updateCommand, autoCreateFlag)
|
||||
// if errorUpdating != nil {
|
||||
// return errorUpdating
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
// return readAndUpdate(writer, inputFile, updateData)
|
||||
// }
|
||||
|
||||
// func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) error {
|
||||
// var destination io.Writer
|
||||
// var destinationName string
|
||||
// var completedSuccessfully = false
|
||||
// if writeInplace {
|
||||
// info, err := os.Stat(inputFile)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// // mkdir temp dir as some docker images does not have temp dir
|
||||
// _, err = os.Stat(os.TempDir())
|
||||
// if os.IsNotExist(err) {
|
||||
// err = os.Mkdir(os.TempDir(), 0700)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// } else if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// tempFile, err := ioutil.TempFile("", "temp")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// destinationName = tempFile.Name()
|
||||
// err = os.Chmod(destinationName, info.Mode())
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// destination = tempFile
|
||||
// defer func() {
|
||||
// safelyCloseFile(tempFile)
|
||||
// if completedSuccessfully {
|
||||
// safelyRenameFile(tempFile.Name(), inputFile)
|
||||
// }
|
||||
// }()
|
||||
// } else {
|
||||
// destination = stdOut
|
||||
// destinationName = "Stdout"
|
||||
// }
|
||||
|
||||
// log.Debugf("Writing to %v from %v", destinationName, inputFile)
|
||||
|
||||
// bufferedWriter := bufio.NewWriter(destination)
|
||||
// defer safelyFlush(bufferedWriter)
|
||||
|
||||
// var encoder yqlib.Encoder
|
||||
// if outputToJSON {
|
||||
// encoder = yqlib.NewJsonEncoder(bufferedWriter, prettyPrint, indent)
|
||||
// } else {
|
||||
// encoder = yqlib.NewYamlEncoder(bufferedWriter, indent, colorsEnabled)
|
||||
// }
|
||||
|
||||
// var errorProcessing = readStream(inputFile, mapYamlDecoder(updateData, encoder))
|
||||
// completedSuccessfully = errorProcessing == nil
|
||||
// return errorProcessing
|
||||
// }
|
||||
|
||||
type updateCommandParsed struct {
|
||||
Command string
|
||||
Path string
|
||||
Value yaml.Node
|
||||
}
|
||||
|
||||
// func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string, allowNoValue bool) ([]yqlib.UpdateCommand, error) {
|
||||
// var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
|
||||
// if writeScript != "" {
|
||||
// var parsedCommands = make([]updateCommandParsed, 0)
|
||||
|
||||
// err := readData(writeScript, 0, &parsedCommands)
|
||||
|
||||
// if err != nil && err != io.EOF {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// log.Debugf("Read write commands file '%v'", parsedCommands)
|
||||
// for index := range parsedCommands {
|
||||
// parsedCommand := parsedCommands[index]
|
||||
// updateCommand := yqlib.UpdateCommand{Command: parsedCommand.Command, Path: parsedCommand.Path, Value: &parsedCommand.Value, Overwrite: true}
|
||||
// updateCommands = append(updateCommands, updateCommand)
|
||||
// }
|
||||
|
||||
// log.Debugf("Read write commands file '%v'", updateCommands)
|
||||
// } else if sourceYamlFile != "" && len(args) == expectedArgs-1 {
|
||||
// log.Debugf("Reading value from %v", sourceYamlFile)
|
||||
// var value yaml.Node
|
||||
// err := readData(sourceYamlFile, 0, &value)
|
||||
// if err != nil && err != io.EOF {
|
||||
// return nil, err
|
||||
// }
|
||||
// log.Debug("args %v", args[expectedArgs-2])
|
||||
// updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||
// updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: value.Content[0], Overwrite: true}
|
||||
// } else if len(args) == expectedArgs {
|
||||
// updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||
// log.Debug("args %v", args)
|
||||
// log.Debug("path %v", args[expectedArgs-2])
|
||||
// log.Debug("Value %v", args[expectedArgs-1])
|
||||
// value := valueParser.Parse(args[expectedArgs-1], customTag, customStyle, anchorName, makeAlias)
|
||||
// updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: value, Overwrite: true, CommentsMergeStrategy: yqlib.IgnoreCommentsMergeStrategy}
|
||||
// } else if len(args) == expectedArgs-1 && allowNoValue {
|
||||
// // don't update the value
|
||||
// updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||
// log.Debug("args %v", args)
|
||||
// log.Debug("path %v", args[expectedArgs-2])
|
||||
// updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse("", customTag, customStyle, anchorName, makeAlias), Overwrite: true, DontUpdateNodeValue: true}
|
||||
// } else {
|
||||
// return nil, errors.New(badArgsMessage)
|
||||
// }
|
||||
// return updateCommands, nil
|
||||
// }
|
||||
|
||||
func safelyRenameFile(from string, to string) {
|
||||
if renameError := os.Rename(from, to); renameError != nil {
|
||||
log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
|
||||
@ -584,36 +336,3 @@ func safelyCloseFile(file *os.File) {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type yamlDecoderFn func(*yaml.Decoder) error
|
||||
|
||||
func readStream(filename string, yamlDecoder yamlDecoderFn) error {
|
||||
if filename == "" {
|
||||
return errors.New("Must provide filename")
|
||||
}
|
||||
|
||||
var stream io.Reader
|
||||
if filename == "-" {
|
||||
stream = bufio.NewReader(os.Stdin)
|
||||
} else {
|
||||
file, err := os.Open(filename) // nolint gosec
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer safelyCloseFile(file)
|
||||
stream = file
|
||||
}
|
||||
return yamlDecoder(yaml.NewDecoder(stream))
|
||||
}
|
||||
|
||||
func readData(filename string, indexToRead int, parsedData interface{}) error {
|
||||
return readStream(filename, func(decoder *yaml.Decoder) error {
|
||||
for currentIndex := 0; currentIndex < indexToRead; currentIndex++ {
|
||||
errorSkipping := decoder.Decode(parsedData)
|
||||
if errorSkipping != nil {
|
||||
return errors.Wrapf(errorSkipping, "Error processing document at index %v, %v", currentIndex, errorSkipping)
|
||||
}
|
||||
}
|
||||
return decoder.Decode(parsedData)
|
||||
})
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
errors "github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func createValidateCmd() *cobra.Command {
|
||||
var cmdRead = &cobra.Command{
|
||||
Use: "validate [yaml_file]",
|
||||
Aliases: []string{"v"},
|
||||
Short: "yq v sample.yaml",
|
||||
Example: `
|
||||
yq v - # reads from stdin
|
||||
`,
|
||||
RunE: validateProperty,
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: false,
|
||||
}
|
||||
cmdRead.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
return cmdRead
|
||||
}
|
||||
|
||||
func validateProperty(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return errors.New("Must provide filename")
|
||||
}
|
||||
|
||||
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
if errorParsingDocIndex != nil {
|
||||
return errorParsingDocIndex
|
||||
}
|
||||
|
||||
_, errorReadingStream := readYamlFile(args[0], "", updateAll, docIndexInt)
|
||||
|
||||
return errorReadingStream
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v3/test"
|
||||
)
|
||||
|
||||
func TestValidateCmd(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "validate ../examples/sample.yaml b.c")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
test.AssertResult(t, "", result.Output)
|
||||
}
|
||||
|
||||
func TestValidateBadDataCmd(t *testing.T) {
|
||||
content := `[!Whatever]`
|
||||
filename := test.WriteTempYamlFile(content)
|
||||
defer test.RemoveTempYamlFile(filename)
|
||||
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, fmt.Sprintf("validate %s", filename))
|
||||
if result.Error == nil {
|
||||
t.Error("Expected command to fail")
|
||||
}
|
||||
expectedOutput := `yaml: line 1: did not find expected ',' or ']'`
|
||||
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
}
|
@ -11,7 +11,7 @@ var (
|
||||
GitDescribe string
|
||||
|
||||
// Version is main version number that is being run at the moment.
|
||||
Version = "3.4.0"
|
||||
Version = "4.0.0-beta"
|
||||
|
||||
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||
|
@ -1,3 +1,5 @@
|
||||
# Some doc
|
||||
|
||||
a: true
|
||||
b:
|
||||
c: 2
|
||||
|
2
go.mod
2
go.mod
@ -1,4 +1,4 @@
|
||||
module github.com/mikefarah/yq/v3
|
||||
module github.com/mikefarah/yq/v4
|
||||
|
||||
require (
|
||||
github.com/elliotchance/orderedmap v1.3.0 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -77,6 +77,10 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mikefarah/yq v1.15.0 h1:ViMYNRG5UB7hzm8olxMFqPtkpMXXKO4g32/v9JUa62o=
|
||||
github.com/mikefarah/yq v2.4.0+incompatible h1:oBxbWy8R9hI3BIUUxEf0CzikWa2AgnGrGhvGQt5jgjk=
|
||||
github.com/mikefarah/yq/v3 v3.0.0-20201020025845-ccb718cd0f59 h1:6nvF+EEFIVD4KT64CgvAzWaMVC283Huno59khWs9r1A=
|
||||
github.com/mikefarah/yq/v3 v3.0.0-20201020025845-ccb718cd0f59/go.mod h1:7eVjFf5bgozMuHk+oKpyxR2zCN3iEN1tF0/bM5jvtKo=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
|
@ -13,6 +13,7 @@ type CandidateNode struct {
|
||||
Node *yaml.Node // the actual node
|
||||
Path []interface{} /// the path we took to get to this node
|
||||
Document uint // the document index of this node
|
||||
Filename string
|
||||
}
|
||||
|
||||
func (n *CandidateNode) GetKey() string {
|
||||
|
@ -17,34 +17,17 @@ type NavigationPrefs struct {
|
||||
}
|
||||
|
||||
type DataTreeNavigator interface {
|
||||
GetMatchingNodes(matchingNodes []*CandidateNode, pathNode *PathTreeNode) ([]*CandidateNode, error)
|
||||
// given a list of CandidateEntities and a pathNode,
|
||||
// this will process the list against the given pathNode and return
|
||||
// a new list of matching candidates
|
||||
GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error)
|
||||
}
|
||||
|
||||
func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator {
|
||||
return &dataTreeNavigator{navigationPrefs}
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes []*CandidateNode, pathNode *PathTreeNode) ([]*CandidateNode, error) {
|
||||
var matchingNodeMap = list.New()
|
||||
|
||||
for _, n := range matchingNodes {
|
||||
matchingNodeMap.PushBack(n)
|
||||
}
|
||||
|
||||
matchedNodes, err := d.getMatchingNodes(matchingNodeMap, pathNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values := make([]*CandidateNode, 0, matchedNodes.Len())
|
||||
|
||||
for el := matchedNodes.Front(); el != nil; el = el.Next() {
|
||||
values = append(values, el.Value.(*CandidateNode))
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) getMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
if pathNode == nil {
|
||||
log.Debugf("getMatchingNodes - nothing to do")
|
||||
return matchingNodes, nil
|
||||
|
@ -1,6 +1,7 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -10,9 +11,10 @@ import (
|
||||
var treeNavigator = NewDataTreeNavigator(NavigationPrefs{})
|
||||
var treeCreator = NewPathTreeCreator()
|
||||
|
||||
func readDoc(t *testing.T, content string) []*CandidateNode {
|
||||
func readDoc(t *testing.T, content string) *list.List {
|
||||
inputList := list.New()
|
||||
if content == "" {
|
||||
return []*CandidateNode{}
|
||||
return inputList
|
||||
}
|
||||
decoder := yaml.NewDecoder(strings.NewReader(content))
|
||||
var dataBucket yaml.Node
|
||||
@ -21,12 +23,19 @@ func readDoc(t *testing.T, content string) []*CandidateNode {
|
||||
t.Error(content)
|
||||
t.Error(err)
|
||||
}
|
||||
return []*CandidateNode{&CandidateNode{Node: dataBucket.Content[0], Document: 0}}
|
||||
|
||||
inputList.PushBack(&CandidateNode{
|
||||
Document: 0,
|
||||
Filename: "test.yml",
|
||||
Node: &dataBucket,
|
||||
})
|
||||
return inputList
|
||||
}
|
||||
|
||||
func resultsToString(results []*CandidateNode) []string {
|
||||
func resultsToString(results *list.List) []string {
|
||||
var pretty []string = make([]string, 0)
|
||||
for _, n := range results {
|
||||
for el := results.Front(); el != nil; el = el.Next() {
|
||||
n := el.Value.(*CandidateNode)
|
||||
pretty = append(pretty, NodeToString(n))
|
||||
}
|
||||
return pretty
|
||||
|
@ -101,34 +101,6 @@ func (p *Operation) toString() string {
|
||||
}
|
||||
}
|
||||
|
||||
type YqTreeLib interface {
|
||||
Get(document int, documentNode *yaml.Node, path string) ([]*CandidateNode, error)
|
||||
// GetForMerge(rootNode *yaml.Node, path string, arrayMergeStrategy ArrayMergeStrategy) ([]*NodeContext, error)
|
||||
// Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error
|
||||
// New(path string) yaml.Node
|
||||
|
||||
// PathStackToString(pathStack []interface{}) string
|
||||
// MergePathStackToString(pathStack []interface{}, arrayMergeStrategy ArrayMergeStrategy) string
|
||||
}
|
||||
|
||||
func NewYqTreeLib() YqTreeLib {
|
||||
return &lib{treeCreator: NewPathTreeCreator()}
|
||||
}
|
||||
|
||||
type lib struct {
|
||||
treeCreator PathTreeCreator
|
||||
}
|
||||
|
||||
func (l *lib) Get(document int, documentNode *yaml.Node, path string) ([]*CandidateNode, error) {
|
||||
nodes := []*CandidateNode{&CandidateNode{Node: documentNode.Content[0], Document: 0}}
|
||||
navigator := NewDataTreeNavigator(NavigationPrefs{})
|
||||
pathNode, errPath := l.treeCreator.ParsePath(path)
|
||||
if errPath != nil {
|
||||
return nil, errPath
|
||||
}
|
||||
return navigator.GetMatchingNodes(nodes, pathNode)
|
||||
}
|
||||
|
||||
//use for debugging only
|
||||
func NodesToString(collection *list.List) string {
|
||||
if !log.IsEnabledFor(logging.DEBUG) {
|
||||
@ -157,7 +129,11 @@ func NodeToString(node *CandidateNode) string {
|
||||
log.Error("Error debugging node, %v", errorEncoding.Error())
|
||||
}
|
||||
encoder.Close()
|
||||
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.Path, value.Tag, buf.String())
|
||||
tag := value.Tag
|
||||
if value.Kind == yaml.DocumentNode {
|
||||
tag = "doc"
|
||||
}
|
||||
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.Path, tag, buf.String())
|
||||
}
|
||||
|
||||
func KindString(kind yaml.Kind) string {
|
||||
|
@ -3,14 +3,14 @@ package treeops
|
||||
import "container/list"
|
||||
|
||||
func AssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -28,14 +28,14 @@ func AssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *Pa
|
||||
|
||||
// does not update content or values
|
||||
func AssignAttributesOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -9,61 +9,70 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: frog}}\n",
|
||||
"D0, P[], (doc)::{a: {b: frog}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b | (. |= "frog")`,
|
||||
expected: []string{
|
||||
"D0, P[a b], (!!str)::frog\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= 5`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: 5}}\n",
|
||||
"D0, P[], (doc)::{a: {b: 5}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= 3.142`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: 3.142}}\n",
|
||||
"D0, P[], (doc)::{a: {b: 3.142}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {b: {g: foof}}}`,
|
||||
expression: `.a |= .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {g: foof}}\n",
|
||||
"D0, P[], (doc)::{a: {g: foof}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {b: apple, c: cactus}}`,
|
||||
expression: `.a[] | select(. == "apple") |= "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: frog, c: cactus}}\n",
|
||||
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `[candy, apple, sandy]`,
|
||||
expression: `.[] | select(. == "*andy") |= "bogs"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::[bogs, apple, bogs]\n",
|
||||
"D0, P[], (doc)::[bogs, apple, bogs]\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{}`,
|
||||
expression: `.a.b |= "bogs"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: bogs}}\n",
|
||||
"D0, P[], (doc)::{a: {b: bogs}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{}`,
|
||||
expression: `.a.b[0] |= "bogs"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: [bogs]}}\n",
|
||||
"D0, P[], (doc)::{a: {b: [bogs]}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{}`,
|
||||
expression: `.a.b[1].c |= "bogs"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: [null, {c: bogs}]}}\n",
|
||||
"D0, P[], (doc)::{a: {b: [null, {c: bogs}]}}\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -7,8 +7,9 @@ import (
|
||||
)
|
||||
|
||||
func isTruthy(c *CandidateNode) (bool, error) {
|
||||
node := c.Node
|
||||
node := UnwrapDoc(c.Node)
|
||||
value := true
|
||||
|
||||
if node.Tag == "!!null" {
|
||||
return false, nil
|
||||
}
|
||||
@ -29,11 +30,11 @@ func booleanOp(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTre
|
||||
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
lhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -19,7 +19,7 @@ func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNod
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
elMap := list.New()
|
||||
elMap.PushBack(candidate)
|
||||
nodesToDelete, err := d.getMatchingNodes(elMap, pathNode.Rhs)
|
||||
nodesToDelete, err := d.GetMatchingNodes(elMap, pathNode.Rhs)
|
||||
log.Debug("nodesToDelete:\n%v", NodesToString(nodesToDelete))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -11,12 +11,12 @@ import (
|
||||
type CrossFunctionCalculation func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error)
|
||||
|
||||
func crossFunction(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode, calculation CrossFunctionCalculation) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rhs, err := d.getMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -46,6 +46,9 @@ func MultiplyOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *
|
||||
}
|
||||
|
||||
func multiply(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
lhs.Node = UnwrapDoc(lhs.Node)
|
||||
rhs.Node = UnwrapDoc(rhs.Node)
|
||||
|
||||
if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode ||
|
||||
(lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) {
|
||||
var results = list.New()
|
||||
@ -93,7 +96,7 @@ func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *Candid
|
||||
|
||||
assignmentOpNode := &PathTreeNode{Operation: assignmentOp, Lhs: createTraversalTree(lhsPath), Rhs: &PathTreeNode{Operation: rhsOp}}
|
||||
|
||||
_, err := d.getMatchingNodes(nodeToMap(lhs), assignmentOpNode)
|
||||
_, err := d.GetMatchingNodes(nodeToMap(lhs), assignmentOpNode)
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -11,43 +11,50 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {also: me}, b: {also: [1]}}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {also: [1]}, b: {also: [1]}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {also: me}, b: {also: {g: wizz}}}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {also: {g: wizz}}, b: {also: {g: wizz}}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {also: {g: wizz}}, b: {also: me}}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {also: {g: wizz}}, b: {also: [1]}}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {also: [1]}, b: {also: [1]}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {also: [1]}, b: {also: {g: wizz}}}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {also: {g: wizz}}, b: {also: {g: wizz}}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {things: great}, b: {also: me}}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {things: great, also: me}, b: {also: me}}\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `a: {things: great}
|
||||
b:
|
||||
also: "me"
|
||||
@ -59,7 +66,8 @@ b:
|
||||
also: "me"
|
||||
`,
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: [1,2,3], b: [3,4,5]}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
|
@ -5,27 +5,27 @@ import (
|
||||
)
|
||||
|
||||
var notOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
document: `cat`,
|
||||
expression: `. | not`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `1`,
|
||||
expression: `. | not`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `0`,
|
||||
expression: `. | not`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
// {
|
||||
// document: `cat`,
|
||||
// expression: `. | not`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::false\n",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// document: `1`,
|
||||
// expression: `. | not`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::false\n",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// document: `0`,
|
||||
// expression: `. | not`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::false\n",
|
||||
// },
|
||||
// },
|
||||
{
|
||||
document: `~`,
|
||||
expression: `. | not`,
|
||||
@ -33,20 +33,20 @@ var notOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `false`,
|
||||
expression: `. | not`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `true`,
|
||||
expression: `. | not`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
// {
|
||||
// document: `false`,
|
||||
// expression: `. | not`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::true\n",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// document: `true`,
|
||||
// expression: `. | not`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::false\n",
|
||||
// },
|
||||
// },
|
||||
}
|
||||
|
||||
func TestNotOperatorScenarios(t *testing.T) {
|
||||
|
@ -18,6 +18,10 @@ func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNod
|
||||
func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List) error {
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
candidate.Node = UnwrapDoc(candidate.Node)
|
||||
|
||||
log.Debugf("Recursive Decent, added %v", NodeToString(candidate))
|
||||
results.PushBack(candidate)
|
||||
|
||||
children, err := Splat(d, nodeToMap(candidate))
|
||||
|
@ -11,14 +11,16 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
||||
expected: []string{
|
||||
"D0, P[], (!!str)::cat\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: frog}`,
|
||||
expression: `..`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: frog}\n",
|
||||
"D0, P[a], (!!str)::frog\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `..`,
|
||||
expected: []string{
|
||||
@ -26,7 +28,8 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
||||
"D0, P[a], (!!map)::{b: apple}\n",
|
||||
"D0, P[a b], (!!str)::apple\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `[1,2,3]`,
|
||||
expression: `..`,
|
||||
expected: []string{
|
||||
@ -35,7 +38,8 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
||||
"D0, P[1], (!!int)::2\n",
|
||||
"D0, P[2], (!!int)::3\n",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
document: `[{a: cat},2,true]`,
|
||||
expression: `..`,
|
||||
expected: []string{
|
||||
|
@ -12,7 +12,7 @@ func SelectOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *Pa
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -3,11 +3,11 @@ package treeops
|
||||
import "container/list"
|
||||
|
||||
func UnionOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rhs, err := d.getMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -9,12 +9,19 @@ import (
|
||||
|
||||
type OperatorHandler func(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error)
|
||||
|
||||
func UnwrapDoc(node *yaml.Node) *yaml.Node {
|
||||
if node.Kind == yaml.DocumentNode {
|
||||
return node.Content[0]
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func PipeOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.getMatchingNodes(lhs, pathNode.Rhs)
|
||||
return d.GetMatchingNodes(lhs, pathNode.Rhs)
|
||||
}
|
||||
|
||||
func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v3/test"
|
||||
"github.com/mikefarah/yq/v4/test"
|
||||
)
|
||||
|
||||
type expressionScenario struct {
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v3/test"
|
||||
"github.com/mikefarah/yq/v4/test"
|
||||
)
|
||||
|
||||
var pathTests = []struct {
|
||||
|
Loading…
Reference in New Issue
Block a user