From 9cab6c95cf0efba918c88ac621731c8910322c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Wed, 30 Aug 2023 15:08:36 +0200 Subject: [PATCH] chore: Replace ghodss/yaml with sigs.k8s.io/yaml (#6195) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a fork that is maintained by the kubernetes community. https://github.com/kubernetes-sigs/yaml Signed-off-by: Manuel RĂ¼ger --- go.mod | 2 +- go.sum | 3 +- internal/config/config.go | 2 +- internal/config/config_test.go | 2 +- internal/strvals/parser.go | 2 +- internal/strvals/parser_test.go | 2 +- loader/loader.go | 2 +- plugins/bundle/config_test.go | 2 +- topdown/encoding.go | 8 +- topdown/topdown_test.go | 3 +- util/json.go | 2 +- vendor/github.com/ghodss/yaml/.travis.yml | 7 - vendor/modules.txt | 6 +- .../ghodss => sigs.k8s.io}/yaml/.gitignore | 4 + vendor/sigs.k8s.io/yaml/.travis.yml | 12 ++ vendor/sigs.k8s.io/yaml/CONTRIBUTING.md | 31 +++++ .../ghodss => sigs.k8s.io}/yaml/LICENSE | 0 vendor/sigs.k8s.io/yaml/OWNERS | 27 ++++ .../ghodss => sigs.k8s.io}/yaml/README.md | 16 ++- vendor/sigs.k8s.io/yaml/RELEASE.md | 9 ++ vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS | 17 +++ vendor/sigs.k8s.io/yaml/code-of-conduct.md | 3 + .../ghodss => sigs.k8s.io}/yaml/fields.go | 1 + .../ghodss => sigs.k8s.io}/yaml/yaml.go | 129 ++++++++++++++++-- vendor/sigs.k8s.io/yaml/yaml_go110.go | 14 ++ 25 files changed, 261 insertions(+), 45 deletions(-) delete mode 100644 vendor/github.com/ghodss/yaml/.travis.yml rename vendor/{github.com/ghodss => sigs.k8s.io}/yaml/.gitignore (88%) create mode 100644 vendor/sigs.k8s.io/yaml/.travis.yml create mode 100644 vendor/sigs.k8s.io/yaml/CONTRIBUTING.md rename vendor/{github.com/ghodss => sigs.k8s.io}/yaml/LICENSE (100%) create mode 100644 vendor/sigs.k8s.io/yaml/OWNERS rename vendor/{github.com/ghodss => sigs.k8s.io}/yaml/README.md (86%) create mode 100644 vendor/sigs.k8s.io/yaml/RELEASE.md create mode 100644 vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS create mode 100644 vendor/sigs.k8s.io/yaml/code-of-conduct.md rename vendor/{github.com/ghodss => sigs.k8s.io}/yaml/fields.go (99%) rename vendor/{github.com/ghodss => sigs.k8s.io}/yaml/yaml.go (66%) create mode 100644 vendor/sigs.k8s.io/yaml/yaml_go110.go diff --git a/go.mod b/go.mod index 7ecef7f602..d12ecdb96b 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/fortytw2/leaktest v1.3.0 github.com/foxcpp/go-mockdns v1.0.0 github.com/fsnotify/fsnotify v1.6.0 - github.com/ghodss/yaml v1.0.0 github.com/go-ini/ini v1.67.0 github.com/go-logr/logr v1.2.4 github.com/gobwas/glob v0.2.3 @@ -44,6 +43,7 @@ require ( gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 oras.land/oras-go/v2 v2.2.1 + sigs.k8s.io/yaml v1.3.0 ) require ( diff --git a/go.sum b/go.sum index f78d86252c..1aa20bfff0 100644 --- a/go.sum +++ b/go.sum @@ -112,7 +112,6 @@ github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -646,3 +645,5 @@ oras.land/oras-go/v2 v2.2.1/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7u rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/config/config.go b/internal/config/config.go index 82be84dea0..b1a9731f65 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,7 +12,7 @@ import ( "regexp" "strings" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" "github.com/open-policy-agent/opa/internal/strvals" "github.com/open-policy-agent/opa/keys" diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 52965a8340..25beebfec7 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" "github.com/open-policy-agent/opa/util/test" ) diff --git a/internal/strvals/parser.go b/internal/strvals/parser.go index 0fc8936af1..1fc07f68c3 100644 --- a/internal/strvals/parser.go +++ b/internal/strvals/parser.go @@ -23,7 +23,7 @@ import ( "strconv" "strings" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) // ErrNotList indicates that a non-list was treated as a list. diff --git a/internal/strvals/parser_test.go b/internal/strvals/parser_test.go index d1445406b7..a31410d809 100644 --- a/internal/strvals/parser_test.go +++ b/internal/strvals/parser_test.go @@ -18,7 +18,7 @@ package strvals import ( "testing" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) func TestSetIndex(t *testing.T) { diff --git a/loader/loader.go b/loader/loader.go index 8640d9c234..df45259df4 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -15,7 +15,7 @@ import ( "sort" "strings" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/bundle" diff --git a/plugins/bundle/config_test.go b/plugins/bundle/config_test.go index d4b0ea9723..0dbd590b48 100644 --- a/plugins/bundle/config_test.go +++ b/plugins/bundle/config_test.go @@ -14,7 +14,7 @@ import ( "github.com/open-policy-agent/opa/bundle" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) func TestConfigValidation(t *testing.T) { diff --git a/topdown/encoding.go b/topdown/encoding.go index f2129d8cd0..19ba323d19 100644 --- a/topdown/encoding.go +++ b/topdown/encoding.go @@ -13,7 +13,7 @@ import ( "net/url" "strings" - ghodss "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/topdown/builtins" @@ -232,7 +232,7 @@ func builtinYAMLMarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.T return err } - bs, err := ghodss.JSONToYAML(buf.Bytes()) + bs, err := yaml.JSONToYAML(buf.Bytes()) if err != nil { return err } @@ -247,7 +247,7 @@ func builtinYAMLUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast return err } - bs, err := ghodss.YAMLToJSON([]byte(str)) + bs, err := yaml.YAMLToJSON([]byte(str)) if err != nil { return err } @@ -273,7 +273,7 @@ func builtinYAMLIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.T } var x interface{} - err = ghodss.Unmarshal([]byte(str), &x) + err = yaml.Unmarshal([]byte(str), &x) return iter(ast.BooleanTerm(err == nil)) } diff --git a/topdown/topdown_test.go b/topdown/topdown_test.go index 0ea8ac9ae8..b2d3838e81 100644 --- a/topdown/topdown_test.go +++ b/topdown/topdown_test.go @@ -21,8 +21,7 @@ import ( "time" "github.com/open-policy-agent/opa/format" - - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" iCache "github.com/open-policy-agent/opa/topdown/cache" diff --git a/util/json.go b/util/json.go index 9c87946162..4f1e14513f 100644 --- a/util/json.go +++ b/util/json.go @@ -11,7 +11,7 @@ import ( "io" "reflect" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" "github.com/open-policy-agent/opa/loader/extension" ) diff --git a/vendor/github.com/ghodss/yaml/.travis.yml b/vendor/github.com/ghodss/yaml/.travis.yml deleted file mode 100644 index 0e9d6edc01..0000000000 --- a/vendor/github.com/ghodss/yaml/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go -go: - - 1.3 - - 1.4 -script: - - go test - - go build diff --git a/vendor/modules.txt b/vendor/modules.txt index 3b6e4f9c5f..4f4418eb7e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -91,9 +91,6 @@ github.com/foxcpp/go-mockdns # github.com/fsnotify/fsnotify v1.6.0 ## explicit; go 1.16 github.com/fsnotify/fsnotify -# github.com/ghodss/yaml v1.0.0 -## explicit -github.com/ghodss/yaml # github.com/go-ini/ini v1.67.0 ## explicit github.com/go-ini/ini @@ -487,4 +484,7 @@ oras.land/oras-go/v2/registry/remote/auth oras.land/oras-go/v2/registry/remote/errcode oras.land/oras-go/v2/registry/remote/internal/errutil oras.land/oras-go/v2/registry/remote/retry +# sigs.k8s.io/yaml v1.3.0 +## explicit; go 1.12 +sigs.k8s.io/yaml # github.com/golang/glog => ./build/replacements/github.com/golang/glog diff --git a/vendor/github.com/ghodss/yaml/.gitignore b/vendor/sigs.k8s.io/yaml/.gitignore similarity index 88% rename from vendor/github.com/ghodss/yaml/.gitignore rename to vendor/sigs.k8s.io/yaml/.gitignore index e256a31e00..2dc92904ef 100644 --- a/vendor/github.com/ghodss/yaml/.gitignore +++ b/vendor/sigs.k8s.io/yaml/.gitignore @@ -6,6 +6,10 @@ .project .settings/** +# Idea files +.idea/** +.idea/ + # Emacs save files *~ diff --git a/vendor/sigs.k8s.io/yaml/.travis.yml b/vendor/sigs.k8s.io/yaml/.travis.yml new file mode 100644 index 0000000000..54ed8f9cb9 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/.travis.yml @@ -0,0 +1,12 @@ +language: go +arch: arm64 +dist: focal +go: 1.15.x +script: + - diff -u <(echo -n) <(gofmt -d *.go) + - diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON) + - GO111MODULE=on go vet . + - GO111MODULE=on go test -v -race ./... + - git diff --exit-code +install: + - GO111MODULE=off go get golang.org/x/lint/golint diff --git a/vendor/sigs.k8s.io/yaml/CONTRIBUTING.md b/vendor/sigs.k8s.io/yaml/CONTRIBUTING.md new file mode 100644 index 0000000000..de47115137 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing Guidelines + +Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt: + +_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._ + +## Getting Started + +We have full documentation on how to get started contributing here: + + + +- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests +- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing) +- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers + +## Mentorship + +- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! + + diff --git a/vendor/github.com/ghodss/yaml/LICENSE b/vendor/sigs.k8s.io/yaml/LICENSE similarity index 100% rename from vendor/github.com/ghodss/yaml/LICENSE rename to vendor/sigs.k8s.io/yaml/LICENSE diff --git a/vendor/sigs.k8s.io/yaml/OWNERS b/vendor/sigs.k8s.io/yaml/OWNERS new file mode 100644 index 0000000000..325b40b076 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/OWNERS @@ -0,0 +1,27 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: +- dims +- lavalamp +- smarterclayton +- deads2k +- sttts +- liggitt +- caesarxuchao +reviewers: +- dims +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- gmarek +- sttts +- ncdc +- tallclair +labels: +- sig/api-machinery diff --git a/vendor/github.com/ghodss/yaml/README.md b/vendor/sigs.k8s.io/yaml/README.md similarity index 86% rename from vendor/github.com/ghodss/yaml/README.md rename to vendor/sigs.k8s.io/yaml/README.md index 0200f75b4d..e81cc426be 100644 --- a/vendor/github.com/ghodss/yaml/README.md +++ b/vendor/sigs.k8s.io/yaml/README.md @@ -1,12 +1,14 @@ # YAML marshaling and unmarshaling support for Go -[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) +[![Build Status](https://travis-ci.org/kubernetes-sigs/yaml.svg)](https://travis-ci.org/kubernetes-sigs/yaml) + +kubernetes-sigs/yaml is a permanent fork of [ghodss/yaml](https://github.com/ghodss/yaml). ## Introduction A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. -In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://web.archive.org/web/20190603050330/http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). ## Compatibility @@ -32,13 +34,13 @@ GOOD: To install, run: ``` -$ go get github.com/ghodss/yaml +$ go get sigs.k8s.io/yaml ``` And import using: ``` -import "github.com/ghodss/yaml" +import "sigs.k8s.io/yaml" ``` Usage is very similar to the JSON library: @@ -49,7 +51,7 @@ package main import ( "fmt" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) type Person struct { @@ -93,7 +95,7 @@ package main import ( "fmt" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) func main() { @@ -105,8 +107,8 @@ func main() { } fmt.Println(string(y)) /* Output: - name: John age: 30 + name: John */ j2, err := yaml.YAMLToJSON(y) if err != nil { diff --git a/vendor/sigs.k8s.io/yaml/RELEASE.md b/vendor/sigs.k8s.io/yaml/RELEASE.md new file mode 100644 index 0000000000..6b642464e5 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/RELEASE.md @@ -0,0 +1,9 @@ +# Release Process + +The `yaml` Project is released on an as-needed basis. The process is as follows: + +1. An issue is proposing a new release with a changelog since the last release +1. All [OWNERS](OWNERS) must LGTM this release +1. An OWNER runs `git tag -s $VERSION` and inserts the changelog and pushes the tag with `git push $VERSION` +1. The release issue is closed +1. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] kubernetes-template-project $VERSION is released` diff --git a/vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS b/vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS new file mode 100644 index 0000000000..0648a8ebff --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/vendor/sigs.k8s.io/yaml/code-of-conduct.md b/vendor/sigs.k8s.io/yaml/code-of-conduct.md new file mode 100644 index 0000000000..0d15c00cf3 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/github.com/ghodss/yaml/fields.go b/vendor/sigs.k8s.io/yaml/fields.go similarity index 99% rename from vendor/github.com/ghodss/yaml/fields.go rename to vendor/sigs.k8s.io/yaml/fields.go index 5860074026..235b7f2cf6 100644 --- a/vendor/github.com/ghodss/yaml/fields.go +++ b/vendor/sigs.k8s.io/yaml/fields.go @@ -1,6 +1,7 @@ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. + package yaml import ( diff --git a/vendor/github.com/ghodss/yaml/yaml.go b/vendor/sigs.k8s.io/yaml/yaml.go similarity index 66% rename from vendor/github.com/ghodss/yaml/yaml.go rename to vendor/sigs.k8s.io/yaml/yaml.go index 4fb4054a8b..efbc535d41 100644 --- a/vendor/github.com/ghodss/yaml/yaml.go +++ b/vendor/sigs.k8s.io/yaml/yaml.go @@ -4,13 +4,14 @@ import ( "bytes" "encoding/json" "fmt" + "io" "reflect" "strconv" "gopkg.in/yaml.v2" ) -// Marshals the object into JSON then converts JSON to YAML and returns the +// Marshal marshals the object into JSON then converts JSON to YAML and returns the // YAML. func Marshal(o interface{}) ([]byte, error) { j, err := json.Marshal(o) @@ -26,15 +27,35 @@ func Marshal(o interface{}) ([]byte, error) { return y, nil } -// Converts YAML to JSON then uses JSON to unmarshal into an object. -func Unmarshal(y []byte, o interface{}) error { +// JSONOpt is a decoding option for decoding from JSON format. +type JSONOpt func(*json.Decoder) *json.Decoder + +// Unmarshal converts YAML to JSON then uses JSON to unmarshal into an object, +// optionally configuring the behavior of the JSON unmarshal. +func Unmarshal(y []byte, o interface{}, opts ...JSONOpt) error { + return yamlUnmarshal(y, o, false, opts...) +} + +// UnmarshalStrict strictly converts YAML to JSON then uses JSON to unmarshal +// into an object, optionally configuring the behavior of the JSON unmarshal. +func UnmarshalStrict(y []byte, o interface{}, opts ...JSONOpt) error { + return yamlUnmarshal(y, o, true, append(opts, DisallowUnknownFields)...) +} + +// yamlUnmarshal unmarshals the given YAML byte stream into the given interface, +// optionally performing the unmarshalling strictly +func yamlUnmarshal(y []byte, o interface{}, strict bool, opts ...JSONOpt) error { vo := reflect.ValueOf(o) - j, err := yamlToJSON(y, &vo) + unmarshalFn := yaml.Unmarshal + if strict { + unmarshalFn = yaml.UnmarshalStrict + } + j, err := yamlToJSON(y, &vo, unmarshalFn) if err != nil { return fmt.Errorf("error converting YAML to JSON: %v", err) } - err = json.Unmarshal(j, o) + err = jsonUnmarshal(bytes.NewReader(j), o, opts...) if err != nil { return fmt.Errorf("error unmarshaling JSON: %v", err) } @@ -42,7 +63,22 @@ func Unmarshal(y []byte, o interface{}) error { return nil } -// Convert JSON to YAML. +// jsonUnmarshal unmarshals the JSON byte stream from the given reader into the +// object, optionally applying decoder options prior to decoding. We are not +// using json.Unmarshal directly as we want the chance to pass in non-default +// options. +func jsonUnmarshal(r io.Reader, o interface{}, opts ...JSONOpt) error { + d := json.NewDecoder(r) + for _, opt := range opts { + d = opt(d) + } + if err := d.Decode(&o); err != nil { + return fmt.Errorf("while decoding JSON: %v", err) + } + return nil +} + +// JSONToYAML Converts JSON to YAML. func JSONToYAML(j []byte) ([]byte, error) { // Convert the JSON to an object. var jsonObj interface{} @@ -60,8 +96,8 @@ func JSONToYAML(j []byte) ([]byte, error) { return yaml.Marshal(jsonObj) } -// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through -// this method should be a no-op. +// YAMLToJSON converts YAML to JSON. Since JSON is a subset of YAML, +// passing JSON through this method should be a no-op. // // Things YAML can do that are not supported by JSON: // * In YAML you can have binary and null keys in your maps. These are invalid @@ -70,14 +106,22 @@ func JSONToYAML(j []byte) ([]byte, error) { // use binary data with this library, encode the data as base64 as usual but do // not use the !!binary tag in your YAML. This will ensure the original base64 // encoded data makes it all the way through to the JSON. +// +// For strict decoding of YAML, use YAMLToJSONStrict. func YAMLToJSON(y []byte) ([]byte, error) { - return yamlToJSON(y, nil) + return yamlToJSON(y, nil, yaml.Unmarshal) } -func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) { +// YAMLToJSONStrict is like YAMLToJSON but enables strict YAML decoding, +// returning an error on any duplicate field names. +func YAMLToJSONStrict(y []byte) ([]byte, error) { + return yamlToJSON(y, nil, yaml.UnmarshalStrict) +} + +func yamlToJSON(y []byte, jsonTarget *reflect.Value, yamlUnmarshal func([]byte, interface{}) error) ([]byte, error) { // Convert the YAML to an object. var yamlObj interface{} - err := yaml.Unmarshal(y, &yamlObj) + err := yamlUnmarshal(y, &yamlObj) if err != nil { return nil, err } @@ -272,6 +316,65 @@ func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (in } return yamlObj, nil } - - return nil, nil +} + +// JSONObjectToYAMLObject converts an in-memory JSON object into a YAML in-memory MapSlice, +// without going through a byte representation. A nil or empty map[string]interface{} input is +// converted to an empty map, i.e. yaml.MapSlice(nil). +// +// interface{} slices stay interface{} slices. map[string]interface{} becomes yaml.MapSlice. +// +// int64 and float64 are down casted following the logic of github.com/go-yaml/yaml: +// - float64s are down-casted as far as possible without data-loss to int, int64, uint64. +// - int64s are down-casted to int if possible without data-loss. +// +// Big int/int64/uint64 do not lose precision as in the json-yaml roundtripping case. +// +// string, bool and any other types are unchanged. +func JSONObjectToYAMLObject(j map[string]interface{}) yaml.MapSlice { + if len(j) == 0 { + return nil + } + ret := make(yaml.MapSlice, 0, len(j)) + for k, v := range j { + ret = append(ret, yaml.MapItem{Key: k, Value: jsonToYAMLValue(v)}) + } + return ret +} + +func jsonToYAMLValue(j interface{}) interface{} { + switch j := j.(type) { + case map[string]interface{}: + if j == nil { + return interface{}(nil) + } + return JSONObjectToYAMLObject(j) + case []interface{}: + if j == nil { + return interface{}(nil) + } + ret := make([]interface{}, len(j)) + for i := range j { + ret[i] = jsonToYAMLValue(j[i]) + } + return ret + case float64: + // replicate the logic in https://github.com/go-yaml/yaml/blob/51d6538a90f86fe93ac480b35f37b2be17fef232/resolve.go#L151 + if i64 := int64(j); j == float64(i64) { + if i := int(i64); i64 == int64(i) { + return i + } + return i64 + } + if ui64 := uint64(j); j == float64(ui64) { + return ui64 + } + return j + case int64: + if i := int(j); j == int64(i) { + return i + } + return j + } + return j } diff --git a/vendor/sigs.k8s.io/yaml/yaml_go110.go b/vendor/sigs.k8s.io/yaml/yaml_go110.go new file mode 100644 index 0000000000..ab3e06a222 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/yaml_go110.go @@ -0,0 +1,14 @@ +// This file contains changes that are only compatible with go 1.10 and onwards. + +// +build go1.10 + +package yaml + +import "encoding/json" + +// DisallowUnknownFields configures the JSON decoder to error out if unknown +// fields come along, instead of dropping them by default. +func DisallowUnknownFields(d *json.Decoder) *json.Decoder { + d.DisallowUnknownFields() + return d +}