diff --git a/cli/command/manifest/annotate.go b/cli/command/manifest/annotate.go index a94fb57e2ae6..0fa3e629fa42 100644 --- a/cli/command/manifest/annotate.go +++ b/cli/command/manifest/annotate.go @@ -77,8 +77,8 @@ func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error { imageManifest.Platform.Variant = opts.variant } - if !isValidOSArch(imageManifest.Platform.OS, imageManifest.Platform.Architecture) { - return errors.Errorf("manifest entry for image has unsupported os/arch combination: %s/%s", opts.os, opts.arch) + if err := validateOSArch(imageManifest.Platform.OS, imageManifest.Platform.Architecture); err != nil { + return err } return manifestStore.Save(targetRef, imgRef, imageManifest) } diff --git a/cli/command/manifest/push.go b/cli/command/manifest/push.go index 0d752371c5b9..5de927b1cd50 100644 --- a/cli/command/manifest/push.go +++ b/cli/command/manifest/push.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -14,13 +15,16 @@ import ( "github.com/docker/distribution/manifest/schema2" "github.com/docker/distribution/reference" "github.com/docker/docker/registry" + "github.com/pkg/errors" "github.com/spf13/cobra" + yaml "gopkg.in/yaml.v2" ) type pushOpts struct { insecure bool purge bool + file bool target string } @@ -42,32 +46,48 @@ type pushRequest struct { insecure bool } +type yamlManifestList struct { + Image string + Manifests []yamlManifest +} + +type yamlManifest struct { + Image string + Platform manifestlist.PlatformSpec +} + func newPushListCommand(dockerCli command.Cli) *cobra.Command { opts := pushOpts{} cmd := &cobra.Command{ Use: "push [OPTIONS] MANIFEST_LIST", - Short: "Push a manifest list to a repository", + Short: "Push a manifest list to a repository, either after a create, or from a file", Args: cli.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { opts.target = args[0] return runPush(dockerCli, opts) }, } - flags := cmd.Flags() - flags.BoolVarP(&opts.purge, "purge", "p", false, "Remove the local manifest list after push") - flags.BoolVar(&opts.insecure, "insecure", false, "Allow push to an insecure registry") + flags.BoolVarP(&opts.purge, "purge", "p", false, "remove the local manifests after push") + flags.BoolVar(&opts.insecure, "insecure", false, "allow push to an insecure registry") + flags.BoolVar(&opts.file, "file", false, "use a file containing the yaml representation of manifest list") return cmd } func runPush(dockerCli command.Cli, opts pushOpts) error { + if opts.file { + return pushListFromYaml(dockerCli, opts.target, opts.insecure) + } + + return pushListFromStore(dockerCli, opts) +} +func pushListFromStore(dockerCli command.Cli, opts pushOpts) error { targetRef, err := normalizeReference(opts.target) if err != nil { return err } - manifests, err := dockerCli.ManifestStore().GetList(targetRef) if err != nil { return err @@ -271,3 +291,68 @@ func mountBlobs(ctx context.Context, client registryclient.RegistryClient, ref r } return nil } + +func pushListFromYaml(dockerCli command.Cli, file string, insecure bool) error { + yamlInput, err := getYamlManifestList(file) + if err != nil { + return err + } + if len(yamlInput.Manifests) == 0 { + return errors.Errorf("no manifests specified in file input") + } + + targetRef, err := normalizeReference(yamlInput.Image) + if err != nil { + return err + } + + ctx := context.Background() + var manifests []types.ImageManifest + for _, manifest := range yamlInput.Manifests { + imageRef, err := normalizeReference(manifest.Image) + if err != nil { + return err + } + im, err := dockerCli.RegistryClient(insecure).GetManifest(ctx, imageRef) + if err != nil { + return err + } + addYamlAnnotations(&im, manifest) + if err := validateOSArch(im.Platform.OS, im.Platform.Architecture); err != nil { + return err + } + manifests = append(manifests, im) + } + + pushRequest, err := buildPushRequest(manifests, targetRef, insecure) + if err != nil { + return err + } + return pushList(ctx, dockerCli, pushRequest) +} + +func addYamlAnnotations(manifest *types.ImageManifest, ym yamlManifest) { + + if ym.Platform.Variant != "" { + manifest.Platform.Variant = ym.Platform.Variant + } + if ym.Platform.OS != "" { + manifest.Platform.OS = ym.Platform.OS + } + if ym.Platform.Architecture != "" { + manifest.Platform.Architecture = ym.Platform.Architecture + } + if len(ym.Platform.OSFeatures) != 0 { + manifest.Platform.OSFeatures = ym.Platform.OSFeatures + } +} + +func getYamlManifestList(yamlFile string) (yamlManifestList, error) { + var yamlInput yamlManifestList + + yamlBuf, err := ioutil.ReadFile(yamlFile) + if err != nil { + return yamlManifestList{}, err + } + return yamlInput, yaml.UnmarshalStrict(yamlBuf, &yamlInput) +} diff --git a/cli/command/manifest/push_test.go b/cli/command/manifest/push_test.go index a09069606b63..fc45bcbf9dd0 100644 --- a/cli/command/manifest/push_test.go +++ b/cli/command/manifest/push_test.go @@ -15,10 +15,10 @@ import ( func newFakeRegistryClient() *fakeRegistryClient { return &fakeRegistryClient{ getManifestFunc: func(_ context.Context, _ reference.Named) (manifesttypes.ImageManifest, error) { - return manifesttypes.ImageManifest{}, errors.New("") + return manifesttypes.ImageManifest{}, errors.New("getManifestFunc not implemented") }, getManifestListFunc: func(_ context.Context, _ reference.Named) ([]manifesttypes.ImageManifest, error) { - return nil, errors.Errorf("") + return nil, errors.Errorf("getManifestListFunc not implemented") }, } } @@ -67,3 +67,60 @@ func TestManifestPush(t *testing.T) { err = cmd.Execute() assert.NilError(t, err) } + +func TestPushFromYaml(t *testing.T) { + cli := test.NewFakeCli(nil) + cli.SetRegistryClient(&fakeRegistryClient{ + getManifestFunc: func(_ context.Context, ref reference.Named) (manifesttypes.ImageManifest, error) { + return fullImageManifest(t, ref), nil + }, + }) + + cmd := newPushListCommand(cli) + cmd.Flags().Set("file", "true") + cmd.SetArgs([]string{"testdata/test-push.yaml"}) + assert.NilError(t, cmd.Execute()) +} + +func TestManifestPushYamlErrors(t *testing.T) { + testCases := []struct { + flags map[string]string + args []string + expectedError string + }{ + { + flags: map[string]string{"file": "true"}, + args: []string{"testdata/test-push-fail.yaml"}, + expectedError: "manifest entry for image has unsupported os/arch combination: linux/nope", + }, + { + flags: map[string]string{"file": "true"}, + args: []string{"testdata/test-push-empty.yaml"}, + expectedError: "no manifests specified in file input", + }, + { + args: []string{"testdata/test-push-empty.yaml"}, + expectedError: "No such manifest: docker.io/testdata/test-push-empty.yaml:latest", + }, + } + + store, sCleanup := newTempManifestStore(t) + defer sCleanup() + for _, tc := range testCases { + cli := test.NewFakeCli(nil) + cli.SetRegistryClient(&fakeRegistryClient{ + getManifestFunc: func(_ context.Context, ref reference.Named) (manifesttypes.ImageManifest, error) { + return fullImageManifest(t, ref), nil + }, + }) + + cli.SetManifestStore(store) + cmd := newPushListCommand(cli) + for k, v := range tc.flags { + cmd.Flags().Set(k, v) + } + cmd.SetArgs(tc.args) + cmd.SetOutput(ioutil.Discard) + assert.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} diff --git a/cli/command/manifest/testdata/test-push-empty.yaml b/cli/command/manifest/testdata/test-push-empty.yaml new file mode 100644 index 000000000000..0e9986a1c930 --- /dev/null +++ b/cli/command/manifest/testdata/test-push-empty.yaml @@ -0,0 +1,2 @@ +image: test/hello-world:latest +manifests: diff --git a/cli/command/manifest/testdata/test-push-fail.yaml b/cli/command/manifest/testdata/test-push-fail.yaml new file mode 100644 index 000000000000..4669f36bbd8c --- /dev/null +++ b/cli/command/manifest/testdata/test-push-fail.yaml @@ -0,0 +1,6 @@ +image: test/hello-world:latest +manifests: + - + image: test/hello-world-ppc64le:latest + platform: + architecture: nope diff --git a/cli/command/manifest/testdata/test-push.yaml b/cli/command/manifest/testdata/test-push.yaml new file mode 100644 index 000000000000..3715f246b8f4 --- /dev/null +++ b/cli/command/manifest/testdata/test-push.yaml @@ -0,0 +1,29 @@ +image: test/hello-world:latest +manifests: + - + image: test/hello-world-ppc64le:latest + platform: + architecture: ppc64le + - + image: test/hello-world-amd64:latest + platform: + architecture: amd64 + os: linux + - + image: test/hello-world-s390x:latest + platform: + architecture: s390x + os: linux + osversion: 1.1 + variant: xyz + osfeatures: [a,b,c] + - + image: test/hello-world-armv5:latest + platform: + - + image: test/hello-world:armhf + platform: + architecture: arm + os: linux + variant: abc + diff --git a/cli/command/manifest/util.go b/cli/command/manifest/util.go index 8d4bd3036456..ec32f44050fc 100644 --- a/cli/command/manifest/util.go +++ b/cli/command/manifest/util.go @@ -2,6 +2,7 @@ package manifest import ( "context" + "fmt" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/manifest/store" @@ -14,6 +15,18 @@ type osArch struct { arch string } +type invalidOSArchErr struct { + osArch +} + +func (e *invalidOSArchErr) Error() string { + return fmt.Sprintf("manifest entry for image has unsupported os/arch combination: %s/%s", e.os, e.arch) +} + +func newInvalidOSArchErr(os1 string, arch1 string) *invalidOSArchErr { + return &invalidOSArchErr{osArch{os: os1, arch: arch1}} +} + // Remove any unsupported os/arch combo // list of valid os/arch values (see "Optional Environment Variables" section // of https://golang.org/doc/install/source @@ -48,10 +61,13 @@ var validOSArches = map[osArch]bool{ {os: "windows", arch: "amd64"}: true, } -func isValidOSArch(os string, arch string) bool { +func validateOSArch(os string, arch string) error { // check for existence of this combo _, ok := validOSArches[osArch{os, arch}] - return ok + if !ok { + return newInvalidOSArchErr(os, arch) + } + return nil } func normalizeReference(ref string) (reference.Named, error) { diff --git a/vendor.conf b/vendor.conf index 0c44656e5eeb..d758e9ea4a08 100755 --- a/vendor.conf +++ b/vendor.conf @@ -82,7 +82,7 @@ golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 google.golang.org/grpc v1.3.0 gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 -gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6 +gopkg.in/yaml.v2 d670f9405373e636a5a2765eea47fac0c9bc91a4 k8s.io/api kubernetes-1.8.2 k8s.io/apimachinery kubernetes-1.8.2 k8s.io/client-go kubernetes-1.8.2 diff --git a/vendor/gopkg.in/yaml.v2/LICENSE b/vendor/gopkg.in/yaml.v2/LICENSE index 866d74a7ad79..8dada3edaf50 100644 --- a/vendor/gopkg.in/yaml.v2/LICENSE +++ b/vendor/gopkg.in/yaml.v2/LICENSE @@ -1,13 +1,201 @@ -Copyright 2011-2016 Canonical Ltd. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - http://www.apache.org/licenses/LICENSE-2.0 + 1. Definitions. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/gopkg.in/yaml.v2/README.md b/vendor/gopkg.in/yaml.v2/README.md index 1884de6a7d7f..2ed3314c7393 100644 --- a/vendor/gopkg.in/yaml.v2/README.md +++ b/vendor/gopkg.in/yaml.v2/README.md @@ -48,6 +48,8 @@ The yaml package is licensed under the Apache License 2.0. Please see the LICENS Example ------- +Some more examples can be found in the "examples" folder. + ```Go package main @@ -65,6 +67,8 @@ b: d: [3, 4] ` +// Note: struct fields must be public in order for unmarshal to +// correctly populate the data. type T struct { A string B struct { diff --git a/vendor/gopkg.in/yaml.v2/decode.go b/vendor/gopkg.in/yaml.v2/decode.go index b13ab9f0796b..e85eb2e3fe1b 100644 --- a/vendor/gopkg.in/yaml.v2/decode.go +++ b/vendor/gopkg.in/yaml.v2/decode.go @@ -120,7 +120,6 @@ func (p *parser) parse() *node { default: panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ))) } - panic("unreachable") } func (p *parser) node(kind int) *node { @@ -191,6 +190,7 @@ type decoder struct { aliases map[string]bool mapType reflect.Type terrors []string + strict bool } var ( @@ -200,8 +200,8 @@ var ( ifaceType = defaultMapType.Elem() ) -func newDecoder() *decoder { - d := &decoder{mapType: defaultMapType} +func newDecoder(strict bool) *decoder { + d := &decoder{mapType: defaultMapType, strict: strict} d.aliases = make(map[string]bool) return d } @@ -251,7 +251,7 @@ func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { // // If n holds a null value, prepare returns before doing anything. func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { - if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "" && n.implicit) { + if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { return out, false, false } again := true @@ -640,6 +640,8 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { value := reflect.New(elemType).Elem() d.unmarshal(n.children[i+1], value) inlineMap.SetMapIndex(name, value) + } else if d.strict { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", ni.line+1, name.String(), out.Type())) } } return true diff --git a/vendor/gopkg.in/yaml.v2/emitterc.go b/vendor/gopkg.in/yaml.v2/emitterc.go index 2befd553ed02..dcaf502f0ebd 100644 --- a/vendor/gopkg.in/yaml.v2/emitterc.go +++ b/vendor/gopkg.in/yaml.v2/emitterc.go @@ -666,7 +666,6 @@ func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, return yaml_emitter_set_emitter_error(emitter, "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS") } - return false } // Expect ALIAS. @@ -995,10 +994,10 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { break_space = false space_break = false - preceeded_by_whitespace = false - followed_by_whitespace = false - previous_space = false - previous_break = false + preceded_by_whitespace = false + followed_by_whitespace = false + previous_space = false + previous_break = false ) emitter.scalar_data.value = value @@ -1017,7 +1016,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { flow_indicators = true } - preceeded_by_whitespace = true + preceded_by_whitespace = true for i, w := 0, 0; i < len(value); i += w { w = width(value[i]) followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) @@ -1048,7 +1047,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { block_indicators = true } case '#': - if preceeded_by_whitespace { + if preceded_by_whitespace { flow_indicators = true block_indicators = true } @@ -1089,7 +1088,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { } // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. - preceeded_by_whitespace = is_blankz(value, i) + preceded_by_whitespace = is_blankz(value, i) } emitter.scalar_data.multiline = line_breaks diff --git a/vendor/gopkg.in/yaml.v2/parserc.go b/vendor/gopkg.in/yaml.v2/parserc.go index 0a7037ad1b2a..81d05dfe573f 100644 --- a/vendor/gopkg.in/yaml.v2/parserc.go +++ b/vendor/gopkg.in/yaml.v2/parserc.go @@ -166,7 +166,6 @@ func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool default: panic("invalid parser state") } - return false } // Parse the production: diff --git a/vendor/gopkg.in/yaml.v2/scannerc.go b/vendor/gopkg.in/yaml.v2/scannerc.go index 25808000f28f..074484455827 100644 --- a/vendor/gopkg.in/yaml.v2/scannerc.go +++ b/vendor/gopkg.in/yaml.v2/scannerc.go @@ -9,7 +9,7 @@ import ( // ************ // // The following notes assume that you are familiar with the YAML specification -// (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in +// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in // some cases we are less restrictive that it requires. // // The process of transforming a YAML stream into a sequence of events is @@ -611,7 +611,7 @@ func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, co if directive { context = "while parsing a %TAG directive" } - return yaml_parser_set_scanner_error(parser, context, context_mark, "did not find URI escaped octet") + return yaml_parser_set_scanner_error(parser, context, context_mark, problem) } func trace(args ...interface{}) func() { @@ -1944,7 +1944,7 @@ func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_ma } else { // It's either the '!' tag or not really a tag handle. If it's a %TAG // directive, it's an error. If it's a tag token, it must be a part of URI. - if directive && !(s[0] == '!' && s[1] == 0) { + if directive && string(s) != "!" { yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "did not find expected '!'") return false @@ -1959,6 +1959,7 @@ func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_ma func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { //size_t length = head ? strlen((char *)head) : 0 var s []byte + hasTag := len(head) > 0 // Copy the head if needed. // @@ -2000,10 +2001,10 @@ func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } + hasTag = true } - // Check if the tag is non-empty. - if len(s) == 0 { + if !hasTag { yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "did not find expected tag URI") return false diff --git a/vendor/gopkg.in/yaml.v2/yaml.go b/vendor/gopkg.in/yaml.v2/yaml.go index 36d6b883a6c0..5e3c2daee435 100644 --- a/vendor/gopkg.in/yaml.v2/yaml.go +++ b/vendor/gopkg.in/yaml.v2/yaml.go @@ -77,8 +77,19 @@ type Marshaler interface { // supported tag options. // func Unmarshal(in []byte, out interface{}) (err error) { + return unmarshal(in, out, false) +} + +// UnmarshalStrict is like Unmarshal except that any fields that are found +// in the data that do not have corresponding struct members will result in +// an error. +func UnmarshalStrict(in []byte, out interface{}) (err error) { + return unmarshal(in, out, true) +} + +func unmarshal(in []byte, out interface{}, strict bool) (err error) { defer handleErr(&err) - d := newDecoder() + d := newDecoder(strict) p := newParser(in) defer p.destroy() node := p.parse() @@ -129,7 +140,7 @@ func Unmarshal(in []byte, out interface{}) (err error) { // For example: // // type T struct { -// F int "a,omitempty" +// F int `yaml:"a,omitempty"` // B int // } // yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" diff --git a/vendor/gopkg.in/yaml.v2/yamlh.go b/vendor/gopkg.in/yaml.v2/yamlh.go index d60a6b6b0035..3caeca0491b5 100644 --- a/vendor/gopkg.in/yaml.v2/yamlh.go +++ b/vendor/gopkg.in/yaml.v2/yamlh.go @@ -508,7 +508,7 @@ type yaml_parser_t struct { problem string // Error description. - // The byte about which the problem occured. + // The byte about which the problem occurred. problem_offset int problem_value int problem_mark yaml_mark_t