mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-24 06:35:40 +00:00
Multi doc supports updating all docs
This commit is contained in:
parent
facc81d1f4
commit
fb87f638f2
119
commands_test.go
119
commands_test.go
@ -394,6 +394,28 @@ apples: ok
|
|||||||
assertResult(t, expectedOutput, result.Output)
|
assertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("write %s -d * apples ok", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
apples: ok
|
||||||
|
---
|
||||||
|
apples: ok`
|
||||||
|
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteCmd_EmptyArray(t *testing.T) {
|
func TestWriteCmd_EmptyArray(t *testing.T) {
|
||||||
content := `b: 3`
|
content := `b: 3`
|
||||||
filename := writeTempYamlFile(content)
|
filename := writeTempYamlFile(content)
|
||||||
@ -569,6 +591,29 @@ func TestDeleteYamlMulti(t *testing.T) {
|
|||||||
assertResult(t, expectedOutput, result.Output)
|
assertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteYamlMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
apples: great
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
something: else
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("delete %s -d * apples", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
something: else`
|
||||||
|
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeCmd(t *testing.T) {
|
func TestMergeCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := runCmd(cmd, "merge examples/data1.yaml examples/data2.yaml")
|
result := runCmd(cmd, "merge examples/data1.yaml examples/data2.yaml")
|
||||||
@ -585,6 +630,22 @@ c:
|
|||||||
assertResult(t, expectedOutput, result.Output)
|
assertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, "merge --overwrite examples/data1.yaml examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: other
|
||||||
|
b:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
assertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeCmd_Multi(t *testing.T) {
|
func TestMergeCmd_Multi(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := runCmd(cmd, "merge -d1 examples/multiple_docs_small.yaml examples/data2.yaml")
|
result := runCmd(cmd, "merge -d1 examples/multiple_docs_small.yaml examples/data2.yaml")
|
||||||
@ -604,6 +665,64 @@ c:
|
|||||||
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMergeYamlMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
apples: green
|
||||||
|
---
|
||||||
|
something: else`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `apples: red
|
||||||
|
something: good`
|
||||||
|
mergeFilename := writeTempYamlFile(mergeContent)
|
||||||
|
defer removeTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("merge -d* %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `apples: green
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
something: good
|
||||||
|
---
|
||||||
|
apples: red
|
||||||
|
something: else`
|
||||||
|
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
apples: green
|
||||||
|
---
|
||||||
|
something: else`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `apples: red
|
||||||
|
something: good`
|
||||||
|
mergeFilename := writeTempYamlFile(mergeContent)
|
||||||
|
defer removeTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("merge --overwrite -d* %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `apples: red
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
something: good
|
||||||
|
---
|
||||||
|
apples: red
|
||||||
|
something: good`
|
||||||
|
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeCmd_Error(t *testing.T) {
|
func TestMergeCmd_Error(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := runCmd(cmd, "merge examples/data1.yaml")
|
result := runCmd(cmd, "merge examples/data1.yaml")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
commonKey: first document
|
||||||
a: Easy! as one two three
|
a: Easy! as one two three
|
||||||
b:
|
b:
|
||||||
c: 2
|
c: 2
|
||||||
@ -8,8 +9,14 @@ b:
|
|||||||
- name: sam
|
- name: sam
|
||||||
value: 4
|
value: 4
|
||||||
---
|
---
|
||||||
|
commonKey: second document
|
||||||
another:
|
another:
|
||||||
document: here
|
document: here
|
||||||
---
|
---
|
||||||
|
commonKey: third document
|
||||||
wow:
|
wow:
|
||||||
- here is another
|
- here is another
|
||||||
|
---
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
59
yq.go
59
yq.go
@ -24,7 +24,7 @@ var outputToJSON = false
|
|||||||
var overwriteFlag = false
|
var overwriteFlag = false
|
||||||
var verbose = false
|
var verbose = false
|
||||||
var version = false
|
var version = false
|
||||||
var docIndex = 0
|
var docIndex = "0"
|
||||||
var log = logging.MustGetLogger("yq")
|
var log = logging.MustGetLogger("yq")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -97,7 +97,7 @@ yq r things.yaml a.array[*].blah
|
|||||||
Long: "Outputs the value of the given path in the yaml file to STDOUT",
|
Long: "Outputs the value of the given path in the yaml file to STDOUT",
|
||||||
RunE: readProperty,
|
RunE: readProperty,
|
||||||
}
|
}
|
||||||
cmdRead.PersistentFlags().IntVarP(&docIndex, "doc", "d", 0, "process document index number (0 based)")
|
cmdRead.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based")
|
||||||
return cmdRead
|
return cmdRead
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ a.b.e:
|
|||||||
}
|
}
|
||||||
cmdWrite.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
cmdWrite.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||||
cmdWrite.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml")
|
cmdWrite.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml")
|
||||||
cmdWrite.PersistentFlags().IntVarP(&docIndex, "doc", "d", 0, "process document index number (0 based)")
|
cmdWrite.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
return cmdWrite
|
return cmdWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ Outputs to STDOUT unless the inplace flag is used, in which case the file is upd
|
|||||||
RunE: deleteProperty,
|
RunE: deleteProperty,
|
||||||
}
|
}
|
||||||
cmdDelete.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
cmdDelete.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||||
cmdDelete.PersistentFlags().IntVarP(&docIndex, "doc", "d", 0, "process document index number (0 based)")
|
cmdDelete.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
return cmdDelete
|
return cmdDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ If overwrite flag is set then existing values will be overwritten using the valu
|
|||||||
}
|
}
|
||||||
cmdMerge.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
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(&overwriteFlag, "overwrite", "x", false, "update the yaml file by overwriting existing values")
|
||||||
cmdMerge.PersistentFlags().IntVarP(&docIndex, "doc", "d", 0, "process document index number (0 based)")
|
cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
return cmdMerge
|
return cmdMerge
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +226,11 @@ func read(args []string) (interface{}, error) {
|
|||||||
path = args[1]
|
path = args[1]
|
||||||
}
|
}
|
||||||
var generalData interface{}
|
var generalData interface{}
|
||||||
if err := readData(args[0], docIndex, &generalData); err != nil {
|
var docIndexInt, errorParsingDocumentIndex = strconv.ParseInt(docIndex, 10, 32)
|
||||||
|
if errorParsingDocumentIndex != nil {
|
||||||
|
return nil, errors.Wrapf(errorParsingDocumentIndex, "Document index %v is not a integer", docIndex)
|
||||||
|
}
|
||||||
|
if err := readData(args[0], int(docIndexInt), &generalData); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if path == "" {
|
if path == "" {
|
||||||
@ -234,8 +238,7 @@ func read(args []string) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var paths = parsePath(path)
|
var paths = parsePath(path)
|
||||||
value, err := recurse(generalData, paths[0], paths[1:])
|
return recurse(generalData, paths[0], paths[1:])
|
||||||
return value, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProperty(cmd *cobra.Command, args []string) error {
|
func newProperty(cmd *cobra.Command, args []string) error {
|
||||||
@ -276,6 +279,17 @@ func newYaml(args []string) (interface{}, error) {
|
|||||||
return dataBucket, nil
|
return dataBucket, 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 interface{}, currentIndex int) (interface{}, error)
|
type updateDataFn func(dataBucket interface{}, currentIndex int) (interface{}, error)
|
||||||
|
|
||||||
func mapYamlDecoder(updateData updateDataFn, encoder *yaml.Encoder) yamlDecoderFn {
|
func mapYamlDecoder(updateData updateDataFn, encoder *yaml.Encoder) yamlDecoderFn {
|
||||||
@ -286,12 +300,17 @@ func mapYamlDecoder(updateData updateDataFn, encoder *yaml.Encoder) yamlDecoderF
|
|||||||
var errorUpdating error
|
var errorUpdating error
|
||||||
var currentIndex = 0
|
var currentIndex = 0
|
||||||
|
|
||||||
|
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||||
|
if errorParsingDocIndex != nil {
|
||||||
|
return errorParsingDocIndex
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
log.Debugf("Read doc %v", currentIndex)
|
log.Debugf("Read doc %v", currentIndex)
|
||||||
errorReading = decoder.Decode(&dataBucket)
|
errorReading = decoder.Decode(&dataBucket)
|
||||||
|
|
||||||
if errorReading == io.EOF {
|
if errorReading == io.EOF {
|
||||||
if currentIndex < docIndex {
|
if !updateAll && currentIndex < docIndexInt {
|
||||||
return fmt.Errorf("Asked to process document %v but there are only %v document(s)", docIndex, currentIndex)
|
return fmt.Errorf("Asked to process document %v but there are only %v document(s)", docIndex, currentIndex)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -318,8 +337,13 @@ func writeProperty(cmd *cobra.Command, args []string) error {
|
|||||||
if writeCommandsError != nil {
|
if writeCommandsError != nil {
|
||||||
return writeCommandsError
|
return writeCommandsError
|
||||||
}
|
}
|
||||||
|
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||||
|
if errorParsingDocIndex != nil {
|
||||||
|
return errorParsingDocIndex
|
||||||
|
}
|
||||||
|
|
||||||
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||||
if currentIndex == docIndex {
|
if updateAll || currentIndex == docIndexInt {
|
||||||
log.Debugf("Updating doc %v", currentIndex)
|
log.Debugf("Updating doc %v", currentIndex)
|
||||||
for _, entry := range writeCommands {
|
for _, entry := range writeCommands {
|
||||||
path := entry.Key.(string)
|
path := entry.Key.(string)
|
||||||
@ -365,8 +389,13 @@ func deleteProperty(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
var deletePath = args[1]
|
var deletePath = args[1]
|
||||||
var paths = parsePath(deletePath)
|
var paths = parsePath(deletePath)
|
||||||
|
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||||
|
if errorParsingDocIndex != nil {
|
||||||
|
return errorParsingDocIndex
|
||||||
|
}
|
||||||
|
|
||||||
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||||
if currentIndex == docIndex {
|
if updateAll || currentIndex == docIndexInt {
|
||||||
log.Debugf("Deleting path in doc %v", currentIndex)
|
log.Debugf("Deleting path in doc %v", currentIndex)
|
||||||
return deleteChildValue(dataBucket, paths), nil
|
return deleteChildValue(dataBucket, paths), nil
|
||||||
}
|
}
|
||||||
@ -382,9 +411,13 @@ func mergeProperties(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
var input = args[0]
|
var input = args[0]
|
||||||
var filesToMerge = args[1:]
|
var filesToMerge = args[1:]
|
||||||
|
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||||
|
if errorParsingDocIndex != nil {
|
||||||
|
return errorParsingDocIndex
|
||||||
|
}
|
||||||
|
|
||||||
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||||
if currentIndex == docIndex {
|
if updateAll || currentIndex == docIndexInt {
|
||||||
log.Debugf("Merging doc %v", currentIndex)
|
log.Debugf("Merging doc %v", currentIndex)
|
||||||
var mergedData map[interface{}]interface{}
|
var mergedData map[interface{}]interface{}
|
||||||
if err := merge(&mergedData, dataBucket, overwriteFlag); err != nil {
|
if err := merge(&mergedData, dataBucket, overwriteFlag); err != nil {
|
||||||
@ -520,8 +553,6 @@ func readStream(filename string, yamlDecoder yamlDecoderFn) error {
|
|||||||
|
|
||||||
func readData(filename string, indexToRead int, parsedData interface{}) error {
|
func readData(filename string, indexToRead int, parsedData interface{}) error {
|
||||||
return readStream(filename, func(decoder *yaml.Decoder) error {
|
return readStream(filename, func(decoder *yaml.Decoder) error {
|
||||||
// naive implementation of document indexing, decodes all the yaml documents
|
|
||||||
// before the docIndex and throws them away.
|
|
||||||
for currentIndex := 0; currentIndex < indexToRead; currentIndex++ {
|
for currentIndex := 0; currentIndex < indexToRead; currentIndex++ {
|
||||||
errorSkipping := decoder.Decode(parsedData)
|
errorSkipping := decoder.Decode(parsedData)
|
||||||
if errorSkipping != nil {
|
if errorSkipping != nil {
|
||||||
|
@ -29,10 +29,10 @@ func TestRead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMulti(t *testing.T) {
|
func TestReadMulti(t *testing.T) {
|
||||||
docIndex = 1
|
docIndex = "1"
|
||||||
result, _ := read([]string{"examples/multiple_docs.yaml", "another.document"})
|
result, _ := read([]string{"examples/multiple_docs.yaml", "another.document"})
|
||||||
assertResult(t, "here", result)
|
assertResult(t, "here", result)
|
||||||
docIndex = 0
|
docIndex = "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadArray(t *testing.T) {
|
func TestReadArray(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user