Maintain order

This commit is contained in:
Mike Farah 2017-02-27 09:01:52 +11:00
parent 5d2d37a5f8
commit 44ee869e47
8 changed files with 79 additions and 27 deletions

View File

@ -2,21 +2,34 @@ package main
import (
// "fmt"
"github.com/mikefarah/yaml/Godeps/_workspace/src/gopkg.in/yaml.v2"
"strconv"
)
func write(context map[interface{}]interface{}, head string, tail []string, value interface{}) {
func entryInSlice(context yaml.MapSlice, key interface{}) *yaml.MapItem {
for idx := range context {
var entry = &context[idx]
if entry.Key == key {
return entry
}
}
return nil
}
func write(context yaml.MapSlice, head string, tail []string, value interface{}) {
if len(tail) == 0 {
context[head] = value
var entry = entryInSlice(context, head)
entry.Value = value
} else {
// e.g. if updating a.b.c, we need to get the 'b', this could be a map or an array
var parent = readMap(context, head, tail[0:len(tail)-1])
switch parent.(type) {
case map[interface{}]interface{}:
toUpdate := parent.(map[interface{}]interface{})
case yaml.MapSlice:
toUpdate := parent.(yaml.MapSlice)
// b is a map, update the key 'c' to the supplied value
key := (tail[len(tail)-1])
toUpdate[key] = value
toUpdateEntry := entryInSlice(toUpdate, key)
toUpdateEntry.Value = value
case []interface{}:
toUpdate := parent.([]interface{})
// b is an array, update it at index 'c' to the supplied value
@ -31,22 +44,26 @@ func write(context map[interface{}]interface{}, head string, tail []string, valu
}
}
func readMap(context map[interface{}]interface{}, head string, tail []string) interface{} {
func readMap(context yaml.MapSlice, head string, tail []string) interface{} {
if head == "*" {
return readMapSplat(context, tail)
}
value := context[head]
entry := entryInSlice(context, head)
var value interface{}
if entry != nil {
value = entry.Value
}
return calculateValue(value, tail)
}
func readMapSplat(context map[interface{}]interface{}, tail []string) interface{} {
func readMapSplat(context yaml.MapSlice, tail []string) interface{} {
var newArray = make([]interface{}, len(context))
var i = 0
for _, value := range context {
for _, entry := range context {
if len(tail) > 0 {
newArray[i] = recurse(value, tail[0], tail[1:len(tail)])
newArray[i] = recurse(entry.Value, tail[0], tail[1:len(tail)])
} else {
newArray[i] = value
newArray[i] = entry.Value
}
i++
}
@ -64,8 +81,8 @@ func recurse(value interface{}, head string, tail []string) interface{} {
die("Error accessing array: %v", err)
}
return readArray(value.([]interface{}), index, tail)
case map[interface{}]interface{}:
return readMap(value.(map[interface{}]interface{}), head, tail)
case yaml.MapSlice:
return readMap(value.(yaml.MapSlice), head, tail)
default:
return nil
}

View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"github.com/mikefarah/yaml/Godeps/_workspace/src/gopkg.in/yaml.v2"
"sort"
"testing"
)
@ -107,6 +108,16 @@ e:
assertResult(t, "[Fred Sam]", fmt.Sprintf("%v", readMap(data, "e", []string{"*", "name"})))
}
func TestWrite_really_simple(t *testing.T) {
var data = parseData(`
b: 2
`)
write(data, "b", []string{}, "4")
b := entryInSlice(data, "b").Value
assertResult(t, "4", b)
}
func TestWrite_simple(t *testing.T) {
var data = parseData(`
b:
@ -114,9 +125,9 @@ b:
`)
write(data, "b", []string{"c"}, "4")
b := data["b"].(map[interface{}]interface{})
assertResult(t, "4", b["c"].(string))
b := entryInSlice(data, "b").Value.(yaml.MapSlice)
c := entryInSlice(b, "c").Value
assertResult(t, "4", c)
}
func TestWrite_array(t *testing.T) {
@ -127,7 +138,7 @@ b:
write(data, "b", []string{"0"}, "bb")
b := data["b"].([]interface{})
b := entryInSlice(data, "b").Value.([]interface{})
assertResult(t, "bb", b[0].(string))
}
@ -138,6 +149,6 @@ b:
`)
write(data, "b", []string{}, "4")
b := data["b"]
b := entryInSlice(data, "b").Value
assertResult(t, "4", fmt.Sprintf("%v", b))
}

View File

@ -2,6 +2,7 @@ package main
import (
"encoding/json"
"github.com/mikefarah/yaml/Godeps/_workspace/src/gopkg.in/yaml.v2"
)
func fromJSONBytes(jsonBytes []byte, parsedData *map[interface{}]interface{}) {
@ -55,11 +56,11 @@ func toJSON(context interface{}) interface{} {
newArray[index] = toJSON(value)
}
return newArray
case map[interface{}]interface{}:
oldMap := context.(map[interface{}]interface{})
case yaml.MapSlice:
oldMap := context.(yaml.MapSlice)
newMap := make(map[string]interface{})
for key, value := range oldMap {
newMap[key.(string)] = toJSON(value)
for _, entry := range oldMap {
newMap[entry.Key.(string)] = toJSON(entry.Value)
}
return newMap
default:

2
order.yaml Normal file
View File

@ -0,0 +1,2 @@
version: 3
application: MyApp

6
order.yml Normal file
View File

@ -0,0 +1,6 @@
version: '2'
services:
test:
image: ubuntu:14.04
stdin_open: true
tty: true

View File

@ -7,8 +7,8 @@ import (
"testing"
)
func parseData(rawData string) map[interface{}]interface{} {
var parsedData map[interface{}]interface{}
func parseData(rawData string) yaml.MapSlice {
var parsedData yaml.MapSlice
err := yaml.Unmarshal([]byte(rawData), &parsedData)
if err != nil {
fmt.Println("Error parsing yaml: %v", err)

View File

@ -81,7 +81,7 @@ func readProperty(cmd *cobra.Command, args []string) {
}
func read(args []string) interface{} {
var parsedData map[interface{}]interface{}
var parsedData yaml.MapSlice
readData(args[0], &parsedData, inputJSON)
@ -114,13 +114,14 @@ func updateYaml(args []string) interface{} {
writeCommands[args[1]] = parseValue(args[2])
}
var parsedData map[interface{}]interface{}
var parsedData yaml.MapSlice
readData(args[0], &parsedData, inputJSON)
for path, value := range writeCommands {
var paths = parsePath(path)
write(parsedData, paths[0], paths[1:len(paths)], value)
}
return parsedData
}

View File

@ -1,6 +1,7 @@
package main
import (
"fmt"
"testing"
)
@ -26,8 +27,21 @@ func TestRead(t *testing.T) {
assertResult(t, 2, result)
}
func TestOrder(t *testing.T) {
result := read([]string{"order.yaml"})
formattedResult := yamlToString(result)
assertResult(t,
`version: 3
application: MyApp`,
formattedResult)
}
func TestUpdateYaml(t *testing.T) {
updateYaml([]string{"sample.yaml", "b.c", "3"})
result := updateYaml([]string{"sample.yaml", "b.c", "3"})
formattedResult := fmt.Sprintf("%v", result)
assertResult(t,
"[{a Easy! as one two three} {b [{c 3} {d [3 4]} {e [[{name fred} {value 3}] [{name sam} {value 4}]]}]}]",
formattedResult)
}
func TestUpdateYaml_WithScript(t *testing.T) {