mirror of https://github.com/containers/podman.git
				
				
				
			Merge pull request #18066 from Juneezee/chore/yaml
chore: replace `github.com/ghodss/yaml` with `sigs.k8s.io/yaml`
This commit is contained in:
		
						commit
						83773074e3
					
				|  | @ -17,8 +17,8 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/libpod/define" | 	"github.com/containers/podman/v4/libpod/define" | ||||||
| 	"github.com/containers/podman/v4/pkg/domain/entities" | 	"github.com/containers/podman/v4/pkg/domain/entities" | ||||||
| 	"github.com/containers/podman/v4/pkg/machine" | 	"github.com/containers/podman/v4/pkg/machine" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var infoDescription = `Display information pertaining to the machine host.` | var infoDescription = `Display information pertaining to the machine host.` | ||||||
|  |  | ||||||
|  | @ -10,8 +10,8 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/cmd/podman/registry" | 	"github.com/containers/podman/v4/cmd/podman/registry" | ||||||
| 	"github.com/containers/podman/v4/cmd/podman/validate" | 	"github.com/containers/podman/v4/cmd/podman/validate" | ||||||
| 	"github.com/containers/podman/v4/libpod/define" | 	"github.com/containers/podman/v4/libpod/define" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										3
									
								
								go.mod
								
								
								
								
							|  | @ -28,7 +28,6 @@ require ( | ||||||
| 	github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651 | 	github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651 | ||||||
| 	github.com/docker/go-units v0.5.0 | 	github.com/docker/go-units v0.5.0 | ||||||
| 	github.com/fsnotify/fsnotify v1.6.0 | 	github.com/fsnotify/fsnotify v1.6.0 | ||||||
| 	github.com/ghodss/yaml v1.0.0 |  | ||||||
| 	github.com/godbus/dbus/v5 v5.1.1-0.20221029134443-4b691ce883d5 | 	github.com/godbus/dbus/v5 v5.1.1-0.20221029134443-4b691ce883d5 | ||||||
| 	github.com/google/gofuzz v1.2.0 | 	github.com/google/gofuzz v1.2.0 | ||||||
| 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 | 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 | ||||||
|  | @ -70,6 +69,7 @@ require ( | ||||||
| 	google.golang.org/protobuf v1.30.0 | 	google.golang.org/protobuf v1.30.0 | ||||||
| 	gopkg.in/inf.v0 v0.9.1 | 	gopkg.in/inf.v0 v0.9.1 | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 | 	gopkg.in/yaml.v3 v3.0.1 | ||||||
|  | 	sigs.k8s.io/yaml v1.3.0 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
|  | @ -176,7 +176,6 @@ require ( | ||||||
| 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect | 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect | ||||||
| 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect | 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 // indirect | 	gopkg.in/yaml.v2 v2.4.0 // indirect | ||||||
| 	sigs.k8s.io/yaml v1.3.0 // indirect |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| replace github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.1-0.20220617142545-8b9452f75cbc | replace github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.1-0.20220617142545-8b9452f75cbc | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										1
									
								
								go.sum
								
								
								
								
							|  | @ -370,7 +370,6 @@ github.com/fsouza/go-dockerclient v1.9.6/go.mod h1:Z0GysXoBlysCsdUO2tMK/13R2tvpe | ||||||
| github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= | github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= | ||||||
| github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= | github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= | ||||||
| github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||||||
| github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= |  | ||||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | 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 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= | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/containers/podman/v4/pkg/domain/entities" | 	"github.com/containers/podman/v4/pkg/domain/entities" | ||||||
| 	k8sAPI "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" | 	k8sAPI "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" | ||||||
| 	"github.com/ghodss/yaml" | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (ic *ContainerEngine) KubeApply(ctx context.Context, body io.Reader, options entities.ApplyOptions) error { | func (ic *ContainerEngine) KubeApply(ctx context.Context, body io.Reader, options entities.ApplyOptions) error { | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/pkg/specgen" | 	"github.com/containers/podman/v4/pkg/specgen" | ||||||
| 	generateUtils "github.com/containers/podman/v4/pkg/specgen/generate" | 	generateUtils "github.com/containers/podman/v4/pkg/specgen/generate" | ||||||
| 	"github.com/containers/podman/v4/pkg/systemd/generate" | 	"github.com/containers/podman/v4/pkg/systemd/generate" | ||||||
| 	"github.com/ghodss/yaml" | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { | func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { | ||||||
|  |  | ||||||
|  | @ -32,11 +32,11 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/pkg/util" | 	"github.com/containers/podman/v4/pkg/util" | ||||||
| 	"github.com/containers/podman/v4/utils" | 	"github.com/containers/podman/v4/utils" | ||||||
| 	"github.com/coreos/go-systemd/v22/daemon" | 	"github.com/coreos/go-systemd/v22/daemon" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/opencontainers/go-digest" | 	"github.com/opencontainers/go-digest" | ||||||
| 	"github.com/opencontainers/selinux/go-selinux" | 	"github.com/opencontainers/selinux/go-selinux" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| 	yamlv3 "gopkg.in/yaml.v3" | 	yamlv3 "gopkg.in/yaml.v3" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // sdNotifyAnnotation allows for configuring service-global and
 | // sdNotifyAnnotation allows for configuring service-global and
 | ||||||
|  |  | ||||||
|  | @ -33,9 +33,9 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/pkg/util" | 	"github.com/containers/podman/v4/pkg/util" | ||||||
| 	"github.com/docker/docker/pkg/system" | 	"github.com/docker/docker/pkg/system" | ||||||
| 	"github.com/docker/go-units" | 	"github.com/docker/go-units" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	spec "github.com/opencontainers/runtime-spec/specs-go" | 	spec "github.com/opencontainers/runtime-spec/specs-go" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, podYAML *v1.PodTemplateSpec) (entities.PodCreateOptions, error) { | func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, podYAML *v1.PodTemplateSpec) (entities.PodCreateOptions, error) { | ||||||
|  |  | ||||||
|  | @ -16,8 +16,8 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/util/intstr" | 	"github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/util/intstr" | ||||||
| 	"github.com/containers/podman/v4/pkg/specgen" | 	"github.com/containers/podman/v4/pkg/specgen" | ||||||
| 	"github.com/docker/docker/pkg/system" | 	"github.com/docker/docker/pkg/system" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func createSecrets(t *testing.T, d string) *secrets.SecretsManager { | func createSecrets(t *testing.T, d string) *secrets.SecretsManager { | ||||||
|  |  | ||||||
|  | @ -10,8 +10,8 @@ import ( | ||||||
| 	"github.com/containers/podman/v4/libpod" | 	"github.com/containers/podman/v4/libpod" | ||||||
| 	v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" | 	v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" | ||||||
| 
 | 
 | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/containers/image/v5/types" | 	"github.com/containers/image/v5/types" | ||||||
| 	"github.com/docker/docker/pkg/homedir" | 	"github.com/docker/docker/pkg/homedir" | ||||||
| 	"github.com/ghodss/yaml" | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // registryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all.
 | // registryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all.
 | ||||||
|  |  | ||||||
|  | @ -12,10 +12,10 @@ import ( | ||||||
| 	v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" | 	v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" | ||||||
| 	"github.com/containers/podman/v4/pkg/util" | 	"github.com/containers/podman/v4/pkg/util" | ||||||
| 	. "github.com/containers/podman/v4/test/utils" | 	. "github.com/containers/podman/v4/test/utils" | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| 	. "github.com/onsi/ginkgo" | 	. "github.com/onsi/ginkgo" | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| 	. "github.com/onsi/gomega/gexec" | 	. "github.com/onsi/gomega/gexec" | ||||||
|  | 	"sigs.k8s.io/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var _ = Describe("Podman kube generate", func() { | var _ = Describe("Podman kube generate", func() { | ||||||
|  |  | ||||||
|  | @ -1,20 +0,0 @@ | ||||||
| # OSX leaves these everywhere on SMB shares |  | ||||||
| ._* |  | ||||||
| 
 |  | ||||||
| # Eclipse files |  | ||||||
| .classpath |  | ||||||
| .project |  | ||||||
| .settings/** |  | ||||||
| 
 |  | ||||||
| # Emacs save files |  | ||||||
| *~ |  | ||||||
| 
 |  | ||||||
| # Vim-related files |  | ||||||
| [._]*.s[a-w][a-z] |  | ||||||
| [._]s[a-w][a-z] |  | ||||||
| *.un~ |  | ||||||
| Session.vim |  | ||||||
| .netrwhist |  | ||||||
| 
 |  | ||||||
| # Go test binaries |  | ||||||
| *.test |  | ||||||
|  | @ -1,7 +0,0 @@ | ||||||
| language: go |  | ||||||
| go: |  | ||||||
|   - 1.3 |  | ||||||
|   - 1.4 |  | ||||||
| script: |  | ||||||
|   - go test |  | ||||||
|   - go build |  | ||||||
|  | @ -1,50 +0,0 @@ | ||||||
| The MIT License (MIT) |  | ||||||
| 
 |  | ||||||
| Copyright (c) 2014 Sam Ghods |  | ||||||
| 
 |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
| of this software and associated documentation files (the "Software"), to deal |  | ||||||
| in the Software without restriction, including without limitation the rights |  | ||||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
| copies of the Software, and to permit persons to whom the Software is |  | ||||||
| furnished to do so, subject to the following conditions: |  | ||||||
| 
 |  | ||||||
| The above copyright notice and this permission notice shall be included in all |  | ||||||
| copies or substantial portions of the Software. |  | ||||||
| 
 |  | ||||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |  | ||||||
| SOFTWARE. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Copyright (c) 2012 The Go Authors. All rights reserved. |  | ||||||
| 
 |  | ||||||
| Redistribution and use in source and binary forms, with or without |  | ||||||
| modification, are permitted provided that the following conditions are |  | ||||||
| met: |  | ||||||
| 
 |  | ||||||
|    * Redistributions of source code must retain the above copyright |  | ||||||
| notice, this list of conditions and the following disclaimer. |  | ||||||
|    * Redistributions in binary form must reproduce the above |  | ||||||
| copyright notice, this list of conditions and the following disclaimer |  | ||||||
| in the documentation and/or other materials provided with the |  | ||||||
| distribution. |  | ||||||
|    * Neither the name of Google Inc. nor the names of its |  | ||||||
| contributors may be used to endorse or promote products derived from |  | ||||||
| this software without specific prior written permission. |  | ||||||
| 
 |  | ||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |  | ||||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |  | ||||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |  | ||||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |  | ||||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |  | ||||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | ||||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |  | ||||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  | @ -1,121 +0,0 @@ | ||||||
| # YAML marshaling and unmarshaling support for Go |  | ||||||
| 
 |  | ||||||
| [](https://travis-ci.org/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/). |  | ||||||
| 
 |  | ||||||
| ## Compatibility |  | ||||||
| 
 |  | ||||||
| This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). |  | ||||||
| 
 |  | ||||||
| ## Caveats |  | ||||||
| 
 |  | ||||||
| **Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| BAD: |  | ||||||
| 	exampleKey: !!binary gIGC |  | ||||||
| 
 |  | ||||||
| GOOD: |  | ||||||
| 	exampleKey: gIGC |  | ||||||
| ... and decode the base64 data in your code. |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| **Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. |  | ||||||
| 
 |  | ||||||
| ## Installation and usage |  | ||||||
| 
 |  | ||||||
| To install, run: |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| $ go get github.com/ghodss/yaml |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| And import using: |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| import "github.com/ghodss/yaml" |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Usage is very similar to the JSON library: |  | ||||||
| 
 |  | ||||||
| ```go |  | ||||||
| package main |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 
 |  | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type Person struct { |  | ||||||
| 	Name string `json:"name"` // Affects YAML field names too. |  | ||||||
| 	Age  int    `json:"age"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
| 	// Marshal a Person struct to YAML. |  | ||||||
| 	p := Person{"John", 30} |  | ||||||
| 	y, err := yaml.Marshal(p) |  | ||||||
| 	if err != nil { |  | ||||||
| 		fmt.Printf("err: %v\n", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	fmt.Println(string(y)) |  | ||||||
| 	/* Output: |  | ||||||
| 	age: 30 |  | ||||||
| 	name: John |  | ||||||
| 	*/ |  | ||||||
| 
 |  | ||||||
| 	// Unmarshal the YAML back into a Person struct. |  | ||||||
| 	var p2 Person |  | ||||||
| 	err = yaml.Unmarshal(y, &p2) |  | ||||||
| 	if err != nil { |  | ||||||
| 		fmt.Printf("err: %v\n", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	fmt.Println(p2) |  | ||||||
| 	/* Output: |  | ||||||
| 	{John 30} |  | ||||||
| 	*/ |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| `yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: |  | ||||||
| 
 |  | ||||||
| ```go |  | ||||||
| package main |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 
 |  | ||||||
| 	"github.com/ghodss/yaml" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
| 	j := []byte(`{"name": "John", "age": 30}`) |  | ||||||
| 	y, err := yaml.JSONToYAML(j) |  | ||||||
| 	if err != nil { |  | ||||||
| 		fmt.Printf("err: %v\n", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	fmt.Println(string(y)) |  | ||||||
| 	/* Output: |  | ||||||
| 	name: John |  | ||||||
| 	age: 30 |  | ||||||
| 	*/ |  | ||||||
| 	j2, err := yaml.YAMLToJSON(y) |  | ||||||
| 	if err != nil { |  | ||||||
| 		fmt.Printf("err: %v\n", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	fmt.Println(string(j2)) |  | ||||||
| 	/* Output: |  | ||||||
| 	{"age":30,"name":"John"} |  | ||||||
| 	*/ |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  | @ -1,501 +0,0 @@ | ||||||
| // 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 ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"reflect" |  | ||||||
| 	"sort" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
| 	"unicode" |  | ||||||
| 	"unicode/utf8" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // indirect walks down v allocating pointers as needed,
 |  | ||||||
| // until it gets to a non-pointer.
 |  | ||||||
| // if it encounters an Unmarshaler, indirect stops and returns that.
 |  | ||||||
| // if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
 |  | ||||||
| func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { |  | ||||||
| 	// If v is a named type and is addressable,
 |  | ||||||
| 	// start with its address, so that if the type has pointer methods,
 |  | ||||||
| 	// we find them.
 |  | ||||||
| 	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { |  | ||||||
| 		v = v.Addr() |  | ||||||
| 	} |  | ||||||
| 	for { |  | ||||||
| 		// Load value from interface, but only if the result will be
 |  | ||||||
| 		// usefully addressable.
 |  | ||||||
| 		if v.Kind() == reflect.Interface && !v.IsNil() { |  | ||||||
| 			e := v.Elem() |  | ||||||
| 			if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { |  | ||||||
| 				v = e |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if v.Kind() != reflect.Ptr { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		if v.IsNil() { |  | ||||||
| 			if v.CanSet() { |  | ||||||
| 				v.Set(reflect.New(v.Type().Elem())) |  | ||||||
| 			} else { |  | ||||||
| 				v = reflect.New(v.Type().Elem()) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if v.Type().NumMethod() > 0 { |  | ||||||
| 			if u, ok := v.Interface().(json.Unmarshaler); ok { |  | ||||||
| 				return u, nil, reflect.Value{} |  | ||||||
| 			} |  | ||||||
| 			if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { |  | ||||||
| 				return nil, u, reflect.Value{} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		v = v.Elem() |  | ||||||
| 	} |  | ||||||
| 	return nil, nil, v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // A field represents a single field found in a struct.
 |  | ||||||
| type field struct { |  | ||||||
| 	name      string |  | ||||||
| 	nameBytes []byte                 // []byte(name)
 |  | ||||||
| 	equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
 |  | ||||||
| 
 |  | ||||||
| 	tag       bool |  | ||||||
| 	index     []int |  | ||||||
| 	typ       reflect.Type |  | ||||||
| 	omitEmpty bool |  | ||||||
| 	quoted    bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func fillField(f field) field { |  | ||||||
| 	f.nameBytes = []byte(f.name) |  | ||||||
| 	f.equalFold = foldFunc(f.nameBytes) |  | ||||||
| 	return f |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // byName sorts field by name, breaking ties with depth,
 |  | ||||||
| // then breaking ties with "name came from json tag", then
 |  | ||||||
| // breaking ties with index sequence.
 |  | ||||||
| type byName []field |  | ||||||
| 
 |  | ||||||
| func (x byName) Len() int { return len(x) } |  | ||||||
| 
 |  | ||||||
| func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } |  | ||||||
| 
 |  | ||||||
| func (x byName) Less(i, j int) bool { |  | ||||||
| 	if x[i].name != x[j].name { |  | ||||||
| 		return x[i].name < x[j].name |  | ||||||
| 	} |  | ||||||
| 	if len(x[i].index) != len(x[j].index) { |  | ||||||
| 		return len(x[i].index) < len(x[j].index) |  | ||||||
| 	} |  | ||||||
| 	if x[i].tag != x[j].tag { |  | ||||||
| 		return x[i].tag |  | ||||||
| 	} |  | ||||||
| 	return byIndex(x).Less(i, j) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // byIndex sorts field by index sequence.
 |  | ||||||
| type byIndex []field |  | ||||||
| 
 |  | ||||||
| func (x byIndex) Len() int { return len(x) } |  | ||||||
| 
 |  | ||||||
| func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } |  | ||||||
| 
 |  | ||||||
| func (x byIndex) Less(i, j int) bool { |  | ||||||
| 	for k, xik := range x[i].index { |  | ||||||
| 		if k >= len(x[j].index) { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 		if xik != x[j].index[k] { |  | ||||||
| 			return xik < x[j].index[k] |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return len(x[i].index) < len(x[j].index) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // typeFields returns a list of fields that JSON should recognize for the given type.
 |  | ||||||
| // The algorithm is breadth-first search over the set of structs to include - the top struct
 |  | ||||||
| // and then any reachable anonymous structs.
 |  | ||||||
| func typeFields(t reflect.Type) []field { |  | ||||||
| 	// Anonymous fields to explore at the current level and the next.
 |  | ||||||
| 	current := []field{} |  | ||||||
| 	next := []field{{typ: t}} |  | ||||||
| 
 |  | ||||||
| 	// Count of queued names for current level and the next.
 |  | ||||||
| 	count := map[reflect.Type]int{} |  | ||||||
| 	nextCount := map[reflect.Type]int{} |  | ||||||
| 
 |  | ||||||
| 	// Types already visited at an earlier level.
 |  | ||||||
| 	visited := map[reflect.Type]bool{} |  | ||||||
| 
 |  | ||||||
| 	// Fields found.
 |  | ||||||
| 	var fields []field |  | ||||||
| 
 |  | ||||||
| 	for len(next) > 0 { |  | ||||||
| 		current, next = next, current[:0] |  | ||||||
| 		count, nextCount = nextCount, map[reflect.Type]int{} |  | ||||||
| 
 |  | ||||||
| 		for _, f := range current { |  | ||||||
| 			if visited[f.typ] { |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			visited[f.typ] = true |  | ||||||
| 
 |  | ||||||
| 			// Scan f.typ for fields to include.
 |  | ||||||
| 			for i := 0; i < f.typ.NumField(); i++ { |  | ||||||
| 				sf := f.typ.Field(i) |  | ||||||
| 				if sf.PkgPath != "" { // unexported
 |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				tag := sf.Tag.Get("json") |  | ||||||
| 				if tag == "-" { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				name, opts := parseTag(tag) |  | ||||||
| 				if !isValidTag(name) { |  | ||||||
| 					name = "" |  | ||||||
| 				} |  | ||||||
| 				index := make([]int, len(f.index)+1) |  | ||||||
| 				copy(index, f.index) |  | ||||||
| 				index[len(f.index)] = i |  | ||||||
| 
 |  | ||||||
| 				ft := sf.Type |  | ||||||
| 				if ft.Name() == "" && ft.Kind() == reflect.Ptr { |  | ||||||
| 					// Follow pointer.
 |  | ||||||
| 					ft = ft.Elem() |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				// Record found field and index sequence.
 |  | ||||||
| 				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { |  | ||||||
| 					tagged := name != "" |  | ||||||
| 					if name == "" { |  | ||||||
| 						name = sf.Name |  | ||||||
| 					} |  | ||||||
| 					fields = append(fields, fillField(field{ |  | ||||||
| 						name:      name, |  | ||||||
| 						tag:       tagged, |  | ||||||
| 						index:     index, |  | ||||||
| 						typ:       ft, |  | ||||||
| 						omitEmpty: opts.Contains("omitempty"), |  | ||||||
| 						quoted:    opts.Contains("string"), |  | ||||||
| 					})) |  | ||||||
| 					if count[f.typ] > 1 { |  | ||||||
| 						// If there were multiple instances, add a second,
 |  | ||||||
| 						// so that the annihilation code will see a duplicate.
 |  | ||||||
| 						// It only cares about the distinction between 1 or 2,
 |  | ||||||
| 						// so don't bother generating any more copies.
 |  | ||||||
| 						fields = append(fields, fields[len(fields)-1]) |  | ||||||
| 					} |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				// Record new anonymous struct to explore in next round.
 |  | ||||||
| 				nextCount[ft]++ |  | ||||||
| 				if nextCount[ft] == 1 { |  | ||||||
| 					next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	sort.Sort(byName(fields)) |  | ||||||
| 
 |  | ||||||
| 	// Delete all fields that are hidden by the Go rules for embedded fields,
 |  | ||||||
| 	// except that fields with JSON tags are promoted.
 |  | ||||||
| 
 |  | ||||||
| 	// The fields are sorted in primary order of name, secondary order
 |  | ||||||
| 	// of field index length. Loop over names; for each name, delete
 |  | ||||||
| 	// hidden fields by choosing the one dominant field that survives.
 |  | ||||||
| 	out := fields[:0] |  | ||||||
| 	for advance, i := 0, 0; i < len(fields); i += advance { |  | ||||||
| 		// One iteration per name.
 |  | ||||||
| 		// Find the sequence of fields with the name of this first field.
 |  | ||||||
| 		fi := fields[i] |  | ||||||
| 		name := fi.name |  | ||||||
| 		for advance = 1; i+advance < len(fields); advance++ { |  | ||||||
| 			fj := fields[i+advance] |  | ||||||
| 			if fj.name != name { |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if advance == 1 { // Only one field with this name
 |  | ||||||
| 			out = append(out, fi) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		dominant, ok := dominantField(fields[i : i+advance]) |  | ||||||
| 		if ok { |  | ||||||
| 			out = append(out, dominant) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fields = out |  | ||||||
| 	sort.Sort(byIndex(fields)) |  | ||||||
| 
 |  | ||||||
| 	return fields |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // dominantField looks through the fields, all of which are known to
 |  | ||||||
| // have the same name, to find the single field that dominates the
 |  | ||||||
| // others using Go's embedding rules, modified by the presence of
 |  | ||||||
| // JSON tags. If there are multiple top-level fields, the boolean
 |  | ||||||
| // will be false: This condition is an error in Go and we skip all
 |  | ||||||
| // the fields.
 |  | ||||||
| func dominantField(fields []field) (field, bool) { |  | ||||||
| 	// The fields are sorted in increasing index-length order. The winner
 |  | ||||||
| 	// must therefore be one with the shortest index length. Drop all
 |  | ||||||
| 	// longer entries, which is easy: just truncate the slice.
 |  | ||||||
| 	length := len(fields[0].index) |  | ||||||
| 	tagged := -1 // Index of first tagged field.
 |  | ||||||
| 	for i, f := range fields { |  | ||||||
| 		if len(f.index) > length { |  | ||||||
| 			fields = fields[:i] |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		if f.tag { |  | ||||||
| 			if tagged >= 0 { |  | ||||||
| 				// Multiple tagged fields at the same level: conflict.
 |  | ||||||
| 				// Return no field.
 |  | ||||||
| 				return field{}, false |  | ||||||
| 			} |  | ||||||
| 			tagged = i |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if tagged >= 0 { |  | ||||||
| 		return fields[tagged], true |  | ||||||
| 	} |  | ||||||
| 	// All remaining fields have the same length. If there's more than one,
 |  | ||||||
| 	// we have a conflict (two fields named "X" at the same level) and we
 |  | ||||||
| 	// return no field.
 |  | ||||||
| 	if len(fields) > 1 { |  | ||||||
| 		return field{}, false |  | ||||||
| 	} |  | ||||||
| 	return fields[0], true |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var fieldCache struct { |  | ||||||
| 	sync.RWMutex |  | ||||||
| 	m map[reflect.Type][]field |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
 |  | ||||||
| func cachedTypeFields(t reflect.Type) []field { |  | ||||||
| 	fieldCache.RLock() |  | ||||||
| 	f := fieldCache.m[t] |  | ||||||
| 	fieldCache.RUnlock() |  | ||||||
| 	if f != nil { |  | ||||||
| 		return f |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Compute fields without lock.
 |  | ||||||
| 	// Might duplicate effort but won't hold other computations back.
 |  | ||||||
| 	f = typeFields(t) |  | ||||||
| 	if f == nil { |  | ||||||
| 		f = []field{} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fieldCache.Lock() |  | ||||||
| 	if fieldCache.m == nil { |  | ||||||
| 		fieldCache.m = map[reflect.Type][]field{} |  | ||||||
| 	} |  | ||||||
| 	fieldCache.m[t] = f |  | ||||||
| 	fieldCache.Unlock() |  | ||||||
| 	return f |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func isValidTag(s string) bool { |  | ||||||
| 	if s == "" { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	for _, c := range s { |  | ||||||
| 		switch { |  | ||||||
| 		case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): |  | ||||||
| 			// Backslash and quote chars are reserved, but
 |  | ||||||
| 			// otherwise any punctuation chars are allowed
 |  | ||||||
| 			// in a tag name.
 |  | ||||||
| 		default: |  | ||||||
| 			if !unicode.IsLetter(c) && !unicode.IsDigit(c) { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const ( |  | ||||||
| 	caseMask     = ^byte(0x20) // Mask to ignore case in ASCII.
 |  | ||||||
| 	kelvin       = '\u212a' |  | ||||||
| 	smallLongEss = '\u017f' |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // foldFunc returns one of four different case folding equivalence
 |  | ||||||
| // functions, from most general (and slow) to fastest:
 |  | ||||||
| //
 |  | ||||||
| // 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
 |  | ||||||
| // 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
 |  | ||||||
| // 3) asciiEqualFold, no special, but includes non-letters (including _)
 |  | ||||||
| // 4) simpleLetterEqualFold, no specials, no non-letters.
 |  | ||||||
| //
 |  | ||||||
| // The letters S and K are special because they map to 3 runes, not just 2:
 |  | ||||||
| //  * S maps to s and to U+017F 'ſ' Latin small letter long s
 |  | ||||||
| //  * k maps to K and to U+212A 'K' Kelvin sign
 |  | ||||||
| // See http://play.golang.org/p/tTxjOc0OGo
 |  | ||||||
| //
 |  | ||||||
| // The returned function is specialized for matching against s and
 |  | ||||||
| // should only be given s. It's not curried for performance reasons.
 |  | ||||||
| func foldFunc(s []byte) func(s, t []byte) bool { |  | ||||||
| 	nonLetter := false |  | ||||||
| 	special := false // special letter
 |  | ||||||
| 	for _, b := range s { |  | ||||||
| 		if b >= utf8.RuneSelf { |  | ||||||
| 			return bytes.EqualFold |  | ||||||
| 		} |  | ||||||
| 		upper := b & caseMask |  | ||||||
| 		if upper < 'A' || upper > 'Z' { |  | ||||||
| 			nonLetter = true |  | ||||||
| 		} else if upper == 'K' || upper == 'S' { |  | ||||||
| 			// See above for why these letters are special.
 |  | ||||||
| 			special = true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if special { |  | ||||||
| 		return equalFoldRight |  | ||||||
| 	} |  | ||||||
| 	if nonLetter { |  | ||||||
| 		return asciiEqualFold |  | ||||||
| 	} |  | ||||||
| 	return simpleLetterEqualFold |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // equalFoldRight is a specialization of bytes.EqualFold when s is
 |  | ||||||
| // known to be all ASCII (including punctuation), but contains an 's',
 |  | ||||||
| // 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
 |  | ||||||
| // See comments on foldFunc.
 |  | ||||||
| func equalFoldRight(s, t []byte) bool { |  | ||||||
| 	for _, sb := range s { |  | ||||||
| 		if len(t) == 0 { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 		tb := t[0] |  | ||||||
| 		if tb < utf8.RuneSelf { |  | ||||||
| 			if sb != tb { |  | ||||||
| 				sbUpper := sb & caseMask |  | ||||||
| 				if 'A' <= sbUpper && sbUpper <= 'Z' { |  | ||||||
| 					if sbUpper != tb&caseMask { |  | ||||||
| 						return false |  | ||||||
| 					} |  | ||||||
| 				} else { |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			t = t[1:] |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		// sb is ASCII and t is not. t must be either kelvin
 |  | ||||||
| 		// sign or long s; sb must be s, S, k, or K.
 |  | ||||||
| 		tr, size := utf8.DecodeRune(t) |  | ||||||
| 		switch sb { |  | ||||||
| 		case 's', 'S': |  | ||||||
| 			if tr != smallLongEss { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 		case 'k', 'K': |  | ||||||
| 			if tr != kelvin { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 		default: |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 		t = t[size:] |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 	if len(t) > 0 { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // asciiEqualFold is a specialization of bytes.EqualFold for use when
 |  | ||||||
| // s is all ASCII (but may contain non-letters) and contains no
 |  | ||||||
| // special-folding letters.
 |  | ||||||
| // See comments on foldFunc.
 |  | ||||||
| func asciiEqualFold(s, t []byte) bool { |  | ||||||
| 	if len(s) != len(t) { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	for i, sb := range s { |  | ||||||
| 		tb := t[i] |  | ||||||
| 		if sb == tb { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { |  | ||||||
| 			if sb&caseMask != tb&caseMask { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // simpleLetterEqualFold is a specialization of bytes.EqualFold for
 |  | ||||||
| // use when s is all ASCII letters (no underscores, etc) and also
 |  | ||||||
| // doesn't contain 'k', 'K', 's', or 'S'.
 |  | ||||||
| // See comments on foldFunc.
 |  | ||||||
| func simpleLetterEqualFold(s, t []byte) bool { |  | ||||||
| 	if len(s) != len(t) { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	for i, b := range s { |  | ||||||
| 		if b&caseMask != t[i]&caseMask { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // tagOptions is the string following a comma in a struct field's "json"
 |  | ||||||
| // tag, or the empty string. It does not include the leading comma.
 |  | ||||||
| type tagOptions string |  | ||||||
| 
 |  | ||||||
| // parseTag splits a struct field's json tag into its name and
 |  | ||||||
| // comma-separated options.
 |  | ||||||
| func parseTag(tag string) (string, tagOptions) { |  | ||||||
| 	if idx := strings.Index(tag, ","); idx != -1 { |  | ||||||
| 		return tag[:idx], tagOptions(tag[idx+1:]) |  | ||||||
| 	} |  | ||||||
| 	return tag, tagOptions("") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Contains reports whether a comma-separated list of options
 |  | ||||||
| // contains a particular substr flag. substr must be surrounded by a
 |  | ||||||
| // string boundary or commas.
 |  | ||||||
| func (o tagOptions) Contains(optionName string) bool { |  | ||||||
| 	if len(o) == 0 { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	s := string(o) |  | ||||||
| 	for s != "" { |  | ||||||
| 		var next string |  | ||||||
| 		i := strings.Index(s, ",") |  | ||||||
| 		if i >= 0 { |  | ||||||
| 			s, next = s[:i], s[i+1:] |  | ||||||
| 		} |  | ||||||
| 		if s == optionName { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 		s = next |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  | @ -1,277 +0,0 @@ | ||||||
| package yaml |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"reflect" |  | ||||||
| 	"strconv" |  | ||||||
| 
 |  | ||||||
| 	"gopkg.in/yaml.v2" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // 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) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error marshaling into JSON: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	y, err := JSONToYAML(j) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error converting JSON to YAML: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return y, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Converts YAML to JSON then uses JSON to unmarshal into an object.
 |  | ||||||
| func Unmarshal(y []byte, o interface{}) error { |  | ||||||
| 	vo := reflect.ValueOf(o) |  | ||||||
| 	j, err := yamlToJSON(y, &vo) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error converting YAML to JSON: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = json.Unmarshal(j, o) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error unmarshaling JSON: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Convert JSON to YAML.
 |  | ||||||
| func JSONToYAML(j []byte) ([]byte, error) { |  | ||||||
| 	// Convert the JSON to an object.
 |  | ||||||
| 	var jsonObj interface{} |  | ||||||
| 	// We are using yaml.Unmarshal here (instead of json.Unmarshal) because the
 |  | ||||||
| 	// Go JSON library doesn't try to pick the right number type (int, float,
 |  | ||||||
| 	// etc.) when unmarshalling to interface{}, it just picks float64
 |  | ||||||
| 	// universally. go-yaml does go through the effort of picking the right
 |  | ||||||
| 	// number type, so we can preserve number type throughout this process.
 |  | ||||||
| 	err := yaml.Unmarshal(j, &jsonObj) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Marshal this object into YAML.
 |  | ||||||
| 	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.
 |  | ||||||
| //
 |  | ||||||
| // 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
 |  | ||||||
| //   in JSON. (int and float keys are converted to strings.)
 |  | ||||||
| // * Binary data in YAML with the !!binary tag is not supported. If you want to
 |  | ||||||
| //   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.
 |  | ||||||
| func YAMLToJSON(y []byte) ([]byte, error) { |  | ||||||
| 	return yamlToJSON(y, nil) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) { |  | ||||||
| 	// Convert the YAML to an object.
 |  | ||||||
| 	var yamlObj interface{} |  | ||||||
| 	err := yaml.Unmarshal(y, &yamlObj) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// YAML objects are not completely compatible with JSON objects (e.g. you
 |  | ||||||
| 	// can have non-string keys in YAML). So, convert the YAML-compatible object
 |  | ||||||
| 	// to a JSON-compatible object, failing with an error if irrecoverable
 |  | ||||||
| 	// incompatibilties happen along the way.
 |  | ||||||
| 	jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Convert this object to JSON and return the data.
 |  | ||||||
| 	return json.Marshal(jsonObj) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) { |  | ||||||
| 	var err error |  | ||||||
| 
 |  | ||||||
| 	// Resolve jsonTarget to a concrete value (i.e. not a pointer or an
 |  | ||||||
| 	// interface). We pass decodingNull as false because we're not actually
 |  | ||||||
| 	// decoding into the value, we're just checking if the ultimate target is a
 |  | ||||||
| 	// string.
 |  | ||||||
| 	if jsonTarget != nil { |  | ||||||
| 		ju, tu, pv := indirect(*jsonTarget, false) |  | ||||||
| 		// We have a JSON or Text Umarshaler at this level, so we can't be trying
 |  | ||||||
| 		// to decode into a string.
 |  | ||||||
| 		if ju != nil || tu != nil { |  | ||||||
| 			jsonTarget = nil |  | ||||||
| 		} else { |  | ||||||
| 			jsonTarget = &pv |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// If yamlObj is a number or a boolean, check if jsonTarget is a string -
 |  | ||||||
| 	// if so, coerce.  Else return normal.
 |  | ||||||
| 	// If yamlObj is a map or array, find the field that each key is
 |  | ||||||
| 	// unmarshaling to, and when you recurse pass the reflect.Value for that
 |  | ||||||
| 	// field back into this function.
 |  | ||||||
| 	switch typedYAMLObj := yamlObj.(type) { |  | ||||||
| 	case map[interface{}]interface{}: |  | ||||||
| 		// JSON does not support arbitrary keys in a map, so we must convert
 |  | ||||||
| 		// these keys to strings.
 |  | ||||||
| 		//
 |  | ||||||
| 		// From my reading of go-yaml v2 (specifically the resolve function),
 |  | ||||||
| 		// keys can only have the types string, int, int64, float64, binary
 |  | ||||||
| 		// (unsupported), or null (unsupported).
 |  | ||||||
| 		strMap := make(map[string]interface{}) |  | ||||||
| 		for k, v := range typedYAMLObj { |  | ||||||
| 			// Resolve the key to a string first.
 |  | ||||||
| 			var keyString string |  | ||||||
| 			switch typedKey := k.(type) { |  | ||||||
| 			case string: |  | ||||||
| 				keyString = typedKey |  | ||||||
| 			case int: |  | ||||||
| 				keyString = strconv.Itoa(typedKey) |  | ||||||
| 			case int64: |  | ||||||
| 				// go-yaml will only return an int64 as a key if the system
 |  | ||||||
| 				// architecture is 32-bit and the key's value is between 32-bit
 |  | ||||||
| 				// and 64-bit. Otherwise the key type will simply be int.
 |  | ||||||
| 				keyString = strconv.FormatInt(typedKey, 10) |  | ||||||
| 			case float64: |  | ||||||
| 				// Stolen from go-yaml to use the same conversion to string as
 |  | ||||||
| 				// the go-yaml library uses to convert float to string when
 |  | ||||||
| 				// Marshaling.
 |  | ||||||
| 				s := strconv.FormatFloat(typedKey, 'g', -1, 32) |  | ||||||
| 				switch s { |  | ||||||
| 				case "+Inf": |  | ||||||
| 					s = ".inf" |  | ||||||
| 				case "-Inf": |  | ||||||
| 					s = "-.inf" |  | ||||||
| 				case "NaN": |  | ||||||
| 					s = ".nan" |  | ||||||
| 				} |  | ||||||
| 				keyString = s |  | ||||||
| 			case bool: |  | ||||||
| 				if typedKey { |  | ||||||
| 					keyString = "true" |  | ||||||
| 				} else { |  | ||||||
| 					keyString = "false" |  | ||||||
| 				} |  | ||||||
| 			default: |  | ||||||
| 				return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v", |  | ||||||
| 					reflect.TypeOf(k), k, v) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// jsonTarget should be a struct or a map. If it's a struct, find
 |  | ||||||
| 			// the field it's going to map to and pass its reflect.Value. If
 |  | ||||||
| 			// it's a map, find the element type of the map and pass the
 |  | ||||||
| 			// reflect.Value created from that type. If it's neither, just pass
 |  | ||||||
| 			// nil - JSON conversion will error for us if it's a real issue.
 |  | ||||||
| 			if jsonTarget != nil { |  | ||||||
| 				t := *jsonTarget |  | ||||||
| 				if t.Kind() == reflect.Struct { |  | ||||||
| 					keyBytes := []byte(keyString) |  | ||||||
| 					// Find the field that the JSON library would use.
 |  | ||||||
| 					var f *field |  | ||||||
| 					fields := cachedTypeFields(t.Type()) |  | ||||||
| 					for i := range fields { |  | ||||||
| 						ff := &fields[i] |  | ||||||
| 						if bytes.Equal(ff.nameBytes, keyBytes) { |  | ||||||
| 							f = ff |  | ||||||
| 							break |  | ||||||
| 						} |  | ||||||
| 						// Do case-insensitive comparison.
 |  | ||||||
| 						if f == nil && ff.equalFold(ff.nameBytes, keyBytes) { |  | ||||||
| 							f = ff |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					if f != nil { |  | ||||||
| 						// Find the reflect.Value of the most preferential
 |  | ||||||
| 						// struct field.
 |  | ||||||
| 						jtf := t.Field(f.index[0]) |  | ||||||
| 						strMap[keyString], err = convertToJSONableObject(v, &jtf) |  | ||||||
| 						if err != nil { |  | ||||||
| 							return nil, err |  | ||||||
| 						} |  | ||||||
| 						continue |  | ||||||
| 					} |  | ||||||
| 				} else if t.Kind() == reflect.Map { |  | ||||||
| 					// Create a zero value of the map's element type to use as
 |  | ||||||
| 					// the JSON target.
 |  | ||||||
| 					jtv := reflect.Zero(t.Type().Elem()) |  | ||||||
| 					strMap[keyString], err = convertToJSONableObject(v, &jtv) |  | ||||||
| 					if err != nil { |  | ||||||
| 						return nil, err |  | ||||||
| 					} |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			strMap[keyString], err = convertToJSONableObject(v, nil) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return strMap, nil |  | ||||||
| 	case []interface{}: |  | ||||||
| 		// We need to recurse into arrays in case there are any
 |  | ||||||
| 		// map[interface{}]interface{}'s inside and to convert any
 |  | ||||||
| 		// numbers to strings.
 |  | ||||||
| 
 |  | ||||||
| 		// If jsonTarget is a slice (which it really should be), find the
 |  | ||||||
| 		// thing it's going to map to. If it's not a slice, just pass nil
 |  | ||||||
| 		// - JSON conversion will error for us if it's a real issue.
 |  | ||||||
| 		var jsonSliceElemValue *reflect.Value |  | ||||||
| 		if jsonTarget != nil { |  | ||||||
| 			t := *jsonTarget |  | ||||||
| 			if t.Kind() == reflect.Slice { |  | ||||||
| 				// By default slices point to nil, but we need a reflect.Value
 |  | ||||||
| 				// pointing to a value of the slice type, so we create one here.
 |  | ||||||
| 				ev := reflect.Indirect(reflect.New(t.Type().Elem())) |  | ||||||
| 				jsonSliceElemValue = &ev |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Make and use a new array.
 |  | ||||||
| 		arr := make([]interface{}, len(typedYAMLObj)) |  | ||||||
| 		for i, v := range typedYAMLObj { |  | ||||||
| 			arr[i], err = convertToJSONableObject(v, jsonSliceElemValue) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return arr, nil |  | ||||||
| 	default: |  | ||||||
| 		// If the target type is a string and the YAML type is a number,
 |  | ||||||
| 		// convert the YAML type to a string.
 |  | ||||||
| 		if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String { |  | ||||||
| 			// Based on my reading of go-yaml, it may return int, int64,
 |  | ||||||
| 			// float64, or uint64.
 |  | ||||||
| 			var s string |  | ||||||
| 			switch typedVal := typedYAMLObj.(type) { |  | ||||||
| 			case int: |  | ||||||
| 				s = strconv.FormatInt(int64(typedVal), 10) |  | ||||||
| 			case int64: |  | ||||||
| 				s = strconv.FormatInt(typedVal, 10) |  | ||||||
| 			case float64: |  | ||||||
| 				s = strconv.FormatFloat(typedVal, 'g', -1, 32) |  | ||||||
| 			case uint64: |  | ||||||
| 				s = strconv.FormatUint(typedVal, 10) |  | ||||||
| 			case bool: |  | ||||||
| 				if typedVal { |  | ||||||
| 					s = "true" |  | ||||||
| 				} else { |  | ||||||
| 					s = "false" |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			if len(s) > 0 { |  | ||||||
| 				yamlObj = interface{}(s) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return yamlObj, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
|  | @ -438,9 +438,6 @@ github.com/fsnotify/fsnotify | ||||||
| # github.com/fsouza/go-dockerclient v1.9.6 | # github.com/fsouza/go-dockerclient v1.9.6 | ||||||
| ## explicit; go 1.19 | ## explicit; go 1.19 | ||||||
| github.com/fsouza/go-dockerclient | github.com/fsouza/go-dockerclient | ||||||
| # github.com/ghodss/yaml v1.0.0 |  | ||||||
| ## explicit |  | ||||||
| github.com/ghodss/yaml |  | ||||||
| # github.com/go-jose/go-jose/v3 v3.0.0 | # github.com/go-jose/go-jose/v3 v3.0.0 | ||||||
| ## explicit; go 1.12 | ## explicit; go 1.12 | ||||||
| github.com/go-jose/go-jose/v3 | github.com/go-jose/go-jose/v3 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue