mirror of
				https://github.com/taigrr/yq
				synced 2025-01-18 04:53:17 -08:00 
			
		
		
		
	first cli
This commit is contained in:
		
							parent
							
								
									badd476730
								
							
						
					
					
						commit
						85d059340b
					
				| @ -1,83 +1,83 @@ | |||||||
| package cmd | package cmd | ||||||
| 
 | 
 | ||||||
| import ( | // import ( | ||||||
| 	"strings" | // 	"strings" | ||||||
| 	"testing" | // 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/mikefarah/yq/v3/test" | // 	"github.com/mikefarah/yq/v3/test" | ||||||
| 	"github.com/spf13/cobra" | // 	"github.com/spf13/cobra" | ||||||
| ) | // ) | ||||||
| 
 | 
 | ||||||
| func getRootCommand() *cobra.Command { | // func getRootCommand() *cobra.Command { | ||||||
| 	return New() | // 	return New() | ||||||
| } | // } | ||||||
| 
 | 
 | ||||||
| func TestRootCmd(t *testing.T) { | // func TestRootCmd(t *testing.T) { | ||||||
| 	cmd := getRootCommand() | // 	cmd := getRootCommand() | ||||||
| 	result := test.RunCmd(cmd, "") | // 	result := test.RunCmd(cmd, "") | ||||||
| 	if result.Error != nil { | // 	if result.Error != nil { | ||||||
| 		t.Error(result.Error) | // 		t.Error(result.Error) | ||||||
| 	} | // 	} | ||||||
| 
 | 
 | ||||||
| 	if !strings.Contains(result.Output, "Usage:") { | // 	if !strings.Contains(result.Output, "Usage:") { | ||||||
| 		t.Error("Expected usage message to be printed out, but the usage message was not found.") | // 		t.Error("Expected usage message to be printed out, but the usage message was not found.") | ||||||
| 	} | // 	} | ||||||
| } | // } | ||||||
| 
 | 
 | ||||||
| func TestRootCmd_Help(t *testing.T) { | // func TestRootCmd_Help(t *testing.T) { | ||||||
| 	cmd := getRootCommand() | // 	cmd := getRootCommand() | ||||||
| 	result := test.RunCmd(cmd, "--help") | // 	result := test.RunCmd(cmd, "--help") | ||||||
| 	if result.Error != nil { | // 	if result.Error != nil { | ||||||
| 		t.Error(result.Error) | // 		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.") { | // 	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.") | // 		t.Error("Expected usage message to be printed out, but the usage message was not found.") | ||||||
| 	} | // 	} | ||||||
| } | // } | ||||||
| 
 | 
 | ||||||
| func TestRootCmd_VerboseLong(t *testing.T) { | // func TestRootCmd_VerboseLong(t *testing.T) { | ||||||
| 	cmd := getRootCommand() | // 	cmd := getRootCommand() | ||||||
| 	result := test.RunCmd(cmd, "--verbose") | // 	result := test.RunCmd(cmd, "--verbose") | ||||||
| 	if result.Error != nil { | // 	if result.Error != nil { | ||||||
| 		t.Error(result.Error) | // 		t.Error(result.Error) | ||||||
| 	} | // 	} | ||||||
| 
 | 
 | ||||||
| 	if !verbose { | // 	if !verbose { | ||||||
| 		t.Error("Expected verbose to be true") | // 		t.Error("Expected verbose to be true") | ||||||
| 	} | // 	} | ||||||
| } | // } | ||||||
| 
 | 
 | ||||||
| func TestRootCmd_VerboseShort(t *testing.T) { | // func TestRootCmd_VerboseShort(t *testing.T) { | ||||||
| 	cmd := getRootCommand() | // 	cmd := getRootCommand() | ||||||
| 	result := test.RunCmd(cmd, "-v") | // 	result := test.RunCmd(cmd, "-v") | ||||||
| 	if result.Error != nil { | // 	if result.Error != nil { | ||||||
| 		t.Error(result.Error) | // 		t.Error(result.Error) | ||||||
| 	} | // 	} | ||||||
| 
 | 
 | ||||||
| 	if !verbose { | // 	if !verbose { | ||||||
| 		t.Error("Expected verbose to be true") | // 		t.Error("Expected verbose to be true") | ||||||
| 	} | // 	} | ||||||
| } | // } | ||||||
| 
 | 
 | ||||||
