1
0
mirror of https://github.com/rancher/os.git synced 2025-07-12 14:18:01 +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)
}
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) {
assert := require.New(t)
@ -161,18 +207,20 @@ func TestParseCmdline(t *testing.T) {
"rescue": true,
"key1": "value1",
"key2": "value2",
"keyArray": []interface{}{"1", "2"},
"keyArray": []interface{}{int64(1), int64(2)},
"obj1": map[interface{}]interface{}{
"key3": "3value",
"obj2": map[interface{}]interface{}{
"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)
}

View File

@ -2,10 +2,9 @@ package config
import (
log "github.com/Sirupsen/logrus"
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/rancher/os/util"
"regexp"
"strconv"
"strings"
)
@ -87,7 +86,7 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
// Reached end, set the value
if last && value != nil {
if s, ok := value.(string); ok {
value = DummyMarshall(s)
value = unmarshalOrReturnString(s)
}
t[part] = value
@ -121,28 +120,36 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
return "", tData
}
func DummyMarshall(value string) interface{} {
if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
result := []interface{}{}
for _, i := range strings.Split(value[1:len(value)-1], ",") {
result = append(result, strings.TrimSpace(i))
// YAML parsers will remove newlines, but we'd like to keep those
// replace newlines with magicString, and then undo after unmarshaling
var magicString = "9XsJcx6dR5EERYCC"
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 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 result
}
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{} {
@ -167,7 +174,7 @@ outer:
keys := strings.Split(kv[0], ".")
for i, key := range keys {
if i == len(keys)-1 {
current[key] = DummyMarshall(value)
current[key] = unmarshalOrReturnString(value)
} else {
if obj, ok := current[key]; ok {
if newCurrent, ok := obj.(map[interface{}]interface{}); ok {