diff --git a/cmd/control/config.go b/cmd/control/config.go index f70d7c85..8b83c74c 100644 --- a/cmd/control/config.go +++ b/cmd/control/config.go @@ -211,7 +211,7 @@ func configGet(c *cli.Context) { log.WithFields(log.Fields{"err": err}).Fatal("config get: failed to load config") } - val, err := cfg.Get(arg) + val, err := cfg.GetIgnoreOmitEmpty(arg) if err != nil { log.WithFields(log.Fields{"cfg": cfg, "key": arg, "val": val, "err": err}).Fatal("config get: failed to retrieve value") } diff --git a/config/config.go b/config/config.go index 3175cdee..1c771ee1 100644 --- a/config/config.go +++ b/config/config.go @@ -140,6 +140,16 @@ func (c *CloudConfig) Get(key string) (interface{}, error) { return v, nil } +func (c *CloudConfig) GetIgnoreOmitEmpty(key string) (interface{}, error) { + data := map[interface{}]interface{}{} + if err := util.ConvertIgnoreOmitEmpty(c, &data); err != nil { + return nil, err + } + + v, _ := getOrSetVal(key, data, nil) + return v, nil +} + func (c *CloudConfig) Set(key string, value interface{}) (*CloudConfig, error) { data := map[interface{}]interface{}{} if err := util.Convert(c, &data); err != nil { diff --git a/trash.yml b/trash.yml index d1e11c31..e5a38349 100644 --- a/trash.yml +++ b/trash.yml @@ -5,7 +5,8 @@ import: version: v0.9.0 - package: github.com/cloudfoundry-incubator/candiedyaml - version: 55a459c2d9da2b078f0725e5fb324823b2c71702 + version: 01cbc92901719f599b11f3a7e3b1768d7002b0bb + repo: https://github.com/rancher/candiedyaml - package: github.com/codegangsta/cli version: v1.2.0 diff --git a/util/util.go b/util/util.go index f903e470..2993e303 100644 --- a/util/util.go +++ b/util/util.go @@ -1,6 +1,7 @@ package util import ( + "bytes" "errors" "fmt" "io" @@ -68,6 +69,25 @@ func Convert(from, to interface{}) error { return yaml.Unmarshal(bytes, to) } +func ConvertIgnoreOmitEmpty(from, to interface{}) error { + var buffer bytes.Buffer + + encoder := yaml.NewEncoder(&buffer) + encoder.IgnoreOmitEmpty = true + + if err := encoder.Encode(from); err != nil { + return err + } + + decoder := yaml.NewDecoder(&buffer) + + if err := decoder.Decode(to); err != nil { + return err + } + + return nil +} + func Copy(d interface{}) interface{} { switch d := d.(type) { case map[interface{}]interface{}: diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/README.md b/vendor/github.com/cloudfoundry-incubator/candiedyaml/README.md index 4979e590..266c28c7 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/README.md +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/README.md @@ -25,7 +25,8 @@ func main() { println("File does not exist:", err.Error()) os.Exit(1) } - + defer file.Close() + document := new(interface{}) decoder := candiedyaml.NewDecoder(file) err = decoder.Decode(document) @@ -41,7 +42,8 @@ func main() { println("Failed to open file for writing:", err.Error()) os.Exit(1) } - + defer fileToWrite.Close() + encoder := candiedyaml.NewEncoder(fileToWrite) err = encoder.Encode(document) diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/decode_test.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/decode_test.go index 6ba1275a..dd180b57 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/decode_test.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/decode_test.go @@ -62,6 +62,15 @@ var _ = Describe("Decode", func() { Expect(err).NotTo(HaveOccurred()) Expect(v).To(Equal(map[interface{}]interface{}{"": ""})) }) + + It("Decodes strings starting with a colon", func() { + d := NewDecoder(strings.NewReader(`:colon +`)) + var v interface{} + err := d.Decode(&v) + Expect(err).NotTo(HaveOccurred()) + Expect(v).To(Equal(":colon")) + }) }) Context("Sequence", func() { diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/emitter.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/emitter.go index a42df052..bd2014f3 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/emitter.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/emitter.go @@ -1276,7 +1276,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { for i, w := 0, 0; i < len(value); i += w { w = width(value[i]) - followed_by_whitespace = i+w >= len(value) || is_blankz_at(value, w) + followed_by_whitespace = i+w >= len(value) || is_blankz_at(value, i+w) if i == 0 { switch value[i] { diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode.go index fd991808..fa8466be 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode.go @@ -57,6 +57,8 @@ type Encoder struct { event yaml_event_t flow bool err error + + IgnoreOmitEmpty bool } func Marshal(v interface{}) ([]byte, error) { @@ -174,7 +176,7 @@ func (e *Encoder) emitStruct(tag string, v reflect.Value) { e.mapping(tag, func() { for _, f := range fields { fv := fieldByIndex(v, f.index) - if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) { + if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) && !e.IgnoreOmitEmpty { continue } diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode_test.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode_test.go index d8c2aa81..82563c79 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode_test.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/encode_test.go @@ -68,6 +68,14 @@ var _ = Describe("Encode", func() { }) + It("handles strings that contain colons followed by whitespace", func() { + err := enc.Encode("contains: colon") + Expect(err).NotTo(HaveOccurred()) + Expect(buf.String()).To(Equal(`'contains: colon' +`)) + + }) + Context("handles ints", func() { It("handles ints", func() { err := enc.Encode(13) @@ -303,7 +311,7 @@ int: 123 }) Context("Maps", func() { - It("Decodes simple maps", func() { + It("Encodes simple maps", func() { err := enc.Encode(&map[string]string{ "name": "Mark McGwire", "hr": "65", @@ -315,10 +323,27 @@ int: 123 hr: "65" name: Mark McGwire `)) - }) - It("Decodes mix types", func() { + It("sorts by key when strings otherwise by kind", func() { + err := enc.Encode(&map[interface{}]string{ + 1.2: "float", + 8: "integer", + "name": "Mark McGwire", + "hr": "65", + "avg": "0.278", + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(buf.String()).To(Equal(`8: integer +1.2: float +avg: "0.278" +hr: "65" +name: Mark McGwire +`)) + }) + + It("encodes mix types", func() { err := enc.Encode(&map[string]interface{}{ "name": "Mark McGwire", "hr": 65, @@ -330,12 +355,11 @@ name: Mark McGwire hr: 65 name: Mark McGwire `)) - }) }) Context("Sequence of Maps", func() { - It("decodes", func() { + It("encodes", func() { err := enc.Encode([]map[string]interface{}{ {"name": "Mark McGwire", "hr": 65, @@ -360,7 +384,7 @@ name: Mark McGwire }) Context("Maps of Sequence", func() { - It("decodes", func() { + It("encodes", func() { err := enc.Encode(map[string][]interface{}{ "name": []interface{}{"Mark McGwire", "Sammy Sosa"}, "hr": []interface{}{65, 63}, diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/resolver.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/resolver.go index 65a6d3d4..fb9e8be8 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/resolver.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/resolver.go @@ -323,7 +323,7 @@ func resolve_time(val string, v reflect.Value, event yaml_event_t) (string, erro } else { matches = timestamp_regexp.FindStringSubmatch(val) if len(matches) == 0 { - return "", fmt.Errorf("Invalid timestap: '%s' at %s", val, event.start_mark) + return "", fmt.Errorf("Invalid timestamp: '%s' at %s", val, event.start_mark) } year, _ := strconv.Atoi(matches[1]) diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/scanner.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/scanner.go index f856a563..5c080a06 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/scanner.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/scanner.go @@ -909,7 +909,7 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { b == '@' || b == '`') || (b == '-' && !is_blank(buf[pos+1])) || (parser.flow_level == 0 && - (buf[pos] == '?' || buf[pos+1] == ':') && + (buf[pos] == '?' || buf[pos] == ':') && !is_blank(buf[pos+1])) { return yaml_parser_fetch_plain_scalar(parser) } diff --git a/vendor/github.com/cloudfoundry-incubator/candiedyaml/tags.go b/vendor/github.com/cloudfoundry-incubator/candiedyaml/tags.go index 4df0b0a7..f153aee4 100644 --- a/vendor/github.com/cloudfoundry-incubator/candiedyaml/tags.go +++ b/vendor/github.com/cloudfoundry-incubator/candiedyaml/tags.go @@ -306,10 +306,27 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type { // It implements the methods to sort by string. type stringValues []reflect.Value -func (sv stringValues) Len() int { return len(sv) } -func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } -func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } -func (sv stringValues) get(i int) string { return sv[i].String() } +func (sv stringValues) Len() int { return len(sv) } +func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv stringValues) Less(i, j int) bool { + av, ak := getElem(sv[i]) + bv, bk := getElem(sv[j]) + if ak == reflect.String && bk == reflect.String { + return av.String() < bv.String() + } + + return ak < bk +} + +func getElem(v reflect.Value) (reflect.Value, reflect.Kind) { + k := v.Kind() + for k == reflect.Interface || k == reflect.Ptr && !v.IsNil() { + v = v.Elem() + k = v.Kind() + } + + return v, k +} // parseTag splits a struct field's json tag into its name and // comma-separated options.