| func TestRootCmd_VersionShort(t *testing.T) { | // func TestRootCmd_VersionShort(t *testing.T) { | ||||||
| 	cmd := getRootCommand() | // 	cmd := getRootCommand() | ||||||
| 	result := test.RunCmd(cmd, "-V") | // 	result := test.RunCmd(cmd, "-V") | ||||||
| 	if result.Error != nil { | // 	if result.Error != nil { | ||||||
| 		t.Error(result.Error) | // 		t.Error(result.Error) | ||||||
| 	} | // 	} | ||||||
| 	if !strings.Contains(result.Output, "yq version") { | // 	if !strings.Contains(result.Output, "yq version") { | ||||||
| 		t.Error("expected version message to be printed out, but the message was not found.") | // 		t.Error("expected version message to be printed out, but the message was not found.") | ||||||
| 	} | // 	} | ||||||
| } | // } | ||||||
| 
 | 
 | ||||||
| func TestRootCmd_VersionLong(t *testing.T) { | // func TestRootCmd_VersionLong(t *testing.T) { | ||||||
| 	cmd := getRootCommand() | // 	cmd := getRootCommand() | ||||||
| 	result := test.RunCmd(cmd, "--version") | // 	result := test.RunCmd(cmd, "--version") | ||||||
| 	if result.Error != nil { | // 	if result.Error != nil { | ||||||
| 		t.Error(result.Error) | // 		t.Error(result.Error) | ||||||
| 	} | // 	} | ||||||
| 	if !strings.Contains(result.Output, "yq version") { | // 	if !strings.Contains(result.Output, "yq version") { | ||||||
| 		t.Error("expected version message to be printed out, but the message was not found.") | // 		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 | package cmd | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/mikefarah/yq/v3/pkg/yqlib" |  | ||||||
| 	"github.com/mikefarah/yq/v3/pkg/yqlib/treeops" |  | ||||||
| 	logging "gopkg.in/op/go-logging.v1" | 	logging "gopkg.in/op/go-logging.v1" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -14,7 +12,6 @@ var customStyle = "" | |||||||
| var anchorName = "" | var anchorName = "" | ||||||
| var makeAlias = false | var makeAlias = false | ||||||
| var stripComments = false | var stripComments = false | ||||||
| var collectIntoArray = false |  | ||||||
| var writeInplace = false | var writeInplace = false | ||||||
| var writeScript = "" | var writeScript = "" | ||||||
| var sourceYamlFile = "" | var sourceYamlFile = "" | ||||||
| @ -22,6 +19,8 @@ var outputToJSON = false | |||||||
| var exitStatus = false | var exitStatus = false | ||||||
| var prettyPrint = false | var prettyPrint = false | ||||||
| var explodeAnchors = false | var explodeAnchors = false | ||||||
|  | var forceColor = false | ||||||
|  | var forceNoColor = false | ||||||
| var colorsEnabled = false | var colorsEnabled = false | ||||||
| var defaultValue = "" | var defaultValue = "" | ||||||
| var indent = 2 | var indent = 2 | ||||||
| @ -31,7 +30,5 @@ var arrayMergeStrategyFlag = "update" | |||||||
| var commentsMergeStrategyFlag = "setWhenBlank" | var commentsMergeStrategyFlag = "setWhenBlank" | ||||||
| var verbose = false | var verbose = false | ||||||
| var version = false | var version = false | ||||||
| var docIndex = "0" | var shellCompletion = "" | ||||||
| var log = logging.MustGetLogger("yq") | 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 | package cmd | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/mikefarah/yq/v4/pkg/yqlib/treeops" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	logging "gopkg.in/op/go-logging.v1" | 	logging "gopkg.in/op/go-logging.v1" | ||||||
| ) | ) | ||||||
| @ -17,9 +20,51 @@ func New() *cobra.Command { | |||||||
| 				cmd.Print(GetVersionDisplay()) | 				cmd.Print(GetVersionDisplay()) | ||||||
| 				return nil | 				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) { | 		PersistentPreRun: func(cmd *cobra.Command, args []string) { | ||||||
| 			cmd.SetOut(cmd.OutOrStdout()) | 			cmd.SetOut(cmd.OutOrStdout()) | ||||||
| @ -44,18 +89,15 @@ func New() *cobra.Command { | |||||||
| 	rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print") | 	rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print") | ||||||
| 	rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output") | 	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.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit") | ||||||
| 	rootCmd.PersistentFlags().BoolVarP(&colorsEnabled, "colors", "C", false, "print with colors") |  | ||||||
| 
 | 
 | ||||||
| 	rootCmd.AddCommand( | 	rootCmd.Flags().StringVarP(&shellCompletion, "shellCompletion", "", "", "[bash/zsh/powershell/fish] prints shell completion script") | ||||||
| 		createReadCmd(), | 
 | ||||||
| 		// createCompareCmd(), | 	rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors") | ||||||
| 		createValidateCmd(), | 	rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors") | ||||||
| 		// createWriteCmd(), | 
 | ||||||
| 		// createPrefixCmd(), | 	// rootCmd.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") | ||||||
| 		// createDeleteCmd(), | 	rootCmd.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)") | ||||||
| 		// createNewCmd(), | 	rootCmd.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results") | ||||||
| 		// createMergeCmd(), | 
 | ||||||
| 		createBashCompletionCmd(rootCmd), |  | ||||||
| 	) |  | ||||||
| 	return rootCmd | 	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 ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
| 	"fmt" | 	"container/list" | ||||||
|  | 	"errors" | ||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"strconv" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/mikefarah/yq/v3/pkg/yqlib" | 	"github.com/mikefarah/yq/v4/pkg/yqlib" | ||||||
| 	"github.com/mikefarah/yq/v3/pkg/yqlib/treeops" | 	"github.com/mikefarah/yq/v4/pkg/yqlib/treeops" | ||||||
| 	errors "github.com/pkg/errors" |  | ||||||
| 	yaml "gopkg.in/yaml.v3" | 	yaml "gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type readDataFn func(document int, dataBucket *yaml.Node) ([]*treeops.CandidateNode, error) | func readStream(filename string) (*yaml.Decoder, error) { | ||||||
| 
 | 	if filename == "" { | ||||||
| func createReadFunction(path string) func(int, *yaml.Node) ([]*treeops.CandidateNode, error) { | 		return nil, errors.New("Must provide filename") | ||||||
| 	return func(document int, dataBucket *yaml.Node) ([]*treeops.CandidateNode, error) { |  | ||||||
| 		return lib.Get(document, dataBucket, path) |  | ||||||
| 	} | 	} | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func readYamlFile(filename string, path string, updateAll bool, docIndexInt int) ([]*treeops.CandidateNode, error) { | 	var stream io.Reader | ||||||
| 	return doReadYamlFile(filename, createReadFunction(path), updateAll, docIndexInt) | 	if filename == "-" { | ||||||
| } | 		stream = bufio.NewReader(os.Stdin) | ||||||
| 
 | 	} else { | ||||||
| func doReadYamlFile(filename string, readFn readDataFn, updateAll bool, docIndexInt int) ([]*treeops.CandidateNode, error) { | 		file, err := os.Open(filename) // nolint gosec | ||||||
| 	var matchingNodes []*treeops.CandidateNode | 		if err != nil { | ||||||
| 
 | 			return nil, err | ||||||
| 	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 |  | ||||||
| 		} | 		} | ||||||
| 	}) | 		defer safelyCloseFile(file) | ||||||
| 	return matchingNodes, errorReadingStream | 		stream = file | ||||||
|  | 	} | ||||||
|  | 	return yaml.NewDecoder(stream), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func handleEOF(updateAll bool, docIndexInt int, currentIndex int) error { | func evaluate(filename string, node *treeops.PathTreeNode) (*list.List, 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 appendDocument(originalMatchingNodes []*treeops.CandidateNode, dataBucket yaml.Node, readFn readDataFn, updateAll bool, docIndexInt int, currentIndex int) ([]*treeops.CandidateNode, error) { | 	var treeNavigator = treeops.NewDataTreeNavigator(treeops.NavigationPrefs{}) | ||||||
| 	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 |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func lengthOf(node *yaml.Node) int { | 	var matchingNodes = list.New() | ||||||
| 	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) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| // transforms node before printing, if required | 	var currentIndex uint = 0 | ||||||
| func transformNode(node *yaml.Node) *yaml.Node { | 	var decoder, err = readStream(filename) | ||||||
| 	if printLength { | 	if err != nil { | ||||||
| 		return &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", lengthOf(node))} | 		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 { | 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) | 	return encoder.Encode(node) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func removeComments(matchingNodes []*treeops.CandidateNode) { | func removeComments(matchingNodes *list.List) { | ||||||
| 	for _, nodeContext := range matchingNodes { | 	for el := matchingNodes.Front(); el != nil; el = el.Next() { | ||||||
| 		removeCommentOfNode(nodeContext.Node) | 		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) { | func setStyle(matchingNodes *list.List, style yaml.Style) { | ||||||
| 	for _, nodeContext := range matchingNodes { | 	for el := matchingNodes.Front(); el != nil; el = el.Next() { | ||||||
| 		updateStyleOfNode(nodeContext.Node, style) | 		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") | 	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()) | 		log.Debugf("exploding %v", nodeContext.GetKey()) | ||||||
| 		errorExplodingNode := explodeNode(nodeContext.Node) | 		errorExplodingNode := explodeNode(nodeContext.Node) | ||||||
| 		if errorExplodingNode != nil { | 		if errorExplodingNode != nil { | ||||||
| @ -246,7 +219,7 @@ func explode(matchingNodes []*treeops.CandidateNode) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) error { | func printResults(matchingNodes *list.List, writer io.Writer) error { | ||||||
| 	if prettyPrint { | 	if prettyPrint { | ||||||
| 		setStyle(matchingNodes, 0) | 		setStyle(matchingNodes, 0) | ||||||
| 	} | 	} | ||||||
| @ -255,6 +228,12 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro | |||||||
| 		removeComments(matchingNodes) | 		removeComments(matchingNodes) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fileInfo, _ := os.Stdout.Stat() | ||||||
|  | 
 | ||||||
|  | 	if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) { | ||||||
|  | 		colorsEnabled = true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	//always explode anchors when printing json | 	//always explode anchors when printing json | ||||||
| 	if explodeAnchors || outputToJSON { | 	if explodeAnchors || outputToJSON { | ||||||
| 		errorExploding := explode(matchingNodes) | 		errorExploding := explode(matchingNodes) | ||||||
| @ -266,7 +245,7 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro | |||||||
| 	bufferedWriter := bufio.NewWriter(writer) | 	bufferedWriter := bufio.NewWriter(writer) | ||||||
| 	defer safelyFlush(bufferedWriter) | 	defer safelyFlush(bufferedWriter) | ||||||
| 
 | 
 | ||||||
| 	if len(matchingNodes) == 0 { | 	if matchingNodes.Len() == 0 { | ||||||
| 		log.Debug("no matching results, nothing to print") | 		log.Debug("no matching results, nothing to print") | ||||||
| 		if defaultValue != "" { | 		if defaultValue != "" { | ||||||
| 			return writeString(bufferedWriter, defaultValue) | 			return writeString(bufferedWriter, defaultValue) | ||||||
| @ -275,9 +254,9 @@ func printResults(matchingNodes []*treeops.CandidateNode, writer io.Writer) erro | |||||||
| 	} | 	} | ||||||
| 	var errorWriting error | 	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 { | 		switch printMode { | ||||||
| 		case "p": | 		case "p": | ||||||
| 			errorWriting = writeString(bufferedWriter, mappedDoc.PathStackToString()+"\n") | 			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} | 			var parentNode = yaml.Node{Kind: yaml.MappingNode} | ||||||
| 			parentNode.Content = make([]*yaml.Node, 2) | 			parentNode.Content = make([]*yaml.Node, 2) | ||||||
| 			parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: mappedDoc.PathStackToString()} | 			parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: mappedDoc.PathStackToString()} | ||||||
| 			parentNode.Content[1] = transformNode(mappedDoc.Node) | 			if mappedDoc.Node.Kind == yaml.DocumentNode { | ||||||
| 			if collectIntoArray { | 				parentNode.Content[1] = mappedDoc.Node.Content[0] | ||||||
| 				arrayCollection.Content = append(arrayCollection.Content, &parentNode) | 			} else { | ||||||
| 			} else if err := printNode(&parentNode, bufferedWriter); err != nil { | 				parentNode.Content[1] = mappedDoc.Node | ||||||
|  | 			} | ||||||
|  | 			if err := printNode(&parentNode, bufferedWriter); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		default: | 		default: | ||||||
| 			if collectIntoArray { | 			if err := printNode(mappedDoc.Node, bufferedWriter); err != nil { | ||||||
| 				arrayCollection.Content = append(arrayCollection.Content, mappedDoc.Node) |  | ||||||
| 			} else if err := printNode(transformNode(mappedDoc.Node), bufferedWriter); err != nil { |  | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if collectIntoArray { |  | ||||||
| 		if err := printNode(transformNode(&arrayCollection), bufferedWriter); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil | 	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) { | func safelyRenameFile(from string, to string) { | ||||||
| 	if renameError := os.Rename(from, to); renameError != nil { | 	if renameError := os.Rename(from, to); renameError != nil { | ||||||
| 		log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to) | 		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()) | 		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 | 	GitDescribe string | ||||||
| 
 | 
 | ||||||
| 	// Version is main version number that is being run at the moment. | 	// 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) | 	// 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 | 	// then it means that it is a final release. Otherwise, this is a pre-release | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | # Some doc | ||||||
|  | 
 | ||||||
| a: true | a: true | ||||||
| b: | b: | ||||||
|   c: 2 |   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 ( | require ( | ||||||
| 	github.com/elliotchance/orderedmap v1.3.0 // indirect | 	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 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= | ||||||
| github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | 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/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/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | ||||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | 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= | 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 | 	Node     *yaml.Node    // the actual node | ||||||
| 	Path     []interface{} /// the path we took to get to this node | 	Path     []interface{} /// the path we took to get to this node | ||||||
| 	Document uint          // the document index of this node | 	Document uint          // the document index of this node | ||||||
|  | 	Filename string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *CandidateNode) GetKey() string { | func (n *CandidateNode) GetKey() string { | ||||||
|  | |||||||
| @ -17,34 +17,17 @@ type NavigationPrefs struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type DataTreeNavigator interface { | 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 { | func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator { | ||||||
| 	return &dataTreeNavigator{navigationPrefs} | 	return &dataTreeNavigator{navigationPrefs} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes []*CandidateNode, pathNode *PathTreeNode) ([]*CandidateNode, error) { | func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, 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) { |  | ||||||
| 	if pathNode == nil { | 	if pathNode == nil { | ||||||
| 		log.Debugf("getMatchingNodes - nothing to do") | 		log.Debugf("getMatchingNodes - nothing to do") | ||||||
| 		return matchingNodes, nil | 		return matchingNodes, nil | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package treeops | package treeops | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"container/list" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| @ -10,9 +11,10 @@ import ( | |||||||
| var treeNavigator = NewDataTreeNavigator(NavigationPrefs{}) | var treeNavigator = NewDataTreeNavigator(NavigationPrefs{}) | ||||||
| var treeCreator = NewPathTreeCreator() | 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 == "" { | 	if content == "" { | ||||||
| 		return []*CandidateNode{} | 		return inputList | ||||||
| 	} | 	} | ||||||
| 	decoder := yaml.NewDecoder(strings.NewReader(content)) | 	decoder := yaml.NewDecoder(strings.NewReader(content)) | ||||||
| 	var dataBucket yaml.Node | 	var dataBucket yaml.Node | ||||||
| @ -21,12 +23,19 @@ func readDoc(t *testing.T, content string) []*CandidateNode { | |||||||
| 		t.Error(content) | 		t.Error(content) | ||||||
| 		t.Error(err) | 		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) | 	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)) | 		pretty = append(pretty, NodeToString(n)) | ||||||
| 	} | 	} | ||||||
| 	return pretty | 	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 | //use for debugging only | ||||||
| func NodesToString(collection *list.List) string { | func NodesToString(collection *list.List) string { | ||||||
| 	if !log.IsEnabledFor(logging.DEBUG) { | 	if !log.IsEnabledFor(logging.DEBUG) { | ||||||
| @ -157,7 +129,11 @@ func NodeToString(node *CandidateNode) string { | |||||||
| 		log.Error("Error debugging node, %v", errorEncoding.Error()) | 		log.Error("Error debugging node, %v", errorEncoding.Error()) | ||||||
| 	} | 	} | ||||||
| 	encoder.Close() | 	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 { | func KindString(kind yaml.Kind) string { | ||||||
|  | |||||||
| @ -3,14 +3,14 @@ package treeops | |||||||
| import "container/list" | import "container/list" | ||||||
| 
 | 
 | ||||||
| func AssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) { | 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 { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	for el := lhs.Front(); el != nil; el = el.Next() { | 	for el := lhs.Front(); el != nil; el = el.Next() { | ||||||
| 		candidate := el.Value.(*CandidateNode) | 		candidate := el.Value.(*CandidateNode) | ||||||
| 
 | 
 | ||||||
| 		rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | 		rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | ||||||
| 
 | 
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| @ -28,14 +28,14 @@ func AssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *Pa | |||||||
| 
 | 
 | ||||||
| // does not update content or values | // does not update content or values | ||||||
| func AssignAttributesOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) { | 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 { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	for el := lhs.Front(); el != nil; el = el.Next() { | 	for el := lhs.Front(); el != nil; el = el.Next() { | ||||||
| 		candidate := el.Value.(*CandidateNode) | 		candidate := el.Value.(*CandidateNode) | ||||||
| 
 | 
 | ||||||
| 		rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | 		rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | ||||||
| 
 | 
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
|  | |||||||
| @ -9,61 +9,70 @@ var assignOperatorScenarios = []expressionScenario{ | |||||||
| 		document:   `{a: {b: apple}}`, | 		document:   `{a: {b: apple}}`, | ||||||
| 		expression: `.a.b |= "frog"`, | 		expression: `.a.b |= "frog"`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {b: frog}}\n", | 			"D0, P[], (doc)::{a: {b: frog}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {b: apple}}`, | 		document:   `{a: {b: apple}}`, | ||||||
| 		expression: `.a.b | (. |= "frog")`, | 		expression: `.a.b | (. |= "frog")`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[a b], (!!str)::frog\n", | 			"D0, P[a b], (!!str)::frog\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {b: apple}}`, | 		document:   `{a: {b: apple}}`, | ||||||
| 		expression: `.a.b |= 5`, | 		expression: `.a.b |= 5`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {b: 5}}\n", | 			"D0, P[], (doc)::{a: {b: 5}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {b: apple}}`, | 		document:   `{a: {b: apple}}`, | ||||||
| 		expression: `.a.b |= 3.142`, | 		expression: `.a.b |= 3.142`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {b: 3.142}}\n", | 			"D0, P[], (doc)::{a: {b: 3.142}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {b: {g: foof}}}`, | 		document:   `{a: {b: {g: foof}}}`, | ||||||
| 		expression: `.a |= .b`, | 		expression: `.a |= .b`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {g: foof}}\n", | 			"D0, P[], (doc)::{a: {g: foof}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {b: apple, c: cactus}}`, | 		document:   `{a: {b: apple, c: cactus}}`, | ||||||
| 		expression: `.a[] | select(. == "apple") |= "frog"`, | 		expression: `.a[] | select(. == "apple") |= "frog"`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {b: frog, c: cactus}}\n", | 			"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `[candy, apple, sandy]`, | 		document:   `[candy, apple, sandy]`, | ||||||
| 		expression: `.[] | select(. == "*andy") |= "bogs"`, | 		expression: `.[] | select(. == "*andy") |= "bogs"`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!seq)::[bogs, apple, bogs]\n", | 			"D0, P[], (doc)::[bogs, apple, bogs]\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{}`, | 		document:   `{}`, | ||||||
| 		expression: `.a.b |= "bogs"`, | 		expression: `.a.b |= "bogs"`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {b: bogs}}\n", | 			"D0, P[], (doc)::{a: {b: bogs}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{}`, | 		document:   `{}`, | ||||||
| 		expression: `.a.b[0] |= "bogs"`, | 		expression: `.a.b[0] |= "bogs"`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {b: [bogs]}}\n", | 			"D0, P[], (doc)::{a: {b: [bogs]}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{}`, | 		document:   `{}`, | ||||||
| 		expression: `.a.b[1].c |= "bogs"`, | 		expression: `.a.b[1].c |= "bogs"`, | ||||||
| 		expected: []string{ | 		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) { | func isTruthy(c *CandidateNode) (bool, error) { | ||||||
| 	node := c.Node | 	node := UnwrapDoc(c.Node) | ||||||
| 	value := true | 	value := true | ||||||
|  | 
 | ||||||
| 	if node.Tag == "!!null" { | 	if node.Tag == "!!null" { | ||||||
| 		return false, nil | 		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() { | 	for el := matchingNodes.Front(); el != nil; el = el.Next() { | ||||||
| 		candidate := el.Value.(*CandidateNode) | 		candidate := el.Value.(*CandidateNode) | ||||||
| 		lhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Lhs) | 		lhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Lhs) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | 		rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) { | 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 { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @ -19,7 +19,7 @@ func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNod | |||||||
| 		candidate := el.Value.(*CandidateNode) | 		candidate := el.Value.(*CandidateNode) | ||||||
| 		elMap := list.New() | 		elMap := list.New() | ||||||
| 		elMap.PushBack(candidate) | 		elMap.PushBack(candidate) | ||||||
| 		nodesToDelete, err := d.getMatchingNodes(elMap, pathNode.Rhs) | 		nodesToDelete, err := d.GetMatchingNodes(elMap, pathNode.Rhs) | ||||||
| 		log.Debug("nodesToDelete:\n%v", NodesToString(nodesToDelete)) | 		log.Debug("nodesToDelete:\n%v", NodesToString(nodesToDelete)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
|  | |||||||
| @ -11,12 +11,12 @@ import ( | |||||||
| type CrossFunctionCalculation func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) | 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) { | 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 { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rhs, err := d.getMatchingNodes(matchingNodes, pathNode.Rhs) | 	rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs) | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		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) { | 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 || | 	if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode || | ||||||
| 		(lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) { | 		(lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) { | ||||||
| 		var results = list.New() | 		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}} | 	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 | 	return err | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,43 +11,50 @@ var multiplyOperatorScenarios = []expressionScenario{ | |||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n", | 			"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {also: me}, b: {also: [1]}}`, | 		document:   `{a: {also: me}, b: {also: [1]}}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {also: [1]}, b: {also: [1]}}\n", | 			"D0, P[], (!!map)::{a: {also: [1]}, b: {also: [1]}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {also: me}, b: {also: {g: wizz}}}`, | 		document:   `{a: {also: me}, b: {also: {g: wizz}}}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {also: {g: wizz}}, b: {also: {g: wizz}}}\n", | 			"D0, P[], (!!map)::{a: {also: {g: wizz}}, b: {also: {g: wizz}}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {also: {g: wizz}}, b: {also: me}}`, | 		document:   `{a: {also: {g: wizz}}, b: {also: me}}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n", | 			"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {also: {g: wizz}}, b: {also: [1]}}`, | 		document:   `{a: {also: {g: wizz}}, b: {also: [1]}}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {also: [1]}, b: {also: [1]}}\n", | 			"D0, P[], (!!map)::{a: {also: [1]}, b: {also: [1]}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {also: [1]}, b: {also: {g: wizz}}}`, | 		document:   `{a: {also: [1]}, b: {also: {g: wizz}}}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {also: {g: wizz}}, b: {also: {g: wizz}}}\n", | 			"D0, P[], (!!map)::{a: {also: {g: wizz}}, b: {also: {g: wizz}}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {things: great}, b: {also: me}}`, | 		document:   `{a: {things: great}, b: {also: me}}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: {things: great, also: me}, b: {also: me}}\n", | 			"D0, P[], (!!map)::{a: {things: great, also: me}, b: {also: me}}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document: `a: {things: great} | 		document: `a: {things: great} | ||||||
| b: | b: | ||||||
|   also: "me" |   also: "me" | ||||||
| @ -59,7 +66,8 @@ b: | |||||||
|     also: "me" |     also: "me" | ||||||
| `, | `, | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: [1,2,3], b: [3,4,5]}`, | 		document:   `{a: [1,2,3], b: [3,4,5]}`, | ||||||
| 		expression: `. * {"a":.b}`, | 		expression: `. * {"a":.b}`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
|  | |||||||
| @ -5,27 +5,27 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var notOperatorScenarios = []expressionScenario{ | var notOperatorScenarios = []expressionScenario{ | ||||||
| 	{ | 	// { | ||||||
| 		document:   `cat`, | 	// 	document:   `cat`, | ||||||
| 		expression: `. | not`, | 	// 	expression: `. | not`, | ||||||
| 		expected: []string{ | 	// 	expected: []string{ | ||||||
| 			"D0, P[], (!!bool)::false\n", | 	// 		"D0, P[], (!!bool)::false\n", | ||||||
| 		}, | 	// 	}, | ||||||
| 	}, | 	// }, | ||||||
| 	{ | 	// { | ||||||
| 		document:   `1`, | 	// 	document:   `1`, | ||||||
| 		expression: `. | not`, | 	// 	expression: `. | not`, | ||||||
| 		expected: []string{ | 	// 	expected: []string{ | ||||||
| 			"D0, P[], (!!bool)::false\n", | 	// 		"D0, P[], (!!bool)::false\n", | ||||||
| 		}, | 	// 	}, | ||||||
| 	}, | 	// }, | ||||||
| 	{ | 	// { | ||||||
| 		document:   `0`, | 	// 	document:   `0`, | ||||||
| 		expression: `. | not`, | 	// 	expression: `. | not`, | ||||||
| 		expected: []string{ | 	// 	expected: []string{ | ||||||
| 			"D0, P[], (!!bool)::false\n", | 	// 		"D0, P[], (!!bool)::false\n", | ||||||
| 		}, | 	// 	}, | ||||||
| 	}, | 	// }, | ||||||
| 	{ | 	{ | ||||||
| 		document:   `~`, | 		document:   `~`, | ||||||
| 		expression: `. | not`, | 		expression: `. | not`, | ||||||
| @ -33,20 +33,20 @@ var notOperatorScenarios = []expressionScenario{ | |||||||
| 			"D0, P[], (!!bool)::true\n", | 			"D0, P[], (!!bool)::true\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	// { | ||||||
| 		document:   `false`, | 	// 	document:   `false`, | ||||||
| 		expression: `. | not`, | 	// 	expression: `. | not`, | ||||||
| 		expected: []string{ | 	// 	expected: []string{ | ||||||
| 			"D0, P[], (!!bool)::true\n", | 	// 		"D0, P[], (!!bool)::true\n", | ||||||
| 		}, | 	// 	}, | ||||||
| 	}, | 	// }, | ||||||
| 	{ | 	// { | ||||||
| 		document:   `true`, | 	// 	document:   `true`, | ||||||
| 		expression: `. | not`, | 	// 	expression: `. | not`, | ||||||
| 		expected: []string{ | 	// 	expected: []string{ | ||||||
| 			"D0, P[], (!!bool)::false\n", | 	// 		"D0, P[], (!!bool)::false\n", | ||||||
| 		}, | 	// 	}, | ||||||
| 	}, | 	// }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestNotOperatorScenarios(t *testing.T) { | 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 { | func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List) error { | ||||||
| 	for el := matchMap.Front(); el != nil; el = el.Next() { | 	for el := matchMap.Front(); el != nil; el = el.Next() { | ||||||
| 		candidate := el.Value.(*CandidateNode) | 		candidate := el.Value.(*CandidateNode) | ||||||
|  | 
 | ||||||
|  | 		candidate.Node = UnwrapDoc(candidate.Node) | ||||||
|  | 
 | ||||||
|  | 		log.Debugf("Recursive Decent, added %v", NodeToString(candidate)) | ||||||
| 		results.PushBack(candidate) | 		results.PushBack(candidate) | ||||||
| 
 | 
 | ||||||
| 		children, err := Splat(d, nodeToMap(candidate)) | 		children, err := Splat(d, nodeToMap(candidate)) | ||||||
|  | |||||||
| @ -11,14 +11,16 @@ var recursiveDescentOperatorScenarios = []expressionScenario{ | |||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!str)::cat\n", | 			"D0, P[], (!!str)::cat\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: frog}`, | 		document:   `{a: frog}`, | ||||||
| 		expression: `..`, | 		expression: `..`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| 			"D0, P[], (!!map)::{a: frog}\n", | 			"D0, P[], (!!map)::{a: frog}\n", | ||||||
| 			"D0, P[a], (!!str)::frog\n", | 			"D0, P[a], (!!str)::frog\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `{a: {b: apple}}`, | 		document:   `{a: {b: apple}}`, | ||||||
| 		expression: `..`, | 		expression: `..`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| @ -26,7 +28,8 @@ var recursiveDescentOperatorScenarios = []expressionScenario{ | |||||||
| 			"D0, P[a], (!!map)::{b: apple}\n", | 			"D0, P[a], (!!map)::{b: apple}\n", | ||||||
| 			"D0, P[a b], (!!str)::apple\n", | 			"D0, P[a b], (!!str)::apple\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `[1,2,3]`, | 		document:   `[1,2,3]`, | ||||||
| 		expression: `..`, | 		expression: `..`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
| @ -35,7 +38,8 @@ var recursiveDescentOperatorScenarios = []expressionScenario{ | |||||||
| 			"D0, P[1], (!!int)::2\n", | 			"D0, P[1], (!!int)::2\n", | ||||||
| 			"D0, P[2], (!!int)::3\n", | 			"D0, P[2], (!!int)::3\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, | ||||||
|  | 	{ | ||||||
| 		document:   `[{a: cat},2,true]`, | 		document:   `[{a: cat},2,true]`, | ||||||
| 		expression: `..`, | 		expression: `..`, | ||||||
| 		expected: []string{ | 		expected: []string{ | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ func SelectOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *Pa | |||||||
| 	for el := matchingNodes.Front(); el != nil; el = el.Next() { | 	for el := matchingNodes.Front(); el != nil; el = el.Next() { | ||||||
| 		candidate := el.Value.(*CandidateNode) | 		candidate := el.Value.(*CandidateNode) | ||||||
| 
 | 
 | ||||||
| 		rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | 		rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs) | ||||||
| 
 | 
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
|  | |||||||
| @ -3,11 +3,11 @@ package treeops | |||||||
| import "container/list" | import "container/list" | ||||||
| 
 | 
 | ||||||
| func UnionOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) { | 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 { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	rhs, err := d.getMatchingNodes(matchingNodes, pathNode.Rhs) | 	rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -9,12 +9,19 @@ import ( | |||||||
| 
 | 
 | ||||||
| type OperatorHandler func(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) | 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) { | 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 { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return d.getMatchingNodes(lhs, pathNode.Rhs) | 	return d.GetMatchingNodes(lhs, pathNode.Rhs) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode { | func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode { | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/mikefarah/yq/v3/test" | 	"github.com/mikefarah/yq/v4/test" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type expressionScenario struct { | type expressionScenario struct { | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/mikefarah/yq/v3/test" | 	"github.com/mikefarah/yq/v4/test" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var pathTests = []struct { | var pathTests = []struct { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user