1
0
mirror of https://github.com/rancher/os.git synced 2025-07-13 06:34:04 +00:00

Merge pull request #882 from joshwget/unmarshal-args-as-yaml

Use yaml.Unmarshal to handle config arguments
This commit is contained in:
Darren Shepherd 2016-04-14 21:47:07 -07:00
commit 5d15d3aa2c
2 changed files with 80 additions and 25 deletions

View File

@ -153,6 +153,52 @@ func TestFilterDottedKeys(t *testing.T) {
assert.Equal(expectedRest, rest) assert.Equal(expectedRest, rest)
} }
func TestUnmarshalOrReturnString(t *testing.T) {
assert := require.New(t)
assert.Equal("ab", unmarshalOrReturnString("ab"))
assert.Equal("a\nb", unmarshalOrReturnString("a\nb"))
assert.Equal("a\n", unmarshalOrReturnString("a\n"))
assert.Equal("\nb", unmarshalOrReturnString("\nb"))
assert.Equal("a,b", unmarshalOrReturnString("a,b"))
assert.Equal("a,", unmarshalOrReturnString("a,"))
assert.Equal(",b", unmarshalOrReturnString(",b"))
assert.Equal(int64(10), unmarshalOrReturnString("10"))
assert.Equal(true, unmarshalOrReturnString("true"))
assert.Equal(false, unmarshalOrReturnString("false"))
assert.Equal([]interface{}{"a"}, unmarshalOrReturnString("[a]"))
assert.Equal([]interface{}{"a"}, unmarshalOrReturnString("[\"a\"]"))
assert.Equal([]interface{}{"a,"}, unmarshalOrReturnString("[\"a,\"]"))
assert.Equal([]interface{}{" a, "}, unmarshalOrReturnString("[\" a, \"]"))
assert.Equal([]interface{}{",a"}, unmarshalOrReturnString("[\",a\"]"))
assert.Equal([]interface{}{" ,a "}, unmarshalOrReturnString("[\" ,a \"]"))
assert.Equal([]interface{}{"a\n"}, unmarshalOrReturnString("[\"a\n\"]"))
assert.Equal([]interface{}{" a\n "}, unmarshalOrReturnString("[\" a\n \"]"))
assert.Equal([]interface{}{"\na"}, unmarshalOrReturnString("[\"\na\"]"))
assert.Equal([]interface{}{" \na "}, unmarshalOrReturnString("[\" \na \"]"))
assert.Equal([]interface{}{"a", "b"}, unmarshalOrReturnString("[a,b]"))
assert.Equal([]interface{}{"a", "b"}, unmarshalOrReturnString("[\"a\",\"b\"]"))
assert.Equal([]interface{}{"a,", "b"}, unmarshalOrReturnString("[\"a,\",b]"))
assert.Equal([]interface{}{"a", ",b"}, unmarshalOrReturnString("[a,\",b\"]"))
assert.Equal([]interface{}{" a, ", " ,b "}, unmarshalOrReturnString("[\" a, \",\" ,b \"]"))
assert.Equal([]interface{}{"a\n", "b"}, unmarshalOrReturnString("[\"a\n\",b]"))
assert.Equal([]interface{}{"a", "\nb"}, unmarshalOrReturnString("[a,\"\nb\"]"))
assert.Equal([]interface{}{" a\n ", " \nb "}, unmarshalOrReturnString("[\" a\n \",\" \nb \"]"))
assert.Equal([]interface{}{"a", int64(10)}, unmarshalOrReturnString("[a,10]"))
assert.Equal([]interface{}{int64(10), "a"}, unmarshalOrReturnString("[10,a]"))
assert.Equal([]interface{}{"a", true}, unmarshalOrReturnString("[a,true]"))
assert.Equal([]interface{}{false, "a"}, unmarshalOrReturnString("[false,a]"))
}
func TestParseCmdline(t *testing.T) { func TestParseCmdline(t *testing.T) {
assert := require.New(t) assert := require.New(t)
@ -161,18 +207,20 @@ func TestParseCmdline(t *testing.T) {
"rescue": true, "rescue": true,
"key1": "value1", "key1": "value1",
"key2": "value2", "key2": "value2",
"keyArray": []interface{}{"1", "2"}, "keyArray": []interface{}{int64(1), int64(2)},
"obj1": map[interface{}]interface{}{ "obj1": map[interface{}]interface{}{
"key3": "3value", "key3": "3value",
"obj2": map[interface{}]interface{}{ "obj2": map[interface{}]interface{}{
"key4": true, "key4": true,
}, },
}, },
"key5": 5, "key5": int64(5),
"key6": "a,b",
"key7": "a\nb",
}, },
} }
actual := parseCmdline("a b rancher.rescue rancher.keyArray=[1,2] rancher.key1=value1 c rancher.key2=value2 rancher.obj1.key3=3value rancher.obj1.obj2.key4 rancher.key5=5") actual := parseCmdline("a b rancher.rescue rancher.keyArray=[1,2] rancher.key1=value1 c rancher.key2=value2 rancher.obj1.key3=3value rancher.obj1.obj2.key4 rancher.key5=5 rancher.key6=a,b rancher.key7=a\nb")
assert.Equal(expected, actual) assert.Equal(expected, actual)
} }

View File

@ -2,10 +2,9 @@ package config
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/rancher/os/util" "github.com/rancher/os/util"
"regexp"
"strconv"
"strings" "strings"
) )
@ -87,7 +86,7 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
// Reached end, set the value // Reached end, set the value
if last && value != nil { if last && value != nil {
if s, ok := value.(string); ok { if s, ok := value.(string); ok {
value = DummyMarshall(s) value = unmarshalOrReturnString(s)
} }
t[part] = value t[part] = value
@ -121,28 +120,36 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
return "", tData return "", tData
} }
func DummyMarshall(value string) interface{} { // YAML parsers will remove newlines, but we'd like to keep those
if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") { // replace newlines with magicString, and then undo after unmarshaling
result := []interface{}{} var magicString = "9XsJcx6dR5EERYCC"
for _, i := range strings.Split(value[1:len(value)-1], ",") {
result = append(result, strings.TrimSpace(i)) func reverseReplacement(result interface{}) interface{} {
switch val := result.(type) {
case map[interface{}]interface{}:
for k, v := range val {
val[k] = reverseReplacement(v)
} }
return result return val
case []interface{}:
for i, item := range val {
val[i] = reverseReplacement(item)
}
return val
case string:
return strings.Replace(val, magicString, "\n", -1)
} }
if value == "true" { return result
return true }
} else if value == "false" {
return false
} else if ok, _ := regexp.MatchString("^[0-9]+$", value); ok {
i, err := strconv.Atoi(value)
if err != nil {
panic(err)
}
return i
}
return value func unmarshalOrReturnString(value string) (result interface{}) {
value = strings.Replace(value, "\n", magicString, -1)
if err := yaml.Unmarshal([]byte(value), &result); err != nil {
result = value
}
result = reverseReplacement(result)
return
} }
func parseCmdline(cmdLine string) map[interface{}]interface{} { func parseCmdline(cmdLine string) map[interface{}]interface{} {
@ -167,7 +174,7 @@ outer:
keys := strings.Split(kv[0], ".") keys := strings.Split(kv[0], ".")
for i, key := range keys { for i, key := range keys {
if i == len(keys)-1 { if i == len(keys)-1 {
current[key] = DummyMarshall(value) current[key] = unmarshalOrReturnString(value)
} else { } else {
if obj, ok := current[key]; ok { if obj, ok := current[key]; ok {
if newCurrent, ok := obj.(map[interface{}]interface{}); ok { if newCurrent, ok := obj.(map[interface{}]interface{}); ok {