diff --git a/deploy/chart/crds/0000_50_olm_00-installplans.crd.yaml b/deploy/chart/crds/0000_50_olm_00-installplans.crd.yaml index 616f51ba0d2..6aeaaa7bd74 100644 --- a/deploy/chart/crds/0000_50_olm_00-installplans.crd.yaml +++ b/deploy/chart/crds/0000_50_olm_00-installplans.crd.yaml @@ -222,6 +222,8 @@ spec: - resource - status properties: + optional: + type: boolean resolving: type: string resource: diff --git a/go.mod b/go.mod index 2dbacfe18e5..ccd0da8b5de 100644 --- a/go.mod +++ b/go.mod @@ -67,3 +67,4 @@ replace ( // informers until it can be resolved upstream: sigs.k8s.io/controller-runtime v0.10.0 => github.com/timflannagan/controller-runtime v0.10.1-0.20211210161403-6756a4203e70 ) + diff --git a/pkg/controller/bundle/bundle_unpacker.go b/pkg/controller/bundle/bundle_unpacker.go index 18ebe609d23..a1e25d07150 100644 --- a/pkg/controller/bundle/bundle_unpacker.go +++ b/pkg/controller/bundle/bundle_unpacker.go @@ -47,8 +47,9 @@ const ( type BundleUnpackResult struct { *operatorsv1alpha1.BundleLookup - bundle *api.Bundle - name string + bundle *api.Bundle + filenames []string + name string } func (b *BundleUnpackResult) Bundle() *api.Bundle { @@ -59,6 +60,10 @@ func (b *BundleUnpackResult) Name() string { return b.name } +func (b *BundleUnpackResult) Filenames() []string { + return b.filenames +} + // SetCondition replaces the existing BundleLookupCondition of the same type, or adds it if it was not found. func (b *BundleUnpackResult) SetCondition(cond operatorsv1alpha1.BundleLookupCondition) operatorsv1alpha1.BundleLookupCondition { for i, existing := range b.Conditions { @@ -493,7 +498,7 @@ func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup, return } - result.bundle, err = c.loader.Load(cm) + result.bundle, result.filenames, err = c.loader.Load(cm) if err != nil { return } diff --git a/pkg/controller/operators/catalog/manifests.go b/pkg/controller/operators/catalog/manifests.go index 9e8f12af511..653d42aec5a 100644 --- a/pkg/controller/operators/catalog/manifests.go +++ b/pkg/controller/operators/catalog/manifests.go @@ -82,7 +82,7 @@ func (r *manifestResolver) unpackedStepsForBundle(bundleName string, ref *Unpack return nil, errorwrap.Wrapf(err, "error finding unpacked bundle configmap for ref %v", *ref) } loader := configmap.NewBundleLoader() - bundle, err := loader.Load(cm) + bundle, _, err := loader.Load(cm) if err != nil { return nil, errorwrap.Wrapf(err, "error loading unpacked bundle configmap for ref %v", *ref) } diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 717f7bc05cf..5183fb88cc2 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -1364,11 +1364,12 @@ func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.In // if packed condition is missing, bundle has already been unpacked into steps, continue if res.GetCondition(resolver.BundleLookupConditionPacked).Status == corev1.ConditionUnknown { + o.logger.Debug("Bundle already unpacked") continue } // Ensure that bundle can be applied by the current version of OLM by converting to steps - steps, err := resolver.NewStepsFromBundle(res.Bundle(), out.GetNamespace(), res.Replaces, res.CatalogSourceRef.Name, res.CatalogSourceRef.Namespace) + steps, err := resolver.NewQualifiedStepsFromBundle(res.Bundle(), res.Filenames(), out.GetNamespace(), res.Replaces, res.CatalogSourceRef.Name, res.CatalogSourceRef.Namespace, o.logger) if err != nil { errs = append(errs, fmt.Errorf("failed to turn bundle into steps: %v", err)) unpacked = false @@ -1562,7 +1563,6 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) { syncError = fmt.Errorf("bundle unpacking failed: %v", err) return } - if !reflect.DeepEqual(plan.Status, out.Status) { logger.Warnf("status not equal, updating...") if _, err := o.client.OperatorsV1alpha1().InstallPlans(out.GetNamespace()).UpdateStatus(context.TODO(), out, metav1.UpdateOptions{}); err != nil { @@ -1603,7 +1603,6 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) { return } } - outInstallPlan, syncError := transitionInstallPlanState(logger.Logger, o, *plan, o.now(), o.installPlanTimeout) if syncError != nil { @@ -1955,7 +1954,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } switch step.Status { - case v1alpha1.StepStatusPresent, v1alpha1.StepStatusCreated, v1alpha1.StepStatusWaitingForAPI: + case v1alpha1.StepStatusPresent, v1alpha1.StepStatusCreated, v1alpha1.StepStatusWaitingForAPI, v1alpha1.StepStatusNotCreated: return nil case v1alpha1.StepStatusUnknown, v1alpha1.StepStatusNotPresent: manifest, err := r.ManifestForStep(step) @@ -2224,6 +2223,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { if !isSupported(step.Resource.Kind) { // Not a supported resource plan.Status.Plan[i].Status = v1alpha1.StepStatusUnsupportedResource + o.logger.WithError(err).Debug("resource kind not supported") return v1alpha1.ErrInvalidInstallPlan } @@ -2238,7 +2238,14 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { gvk := unstructuredObject.GroupVersionKind() r, err := o.apiresourceFromGVK(gvk) if err != nil { - return err + if step.Optional { + // Special handling of the unavailability of the API for optional resources: no error + o.logger.WithFields(logrus.Fields{"InstallPlan": plan.Name, "kind": step.Resource.Kind, "name": step.Resource.Name}).Warnf("Optional manifest could not be created. Optional capabilities of the operator may not be available.") + plan.Status.Plan[i].Status = v1alpha1.StepStatusNotCreated + return nil + } else { + return err + } } // Create the GVR @@ -2284,7 +2291,26 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { // Ensure Unstructured Object status, err := ensurer.EnsureUnstructuredObject(resourceInterface, unstructuredObject) if err != nil { - return err + if step.Optional { + switch k8serrors.ReasonForError(err) { + case + metav1.StatusReasonUnauthorized, + metav1.StatusReasonForbidden, + metav1.StatusReasonNotFound, + metav1.StatusReasonInvalid, + metav1.StatusReasonNotAcceptable, + metav1.StatusReasonUnsupportedMediaType, + metav1.StatusReasonConflict: + o.logger.WithFields(logrus.Fields{"kind": step.Resource.Kind, "name": step.Resource.Name}).WithError(err).Warnf("Optional manifest could not be created. Optional capabilities of the operator may not be available.") + status = v1alpha1.StepStatusNotCreated + err = nil + default: + o.logger.WithFields(logrus.Fields{"kind": step.Resource.Kind, "name": step.Resource.Name}).WithError(err).Warnf("Optional manifest could not be created, possibly due to a recoverable error, retrying") + return err + } + } else { + return err + } } plan.Status.Plan[i].Status = status @@ -2309,7 +2335,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { // Loop over one final time to check and see if everything is good. for _, step := range plan.Status.Plan { switch step.Status { - case v1alpha1.StepStatusCreated, v1alpha1.StepStatusPresent: + case v1alpha1.StepStatusCreated, v1alpha1.StepStatusPresent, v1alpha1.StepStatusNotCreated: default: return nil } diff --git a/pkg/controller/operators/catalog/operator_test.go b/pkg/controller/operators/catalog/operator_test.go index 0bc9056018d..0d6f943f798 100644 --- a/pkg/controller/operators/catalog/operator_test.go +++ b/pkg/controller/operators/catalog/operator_test.go @@ -604,6 +604,118 @@ func TestExecutePlan(t *testing.T) { }, }, }, + { + testName: "OptionalManifestWithCRD", + in: withSteps(installPlan("p", namespace, v1alpha1.InstallPlanPhaseInstalling, "csv"), + []*v1alpha1.Step{ + { + Resolving: "csv", + Resource: v1alpha1.StepResource{ + CatalogSource: "catalog", + CatalogSourceNamespace: namespace, + Group: "operators.coreos.com", + Version: "v1alpha1", + Kind: "ClusterServiceVersion", + Name: "csv", + Manifest: toManifest(t, csv("csv", namespace, nil, nil)), + }, + Status: v1alpha1.StepStatusUnknown, + }, + { + Resolving: "csv", + Optional: true, + Resource: v1alpha1.StepResource{ + CatalogSource: "catalog", + CatalogSourceNamespace: namespace, + Group: "monitoring.coreos.com", + Version: "v1", + Kind: "PrometheusRule", + Name: "rule", + Manifest: toManifest(t, decodeFile(t, "./testdata/prometheusrule.cr.yaml", &unstructured.Unstructured{})), + }, + Status: v1alpha1.StepStatusUnknown, + }, + }, + ), + extObjs: []runtime.Object{decodeFile(t, "./testdata/prometheusrule.crd.yaml", &apiextensionsv1beta1.CustomResourceDefinition{})}, + want: []runtime.Object{ + csv("csv", namespace, nil, nil), + modify(t, decodeFile(t, "./testdata/prometheusrule.cr.yaml", &unstructured.Unstructured{}), + withNamespace(namespace), + withOwner(csv("csv", namespace, nil, nil)), + ), + }, + err: nil, + }, + { + testName: "NotOptionalManifestWithoutCRD", + in: withSteps(installPlan("p", namespace, v1alpha1.InstallPlanPhaseInstalling, "csv"), + []*v1alpha1.Step{ + { + Resolving: "csv", + Resource: v1alpha1.StepResource{ + CatalogSource: "catalog", + CatalogSourceNamespace: namespace, + Group: "operators.coreos.com", + Version: "v1alpha1", + Kind: "ClusterServiceVersion", + Name: "csv", + Manifest: toManifest(t, csv("csv", namespace, nil, nil)), + }, + Status: v1alpha1.StepStatusUnknown, + }, + { + Resolving: "csv", + Resource: v1alpha1.StepResource{ + CatalogSource: "catalog", + CatalogSourceNamespace: namespace, + Group: "monitoring.coreos.com", + Version: "v1", + Kind: "PrometheusRule", + Name: "rule", + Manifest: toManifest(t, decodeFile(t, "./testdata/prometheusrule.cr.yaml", &unstructured.Unstructured{})), + }, + Status: v1alpha1.StepStatusUnknown, + }, + }, + ), + err: fmt.Errorf("GroupVersion \"monitoring.coreos.com/v1\" not found"), + }, + { + testName: "OptionalManifestWithoutCRD", + in: withSteps(installPlan("p", namespace, v1alpha1.InstallPlanPhaseInstalling, "csv"), + []*v1alpha1.Step{ + { + Resolving: "csv", + Resource: v1alpha1.StepResource{ + CatalogSource: "catalog", + CatalogSourceNamespace: namespace, + Group: "operators.coreos.com", + Version: "v1alpha1", + Kind: "ClusterServiceVersion", + Name: "csv", + Manifest: toManifest(t, csv("csv", namespace, nil, nil)), + }, + Status: v1alpha1.StepStatusUnknown, + }, + { + Resolving: "csv", + Optional: true, + Resource: v1alpha1.StepResource{ + CatalogSource: "catalog", + CatalogSourceNamespace: namespace, + Group: "monitoring.coreos.com", + Version: "v1", + Kind: "PrometheusRule", + Name: "rule", + Manifest: toManifest(t, decodeFile(t, "./testdata/prometheusrule.cr.yaml", &unstructured.Unstructured{})), + }, + Status: v1alpha1.StepStatusUnknown, + }, + }, + ), + err: nil, + }, } for _, tt := range tests { diff --git a/pkg/controller/registry/resolver/steps.go b/pkg/controller/registry/resolver/steps.go index 7860c7108ab..33ba3a96487 100644 --- a/pkg/controller/registry/resolver/steps.go +++ b/pkg/controller/registry/resolver/steps.go @@ -6,6 +6,8 @@ import ( "fmt" "strings" + "github.com/sirupsen/logrus" + "github.com/operator-framework/operator-registry/pkg/api" extScheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,8 +25,9 @@ import ( ) const ( - secretKind = "Secret" - BundleSecretKind = "BundleSecret" + secretKind = "Secret" + BundleSecretKind = "BundleSecret" + optionalManifestsProp = "olm.manifests.optional" ) var ( @@ -132,11 +135,11 @@ func NewStepResourceFromBundle(bundle *api.Bundle, namespace, replaces, catalogS annos[projection.PropertiesAnnotationKey] = anno csv.SetAnnotations(annos) - step, err := NewStepResourceFromObject(csv, catalogSourceName, catalogSourceNamespace) + csvStep, err := NewStepResourceFromObject(csv, catalogSourceName, catalogSourceNamespace) if err != nil { return nil, err } - steps := []v1alpha1.StepResource{step} + steps := []v1alpha1.StepResource{} for _, object := range bundle.Object { dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(object), 10) @@ -146,6 +149,8 @@ func NewStepResourceFromBundle(bundle *api.Bundle, namespace, replaces, catalogS } if unst.GetObjectKind().GroupVersionKind().Kind == v1alpha1.ClusterServiceVersionKind { + // Adding the CSV step only here, although it was computed earlier, to keep the filename and step orders aligned. + steps = append(steps, csvStep) continue } @@ -182,6 +187,58 @@ func NewStepsFromBundle(bundle *api.Bundle, namespace, replaces, catalogSourceNa return steps, nil } +// NewQualifiedStepsFromBundle returns the steps to be populated into the InstallPlan for a bundle +// Qualified means that steps may have been flaged as optional. +func NewQualifiedStepsFromBundle(bundle *api.Bundle, filenames []string, namespace, replaces, catalogSourceName, catalogSourceNamespace string, + logger *logrus.Logger) ([]*v1alpha1.Step, error) { + + bundleSteps, err := NewStepResourceFromBundle(bundle, namespace, replaces, catalogSourceName, catalogSourceNamespace) + if err != nil { + return nil, err + } + var steps []*v1alpha1.Step + isOptFunc := isOptional(bundle.Properties) + // bundleSteps and filenames are in the same order + for i, s := range bundleSteps { + logger.Infof("bundle step %s", s.String()) + // serviceAccounts defined in CSV may be added to bundle steps without matching files in manifest dir. + // they are not optional + // this logic is fragile but the following constraints lead to it: + // - the optionality of a step is not being carried directly by the matching manifest + // - the existing bundle.Object is not carrying any metadata and only the content of the manifest + // alternatives: + // - having the optional property defined as an annotation directly in the manifest (rejected by maintainers) + // - having bundle.Object being a Map indexed by filenames, which would break the API + var optional bool + if i >= len(filenames) { + logger.Debug("manifest from CSV, not optional") + optional = false + } else { + logger.Debugf("filename %s", filenames[i]) + optional = isOptFunc(filenames[i]) + logger.Debugf("optional %t", optional) + } + // CSV should be positioned first + if s.Kind == v1alpha1.ClusterServiceVersionKind { + steps = append([]*v1alpha1.Step{&v1alpha1.Step{ + Resolving: bundle.CsvName, + Resource: s, + Optional: optional, + Status: v1alpha1.StepStatusUnknown, + }}, steps...) + } else { + steps = append(steps, &v1alpha1.Step{ + Resolving: bundle.CsvName, + Resource: s, + Optional: optional, + Status: v1alpha1.StepStatusUnknown, + }) + } + } + + return steps, nil +} + // NewServiceAccountStepResources returns a list of step resources required to satisfy the RBAC requirements of the given CSV's InstallStrategy func NewServiceAccountStepResources(csv *v1alpha1.ClusterServiceVersion, catalogSourceName, catalogSourceNamespace string) ([]v1alpha1.StepResource, error) { var rbacSteps []v1alpha1.StepResource @@ -230,3 +287,39 @@ func NewServiceAccountStepResources(csv *v1alpha1.ClusterServiceVersion, catalog } return rbacSteps, nil } + +type optionalFiles struct { + Files []string `json:"files"` +} + +// isOptional returns a func giving whether a file is in the list of optional manifests +// or false if any issue occurs. +func isOptional(properties []*api.Property) func(filename string) bool { + if optionals, ok := getPropertyValue(properties, optionalManifestsProp); ok { + var optFiles optionalFiles + if err := json.Unmarshal([]byte(optionals), &optFiles); err == nil { + return func(filename string) bool { + for _, oFilename := range optFiles.Files { + if oFilename == filename { + return true + } + } + return false + } + } + } + return func(filename string) bool { + return false + } +} + +// getPropertyValue returns the value of a specific property from an array of Property +// and true if the value is found, false otherwise +func getPropertyValue(properties []*api.Property, propertyType string) (string, bool) { + for _, property := range properties { + if property.Type == propertyType { + return property.Value, true + } + } + return "", false +} diff --git a/pkg/controller/registry/resolver/steps_test.go b/pkg/controller/registry/resolver/steps_test.go new file mode 100644 index 00000000000..d7db026aa18 --- /dev/null +++ b/pkg/controller/registry/resolver/steps_test.go @@ -0,0 +1,50 @@ +package resolver + +import ( + "fmt" + "testing" + + "github.com/operator-framework/operator-registry/pkg/api" +) + +const ( + optionalFilename = "optional.yaml" + mandatoryFilename = "mandatory.yaml" +) + +func TestIsOptional(t *testing.T) { + + type isOptionalTests struct { + filenames []string + results []bool + } + properties := []*api.Property{ + { + Type: "olm.gvk", + Value: "{\"group\":\"kibana.k8s.elastic.co\",\"kind\":\"Kibana\",\"version\":\"v1alpha1\"}", + }, + { + Type: "olm.manifests.optional", + // Value: fmt.Sprintf("{\"files\":[\"random1.yaml\",\"%s\",\"random2.yaml\"]}", optionalFilename), + Value: fmt.Sprintf(`{"files":["%s"]}`, optionalFilename), + }, + { + Type: "olm.gvk", + Value: "{\"group\":\"apm.k8s.elastic.co\",\"kind\":\"ApmServer\",\"version\":\"v1beta1\"}", + }, + } + + ioTests := isOptionalTests{ + filenames: []string{optionalFilename, mandatoryFilename}, + results: []bool{true, false}, + } + + isOptFunc := isOptional(properties) + for i, filename := range ioTests.filenames { + result := isOptFunc(filename) + if result != ioTests.results[i] { + t.Errorf("filename: %s, got %t; want %t", filename, result, ioTests.results[i]) + } + } + +} diff --git a/pkg/fakes/fake_registry_store.go b/pkg/fakes/fake_registry_store.go index 5894a426aed..e6f94f78dcb 100644 --- a/pkg/fakes/fake_registry_store.go +++ b/pkg/fakes/fake_registry_store.go @@ -463,6 +463,11 @@ func (fake *FakeQuery) GetBundle(arg1 context.Context, arg2 string, arg3 string, return fakeReturns.result1, fakeReturns.result2 } +// temporary +func (fake *FakeQuery) SendBundles(ctx context.Context, stream registry.BundleSender) error { + return nil +} + func (fake *FakeQuery) GetBundleCallCount() int { fake.getBundleMutex.RLock() defer fake.getBundleMutex.RUnlock() diff --git a/vendor/github.com/containerd/containerd/archive/tar_unix.go b/vendor/github.com/containerd/containerd/archive/tar_unix.go index 6e89d2fdbc9..c22e79bf2be 100644 --- a/vendor/github.com/containerd/containerd/archive/tar_unix.go +++ b/vendor/github.com/containerd/containerd/archive/tar_unix.go @@ -113,7 +113,7 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { if hdr.Typeflag == tar.TypeLink { - if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { + if fi, err := os.Lstat(path); err == nil && (fi.Mode()&os.ModeSymlink == 0) { if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) { return err } diff --git a/vendor/github.com/containerd/containerd/content/local/store.go b/vendor/github.com/containerd/containerd/content/local/store.go index 87056814ab8..15f7b25b06f 100644 --- a/vendor/github.com/containerd/containerd/content/local/store.go +++ b/vendor/github.com/containerd/containerd/content/local/store.go @@ -502,7 +502,7 @@ func (s *store) resumeStatus(ref string, total int64, digester digest.Digester) if ref != status.Ref { // NOTE(stevvooe): This is fairly catastrophic. Either we have some // layout corruption or a hash collision for the ref key. - return status, errors.Wrapf(err, "ref key does not match: %v != %v", ref, status.Ref) + return status, errors.Errorf("ref key does not match: %v != %v", ref, status.Ref) } if total > 0 && status.Total > 0 && total != status.Total { diff --git a/vendor/github.com/containerd/containerd/metadata/containers.go b/vendor/github.com/containerd/containerd/metadata/containers.go index 09b0d203d29..4b82f7d0c4e 100644 --- a/vendor/github.com/containerd/containerd/metadata/containers.go +++ b/vendor/github.com/containerd/containerd/metadata/containers.go @@ -290,7 +290,7 @@ func validateContainer(container *containers.Container) error { // image has no validation for k, v := range container.Labels { - if err := labels.Validate(k, v); err == nil { + if err := labels.Validate(k, v); err != nil { return errors.Wrapf(err, "containers.Labels") } } diff --git a/vendor/github.com/containerd/containerd/metadata/content.go b/vendor/github.com/containerd/containerd/metadata/content.go index 268a9b1b79c..649571ef6c3 100644 --- a/vendor/github.com/containerd/containerd/metadata/content.go +++ b/vendor/github.com/containerd/containerd/metadata/content.go @@ -551,13 +551,13 @@ func (nw *namespacedWriter) createAndCopy(ctx context.Context, desc ocispec.Desc if desc.Size > 0 { ra, err := nw.provider.ReaderAt(ctx, nw.desc) if err != nil { + w.Close() return err } defer ra.Close() if err := content.CopyReaderAt(w, ra, desc.Size); err != nil { - nw.w.Close() - nw.w = nil + w.Close() return err } } @@ -708,7 +708,7 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err func validateInfo(info *content.Info) error { for k, v := range info.Labels { - if err := labels.Validate(k, v); err == nil { + if err := labels.Validate(k, v); err != nil { return errors.Wrapf(err, "info.Labels") } } diff --git a/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go b/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go index 001423a0d1c..2f459b70c85 100644 --- a/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go +++ b/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go @@ -31,6 +31,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/version" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/net/context/ctxhttp" @@ -356,6 +357,9 @@ func (ah *authHandler) fetchTokenWithOAuth(ctx context.Context, to tokenOptions) req.Header[k] = append(req.Header[k], v...) } } + if len(req.Header.Get("User-Agent")) == 0 { + req.Header.Set("User-Agent", "containerd/"+version.Version) + } resp, err := ctxhttp.Do(ctx, ah.client, req) if err != nil { @@ -408,6 +412,9 @@ func (ah *authHandler) fetchToken(ctx context.Context, to tokenOptions) (string, req.Header[k] = append(req.Header[k], v...) } } + if len(req.Header.Get("User-Agent")) == 0 { + req.Header.Set("User-Agent", "containerd/"+version.Version) + } reqParams := req.URL.Query() diff --git a/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go b/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go index cd0168be5b9..022c456a9f6 100644 --- a/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go +++ b/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go @@ -148,7 +148,7 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R }) } -func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (io.ReadCloser, error) { +func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, retErr error) { req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", ")) if offset > 0 { @@ -162,13 +162,17 @@ func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, if err != nil { return nil, err } + defer func() { + if retErr != nil { + resp.Body.Close() + } + }() if resp.StatusCode > 299 { // TODO(stevvooe): When doing a offset specific request, we should // really distinguish between a 206 and a 200. In the case of 200, we // can discard the bytes, hiding the seek behavior from the // implementation. - defer resp.Body.Close() if resp.StatusCode == http.StatusNotFound { return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String()) diff --git a/vendor/github.com/containerd/containerd/remotes/docker/pusher.go b/vendor/github.com/containerd/containerd/remotes/docker/pusher.go index d95e0c8b0e9..d46396b7fb1 100644 --- a/vendor/github.com/containerd/containerd/remotes/docker/pusher.go +++ b/vendor/github.com/containerd/containerd/remotes/docker/pusher.go @@ -109,12 +109,15 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten // TODO: Set updated time? }, }) + resp.Body.Close() return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest) } } else if resp.StatusCode != http.StatusNotFound { + resp.Body.Close() // TODO: log error return nil, errors.Errorf("unexpected response: %s", resp.Status) } + resp.Body.Close() } if isManifest { @@ -155,6 +158,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten return nil, err } } + defer resp.Body.Close() switch resp.StatusCode { case http.StatusOK, http.StatusAccepted, http.StatusNoContent: @@ -338,6 +342,7 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di if resp == nil { return errors.New("no response") } + defer resp.Body.Close() // 201 is specified return status, some registries return // 200, 202 or 204. diff --git a/vendor/github.com/containerd/containerd/remotes/docker/resolver.go b/vendor/github.com/containerd/containerd/remotes/docker/resolver.go index f9582188b84..19515a373fb 100644 --- a/vendor/github.com/containerd/containerd/remotes/docker/resolver.go +++ b/vendor/github.com/containerd/containerd/remotes/docker/resolver.go @@ -295,12 +295,14 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp if lastErr == nil { lastErr = err } + log.G(ctx).WithError(err).Info("trying next host") continue // try another host } resp.Body.Close() // don't care about body contents. if resp.StatusCode > 299 { if resp.StatusCode == http.StatusNotFound { + log.G(ctx).Info("trying next host - response was http.StatusNotFound") continue } return "", ocispec.Descriptor{}, errors.Errorf("unexpected status code %v: %v", u, resp.Status) @@ -546,7 +548,21 @@ func (r *request) do(ctx context.Context) (*http.Response, error) { if err := r.authorize(ctx, req); err != nil { return nil, errors.Wrap(err, "failed to authorize") } - resp, err := ctxhttp.Do(ctx, r.host.Client, req) + + var client = &http.Client{} + if r.host.Client != nil { + *client = *r.host.Client + } + if client.CheckRedirect == nil { + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + return errors.Wrap(r.authorize(ctx, req), "failed to authorize redirect") + } + } + + resp, err := ctxhttp.Do(ctx, client, req) if err != nil { return nil, errors.Wrap(err, "failed to do request") } diff --git a/vendor/github.com/containerd/containerd/version/version.go b/vendor/github.com/containerd/containerd/version/version.go index 5394680f0e1..77f581f7cfe 100644 --- a/vendor/github.com/containerd/containerd/version/version.go +++ b/vendor/github.com/containerd/containerd/version/version.go @@ -23,7 +23,7 @@ var ( Package = "github.com/containerd/containerd" // Version holds the complete version number. Filled in at linking time. - Version = "1.4.4+unknown" + Version = "1.4.11+unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. diff --git a/vendor/github.com/go-openapi/spec/.editorconfig b/vendor/github.com/go-openapi/spec/.editorconfig deleted file mode 100644 index 3152da69a5d..00000000000 --- a/vendor/github.com/go-openapi/spec/.editorconfig +++ /dev/null @@ -1,26 +0,0 @@ -# top-most EditorConfig file -root = true - -# Unix-style newlines with a newline ending every file -[*] -end_of_line = lf -insert_final_newline = true -indent_style = space -indent_size = 2 -trim_trailing_whitespace = true - -# Set default charset -[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] -charset = utf-8 - -# Tab indentation (no size specified) -[*.go] -indent_style = tab - -[*.md] -trim_trailing_whitespace = false - -# Matches the exact files either package.json or .travis.yml -[{package.json,.travis.yml}] -indent_style = space -indent_size = 2 diff --git a/vendor/github.com/go-openapi/spec/.gitignore b/vendor/github.com/go-openapi/spec/.gitignore deleted file mode 100644 index dd91ed6a04e..00000000000 --- a/vendor/github.com/go-openapi/spec/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -secrets.yml -coverage.out diff --git a/vendor/github.com/go-openapi/spec/.golangci.yml b/vendor/github.com/go-openapi/spec/.golangci.yml deleted file mode 100644 index 4e17ed4979b..00000000000 --- a/vendor/github.com/go-openapi/spec/.golangci.yml +++ /dev/null @@ -1,28 +0,0 @@ -linters-settings: - govet: - check-shadowing: true - golint: - min-confidence: 0 - gocyclo: - min-complexity: 45 - maligned: - suggest-new: true - dupl: - threshold: 200 - goconst: - min-len: 2 - min-occurrences: 2 - -linters: - enable-all: true - disable: - - maligned - - unparam - - lll - - gochecknoinits - - gochecknoglobals - - funlen - - godox - - gocognit - - whitespace - - wsl diff --git a/vendor/github.com/go-openapi/spec/.travis.yml b/vendor/github.com/go-openapi/spec/.travis.yml deleted file mode 100644 index aa26d8763aa..00000000000 --- a/vendor/github.com/go-openapi/spec/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -after_success: -- bash <(curl -s https://codecov.io/bash) -go: -- 1.11.x -- 1.12.x -install: -- GO111MODULE=off go get -u gotest.tools/gotestsum -env: -- GO111MODULE=on -language: go -notifications: - slack: - secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E= -script: -- gotestsum -f short-verbose -- -race -coverprofile=coverage.txt -covermode=atomic ./... diff --git a/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md deleted file mode 100644 index 9322b065e37..00000000000 --- a/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at ivan+abuse@flanders.co.nz. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/spec/LICENSE b/vendor/github.com/go-openapi/spec/LICENSE deleted file mode 100644 index d6456956733..00000000000 --- a/vendor/github.com/go-openapi/spec/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "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/github.com/go-openapi/spec/README.md b/vendor/github.com/go-openapi/spec/README.md deleted file mode 100644 index 6354742cbf6..00000000000 --- a/vendor/github.com/go-openapi/spec/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# OAI object model [![Build Status](https://travis-ci.org/go-openapi/spec.svg?branch=master)](https://travis-ci.org/go-openapi/spec) [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) - -[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) -[![GoDoc](https://godoc.org/github.com/go-openapi/spec?status.svg)](http://godoc.org/github.com/go-openapi/spec) -[![GolangCI](https://golangci.com/badges/github.com/go-openapi/spec.svg)](https://golangci.com) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/spec)](https://goreportcard.com/report/github.com/go-openapi/spec) - -The object model for OpenAPI specification documents. - -Currently supports Swagger 2.0. diff --git a/vendor/github.com/go-openapi/spec/bindata.go b/vendor/github.com/go-openapi/spec/bindata.go deleted file mode 100644 index 66b1f32635d..00000000000 --- a/vendor/github.com/go-openapi/spec/bindata.go +++ /dev/null @@ -1,297 +0,0 @@ -// Code generated by go-bindata. DO NOT EDIT. -// sources: -// schemas/jsonschema-draft-04.json (4.357kB) -// schemas/v2/schema.json (40.248kB) - -package spec - -import ( - "bytes" - "compress/gzip" - "crypto/sha256" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo - digest [sha256.Size]byte -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -func (fi bindataFileInfo) Name() string { - return fi.name -} -func (fi bindataFileInfo) Size() int64 { - return fi.size -} -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} -func (fi bindataFileInfo) IsDir() bool { - return false -} -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _jsonschemaDraft04Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x3d\x6f\xdb\x3c\x10\xde\xf3\x2b\x08\x26\x63\xf2\x2a\x2f\xd0\xc9\x5b\xd1\x2e\x01\x5a\x34\x43\x37\x23\x03\x6d\x9d\x6c\x06\x14\xa9\x50\x54\x60\xc3\xd0\x7f\x2f\x28\x4a\x14\x29\x91\x92\x2d\xa7\x8d\x97\x28\xbc\xaf\xe7\x8e\xf7\xc5\xd3\x0d\x42\x08\x61\x9a\xe2\x15\xc2\x7b\xa5\x8a\x55\x92\xbc\x96\x82\x3f\x94\xdb\x3d\xe4\xe4\x3f\x21\x77\x49\x2a\x49\xa6\x1e\x1e\xbf\x24\xe6\xec\x16\xdf\x1b\xa1\x3b\xf3\xff\x02\xc9\x14\xca\xad\xa4\x85\xa2\x82\x6b\xe9\x6f\x42\x02\x32\x2c\x28\x07\x45\x5a\x15\x3d\x77\x46\x39\xd5\xcc\x25\x5e\x21\x83\xb8\x21\x18\xb6\xaf\x52\x92\xa3\x47\x68\x88\xea\x58\x80\x56\x4e\x1a\xf2\xbd\x4f\xcc\x29\x7f\x52\x90\x6b\x7d\xff\x0f\x48\xb4\x3d\x3f\x21\x7c\x27\x21\xd3\x2a\x6e\x31\xaa\x2d\x53\xdd\xf3\xe3\x42\x94\x54\xd1\x77\x78\xe2\x0a\x76\x20\xe3\x20\x68\xcb\x30\x86\x41\xf3\x2a\xc7\x2b\xf4\x78\x8e\xfe\xef\x90\x91\x8a\xa9\xc7\xb1\x1d\xc2\xd8\x2f\x0d\x75\xed\xc1\x4e\x9c\xc8\x25\x43\xac\xa8\xbe\xd7\xcc\xa9\xd1\xa9\x21\xa0\x1a\xbd\x04\x61\x94\x34\x2f\x18\xfc\x3e\x16\x50\x8e\x4d\x03\x6f\x1c\x58\xdb\x48\x23\xbc\x11\x82\x01\xe1\xfa\xd3\x3a\x8e\x30\xaf\x18\x33\x7f\xf3\x8d\x39\x11\x9b\x57\xd8\x2a\xfd\x55\x2a\x49\xf9\x0e\xc7\xec\x37\xd4\x25\xf7\xec\x5c\x66\xc7\xd7\x99\xaa\xcf\x4f\x89\x8a\xd3\xb7\x0a\x3a\xaa\x92\x15\xf4\x30\x6f\x1c\xb0\xd6\x46\xe7\x98\x39\x2d\xa4\x28\x40\x2a\x3a\x88\x9e\x29\xba\x88\x37\x2d\xca\x60\x38\xfa\xba\x5b\x20\xac\xa8\x62\xb0\x4c\xd4\xaf\xda\x45\x0a\xba\x5c\x3b\xb9\xc7\x79\xc5\x14\x2d\x18\x34\x19\x1c\x51\xdb\x25\x4d\xb4\x7e\x06\x14\x38\x6c\x59\x55\xd2\x77\xf8\x69\x59\xfc\x7b\x73\xed\x93\x43\xcb\x32\x6d\x3c\x28\xdc\x1b\x9a\xd3\x62\xab\xc2\x27\xf7\x41\xc9\x08\x2b\x23\x08\xad\x13\x57\x21\x9c\xd3\x72\x0d\x42\x72\xf8\x01\x7c\xa7\xf6\x83\xce\x39\xd7\x82\x3c\x1f\x2f\xd6\x60\x1b\xa2\xdf\x35\x89\x52\x20\xe7\x73\x74\xe0\x66\x26\x64\x4e\xb4\x97\x58\xc2\x0e\x0e\xe1\x60\x92\x34\x6d\xa0\x10\xd6\xb5\x83\x61\x27\xe6\x47\xd3\x89\xbd\x63\xfd\x3b\x8d\x03\x3d\x6c\x42\x2d\x5b\x70\xee\xe8\xdf\x4b\xf4\x66\x4e\xe1\x01\x45\x17\x80\x74\xad\x4f\xc3\xf3\xae\xc6\x1d\xc6\xd7\xc2\xce\xc9\xe1\x29\x30\x86\x2f\x4a\xa6\x4b\x15\x84\x73\xc9\x6f\xfd\x7f\xa5\x6e\x9e\xbd\xf1\xb0\xd4\xdd\x45\x5a\xc2\x3e\x4b\x78\xab\xa8\x84\x74\x4a\x91\x3b\x92\x23\x05\xf2\x1c\x1e\x7b\xf3\x09\xf8\xcf\xab\x24\xb6\x60\xa2\xe8\x4c\x9f\x75\x77\xaa\x8c\xe6\x01\x45\x36\x86\xcf\xc3\x63\x3a\xea\xd4\x8d\x7e\x06\xac\x14\x0a\xe0\x29\xf0\xed\x07\x22\x1a\x65\xda\x44\xae\xa2\x73\x1a\xe6\x90\x69\xa2\x8c\x46\xb2\x2f\xde\x49\x38\x08\xed\xfe\xfd\x41\xaf\x9f\xa9\x55\xd7\xdd\x22\x8d\xfa\x45\x63\xc5\x0f\x80\xf3\xb4\x08\xd6\x79\x30\x9e\x93\xee\x59\xa6\xd0\x4b\xee\x22\xe3\x33\xc1\x3a\x27\x68\x36\x78\x7e\x87\x0a\x06\xd5\x2e\x20\xd3\xaf\x15\xfb\xd8\x3b\x73\x14\xbb\x92\xed\x05\x5d\x2e\x29\x38\x2c\x94\xe4\x42\x45\x5e\xd3\xb5\x7d\xdf\x47\xca\x38\xb4\x5c\xaf\xfb\x7d\xdd\x6d\xf4\xa1\x2d\x77\xdd\x2f\xce\x6d\xc4\x7b\x8b\x4e\x67\xa9\x6f\xfe\x04\x00\x00\xff\xff\xb1\xd1\x27\x78\x05\x11\x00\x00") - -func jsonschemaDraft04JsonBytes() ([]byte, error) { - return bindataRead( - _jsonschemaDraft04Json, - "jsonschema-draft-04.json", - ) -} - -func jsonschemaDraft04Json() (*asset, error) { - bytes, err := jsonschemaDraft04JsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "jsonschema-draft-04.json", size: 4357, mode: os.FileMode(0640), modTime: time.Unix(1568963823, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe1, 0x48, 0x9d, 0xb, 0x47, 0x55, 0xf0, 0x27, 0x93, 0x30, 0x25, 0x91, 0xd3, 0xfc, 0xb8, 0xf0, 0x7b, 0x68, 0x93, 0xa8, 0x2a, 0x94, 0xf2, 0x48, 0x95, 0xf8, 0xe4, 0xed, 0xf1, 0x1b, 0x82, 0xe2}} - return a, nil -} - -var _v2SchemaJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5d\x4f\x93\xdb\x36\xb2\xbf\xfb\x53\xa0\x14\x57\xd9\xae\xd8\x92\xe3\xf7\x2e\xcf\x97\xd4\xbc\xd8\x49\x66\x37\x5e\x4f\x79\x26\xbb\x87\x78\x5c\x05\x91\x2d\x09\x09\x09\x30\x00\x38\x33\x5a\xef\x7c\xf7\x2d\xf0\x9f\x08\x02\x20\x41\x8a\xd2\xc8\x0e\x0f\xa9\x78\x28\xa0\xd1\xdd\x68\x34\x7e\xdd\xf8\xf7\xf9\x11\x42\x33\x49\x64\x04\xb3\xd7\x68\x76\x86\xfe\x76\xf9\xfe\x1f\xe8\x32\xd8\x40\x8c\xd1\x8a\x71\x74\x79\x8b\xd7\x6b\xe0\xe8\xd5\xfc\x25\x3a\xbb\x38\x9f\xcf\x9e\xab\x0a\x24\x54\xa5\x37\x52\x26\xaf\x17\x0b\x91\x17\x99\x13\xb6\xb8\x79\xb5\x10\x59\xdd\xf9\xef\x82\xd1\x6f\xf2\xc2\x8f\xf3\x4f\xb5\x1a\xea\xc7\x17\x45\x41\xc6\xd7\x8b\x90\xe3\x95\x7c\xf1\xf2\x7f\x8b\xca\x45\x3d\xb9\x4d\x32\xa6\xd8\xf2\x77\x08\x64\xfe\x8d\xc3\x9f\x29\xe1\xa0\x9a\xff\xed\x11\x42\x08\xcd\x8a\xd6\xb3\x9f\x15\x67\x74\xc5\xca\x7f\x27\x58\x6e\xc4\xec\x11\x42\xd7\x59\x5d\x1c\x86\x44\x12\x46\x71\x74\xc1\x59\x02\x5c\x12\x10\xb3\xd7\x68\x85\x23\x01\x59\x81\x04\x4b\x09\x9c\x6a\xbf\x7e\xce\x49\x7d\xba\x7b\x51\xfd\xa1\x44\xe2\xb0\x52\xac\x7d\xb3\x08\x61\x45\x68\x46\x56\x2c\x6e\x80\x86\x8c\xbf\xbd\x93\x40\x05\x61\x74\x96\x95\xbe\x7f\x84\xd0\x7d\x4e\xde\x42\xb7\xe4\xbe\x46\xbb\x14\x5b\x48\x4e\xe8\xba\x90\x05\xa1\x19\xd0\x34\xae\xc4\xce\xbe\xbc\x9a\xbf\x9c\x15\x7f\x5d\x57\xc5\x42\x10\x01\x27\x89\xe2\x48\x51\xb9\xda\x40\xd5\x87\x37\xc0\x15\x5f\x88\xad\x90\xdc\x10\x81\x42\x16\xa4\x31\x50\x39\x2f\x38\xad\xab\xb0\x53\xd8\xac\x94\x56\x6f\xc3\x84\xf4\x11\xa4\x50\xb3\xfa\xe9\xd3\x6f\x9f\x3e\xdf\x2f\xd0\xeb\x8f\x1f\x3f\x7e\xbc\xfe\xf6\xe9\xf7\xaf\x5f\x7f\xfc\x18\x7e\xfb\xec\xfb\xc7\xb3\x36\x79\x54\x43\xe8\x29\xc5\x31\x20\xc6\x11\x49\x9e\xe5\x12\x41\x66\xa0\xe8\xed\x1d\x8e\x93\x08\x5e\xa3\x27\x3b\xc3\x7c\xa2\x73\xba\xc4\x02\x2e\xb0\xdc\xf4\xe5\x76\xd1\xca\x96\xa2\x8a\x94\xcd\x21\xc9\x6c\xec\x2c\x70\x42\x9e\x34\x74\x9d\x19\x7c\xcd\x20\x9c\xea\x2e\x0a\xfe\x42\x84\xd4\x29\x04\x8c\x8a\xb4\x41\xa2\xc1\xdc\x19\x8a\x88\x90\x4a\x49\xef\xce\xdf\xbd\x45\x4a\x52\x81\x70\x10\x40\x22\x21\x44\xcb\x6d\xc5\xec\x4e\x3c\x1c\x45\xef\x57\x9a\xb5\x7d\xae\xfe\xe5\xe4\x31\x86\x90\xe0\xab\x6d\x02\x3b\x2e\xcb\x11\x90\xd9\xa8\xc6\x77\xc2\x59\x98\x06\xfd\xf9\x2e\x78\x45\x01\xa6\xa8\xa0\x71\x5c\xbe\x33\xa7\xd2\xd9\x5f\x95\xef\xd9\xd5\xac\xfd\xdc\x5d\xbf\x5e\xb8\xd1\x3e\xc7\x31\x48\xe0\x5e\x4c\x14\x65\xdf\xb8\xa8\x71\x10\x09\xa3\xc2\xc7\x02\xcb\xa2\x4e\x5a\x02\x82\x94\x13\xb9\xf5\x30\xe6\xb2\xa4\xb5\xfe\x9b\x3e\x7a\xb2\x55\xd2\xa8\x4a\xbc\x16\xb6\x71\x8e\x39\xc7\xdb\x9d\xe1\x10\x09\x71\xbd\x9c\xb3\x41\x89\xd7\xa5\x89\xdc\x57\xb5\x53\x4a\xfe\x4c\xe1\xbc\xa0\x21\x79\x0a\x1a\x0f\x70\xa7\x5c\x08\x8e\xde\xb0\xc0\x43\x24\xad\x74\x63\x0e\xb1\xd9\x90\xe1\xb0\x2d\x13\xa7\x6d\x78\xfd\x04\x14\x38\x8e\x90\xaa\xce\x63\xac\x3e\x23\xbc\x64\xa9\xb4\xf8\x03\x63\xde\xcd\xbe\x16\x13\x4a\x55\xac\x82\x12\xc6\xac\xd4\x35\xf7\x22\xd4\x3a\xff\x22\x73\x0e\x6e\x51\xa0\x75\x1e\xae\x8f\xe8\x5d\xc7\x59\xe6\xe4\x9a\x18\x8d\xd6\x1c\x53\x84\x4d\xb7\x67\x28\x37\x09\x84\x69\x88\x12\x0e\x01\x11\x80\x32\xa2\xf5\xb9\xaa\xc6\xd9\x73\x53\xab\xfb\xb4\x2e\x20\xc6\x54\x92\xa0\x9a\xf3\x69\x1a\x2f\x81\x77\x37\xae\x53\x1a\xce\x40\xc4\xa8\x82\x1c\xb5\xef\xda\x24\x7d\xb9\x61\x69\x14\xa2\x25\xa0\x90\xac\x56\xc0\x81\x4a\xb4\xe2\x2c\xce\x4a\x64\x7a\x9a\x23\xf4\x13\x91\x3f\xa7\x4b\xf4\x63\x84\x6f\x18\x87\x10\xbd\xc3\xfc\x8f\x90\xdd\x52\x44\x04\xc2\x51\xc4\x6e\x21\x74\x48\x21\x81\xc7\xe2\xfd\xea\x12\xf8\x0d\x09\xf6\xe9\x47\x35\xaf\x67\xc4\x14\xf7\x22\x27\x97\xe1\xe2\x76\x2d\x06\x8c\x4a\x1c\x48\x3f\x73\x2d\x0b\x5b\x29\x45\x24\x00\x2a\x0c\x11\xec\x94\xca\xc2\xa6\xc1\x37\x21\x43\x83\x3b\x5f\x97\xf1\x43\x5e\x53\x73\x19\xa5\x36\xd8\x2d\x05\x2e\x34\x0b\xeb\x39\xfc\x1d\x63\x51\x01\xbd\x3d\xbb\x90\x84\x40\x25\x59\x6d\x09\x5d\xa3\x1c\x37\xe6\x5c\x16\x9a\x40\x09\x70\xc1\xe8\x82\xf1\x35\xa6\xe4\xdf\x99\x5c\x8e\x9e\x4d\x79\xb4\x27\x2f\xbf\x7e\xf8\x05\x25\x8c\x50\xa9\x98\x29\x90\x62\x60\xea\x75\xae\x13\xca\xbf\x2b\x1a\x29\x27\x76\xd6\x20\xc6\x64\x5f\xe6\x32\x1a\x08\x87\x21\x07\x21\xbc\xb4\xe4\xe0\x32\x67\xa6\xcd\xf3\x1e\xcd\xd9\x6b\xb6\x6f\x8e\x27\xa7\xed\xdb\xe7\xbc\xcc\x1a\x07\xce\x6f\x87\x33\xf0\xba\x51\x17\x22\x66\x78\x79\x8e\xce\xe5\x13\x81\x80\x06\x2c\xe5\x78\x0d\xa1\xb2\xb8\x54\xa8\x79\x09\xbd\xbf\x3c\x47\x01\x8b\x13\x2c\xc9\x32\xaa\xaa\x1d\xd5\xee\xab\x36\xbd\x6c\xfd\x54\x6c\xc8\x08\x01\x3c\xbd\xe7\x07\x88\xb0\x24\x37\x79\x90\x28\x4a\x1d\x10\x1a\x92\x1b\x12\xa6\x38\x42\x40\xc3\x4c\x43\x62\x8e\xae\x36\xb0\x45\x71\x2a\xa4\x9a\x23\x79\x59\xb1\xa8\xf2\xa4\x0c\x60\x9f\xcc\x8d\x40\xf5\x80\xca\xa8\x99\xc3\xa7\x85\x1f\x31\x25\xa9\x82\xc5\x6d\xbd\xd8\x36\x76\x7c\x02\x28\x97\xf6\x1d\x74\x3b\x11\x7e\x91\xae\x32\xf8\x6c\xf4\xe6\x7b\x9a\xa5\x1f\x62\xc6\x21\xcf\x9a\xe5\xed\x8b\x02\xf3\x2c\x33\x33\xdf\x00\xca\xc9\x09\xb4\x04\xf5\xa5\x08\xd7\xc3\x02\x18\x66\xf1\xab\x1e\x83\x37\x4c\xcd\x12\xc1\x1d\x50\xf6\xaa\xbd\xfe\xe2\x73\x48\x38\x08\xa0\x32\x9b\x18\x44\x86\x0b\x6a\xc1\xaa\x26\x96\x2d\x96\x3c\xa0\x54\x65\x73\xe3\x08\xb5\x8b\x99\xbd\x82\xbc\x9e\xc2\xe8\x53\x46\x83\x3f\x33\x54\x2b\x5b\xad\x92\x79\xd9\x8f\x5d\x93\x98\xf2\xe6\xc6\x1c\xe6\x9a\x9e\xfc\x43\x82\x31\x66\x8e\x53\x77\xfe\x90\xe7\xf3\xf6\xe9\x62\x23\x3f\x10\x93\x18\xae\x72\x1a\x9d\xf9\x48\xcb\xcc\x5a\x65\xc7\x4a\x04\xf0\xf3\xd5\xd5\x05\x8a\x41\x08\xbc\x86\x86\x43\x51\x6c\xe0\x46\x57\xf6\x44\x40\x0d\xfb\xff\xa2\xc3\x7c\x3d\x39\x84\xdc\x09\x22\x64\x4f\x12\xd9\xba\xaa\xf6\xe3\xbd\x56\xdd\x91\x25\x6a\x14\x9c\x89\x34\x8e\x31\xdf\xee\x15\x7e\x2f\x39\x81\x15\x2a\x28\x95\x66\x51\xf5\xfd\x83\xc5\xfe\x15\x07\xcf\xf7\x08\xee\x1d\x8e\xb6\xc5\x52\xcc\x8c\x5a\x93\x66\xc5\xd8\x79\x38\x46\xd6\xa7\x88\x37\xc9\x2e\xe3\xd2\xa5\x7b\x4b\x3a\xdc\xa1\xdc\x9e\x29\xf1\x8c\x8a\x99\x16\x47\x8d\xd4\x78\x8b\xf6\x1c\xe9\x71\x54\x1b\x69\xa8\x4a\x93\x37\xe5\xb2\x2c\x4f\x0c\x92\xab\xa0\x73\x32\x72\x59\xd3\xf0\x2d\x8d\xed\xca\x37\x16\x19\x9e\xdb\x1c\xab\x17\x49\xc3\x0f\x37\xdc\x88\xb1\xb4\xd4\x42\xcb\x58\x5e\x6a\x52\x0b\x15\x10\x0a\xb0\x04\xe7\xf8\x58\x32\x16\x01\xa6\xcd\x01\xb2\xc2\x69\x24\x35\x38\x6f\x30\x6a\xae\x1b\xb4\x71\xaa\xad\x1d\xa0\xd6\x20\x2d\x8b\x3c\xc6\x82\x62\x27\x34\x6d\x15\x84\x7b\x43\xb1\x35\x78\xa6\x24\x77\x28\xc1\x6e\xfc\xe9\x48\x74\xf4\x15\xe3\xe1\x84\x42\x88\x40\x7a\x26\x49\x3b\x48\xb1\xa4\x19\x8e\x0c\xa7\xb5\x01\x6c\x0c\x97\x61\x8a\xc2\x32\xd8\x8c\x44\x69\x24\xbf\x65\x1d\x74\xd6\xe5\x44\xef\xec\x48\x5e\xb7\x8a\xa3\x29\x8e\x41\x64\xce\x1f\x88\xdc\x00\x47\x4b\x40\x98\x6e\xd1\x0d\x8e\x48\x98\x63\x5c\x21\xb1\x4c\x05\x0a\x58\x98\xc5\x6d\x4f\x0a\x77\x53\x4f\x8b\xc4\x44\x1f\xb2\xdf\x8d\x3b\xea\x9f\xfe\xf6\xf2\xc5\xff\x5d\x7f\xfe\x9f\xfb\x67\x8f\xff\xf3\xe9\x69\xd1\xfe\xb3\xc7\xfd\x3c\xf8\x3f\x71\x94\x82\x23\xd1\x72\x00\xb7\x42\x99\x6c\xc0\x60\x7b\x0f\x79\xea\xa8\x53\x4b\x56\x31\xfa\x0b\x52\x9f\x96\xdb\xcd\x2f\xd7\x67\xcd\x04\x19\x85\xfe\xdb\x02\x9a\x59\x03\xad\x63\x3c\xea\xff\x2e\x18\xfd\x00\xd9\xe2\x56\x60\x59\x93\xb9\xb6\xb2\x3e\x3c\x2c\xab\x0f\xa7\xb2\x89\x43\xc7\xf6\xd5\xce\x2e\xad\xa6\xa9\xed\xa6\xc6\x5a\xb4\xa6\x67\xdf\x8c\x26\x7b\x50\x5a\x91\x08\x2e\x6d\xd4\x3a\xc1\x9d\xf2\xdb\xde\x1e\xb2\x2c\x6c\xa5\x64\xc9\x16\xb4\x90\xaa\x4a\xb7\x0c\xde\x13\xc3\x2a\x9a\x11\x9b\x7a\x1b\x3d\x95\x97\x37\x31\x6b\x69\x7e\x34\xc0\x67\x1f\x66\x19\x49\xef\xf1\x25\xf5\xac\x0e\xea\x0a\x28\x8d\x4d\x7e\xd9\x57\x4b\x49\xe5\xc6\xb3\x25\xfd\xe6\x57\x42\x25\xac\xcd\xcf\x36\x74\x8e\xca\x24\x47\xe7\x80\xa8\x92\x72\xbd\x3d\x84\x2d\x65\xe2\x82\x1a\x9c\xc4\x44\x92\x1b\x10\x79\x8a\xc4\x4a\x2f\x60\x51\x04\x81\xaa\xf0\xa3\x95\x27\xd7\x12\x7b\xa3\x96\x03\x45\x96\xc1\x8a\x07\xc9\xb2\xb0\x95\x52\x8c\xef\x48\x9c\xc6\x7e\x94\xca\xc2\x0e\x07\x12\x44\xa9\x20\x37\xf0\xae\x0f\x49\xa3\x96\x9d\x4b\x42\x7b\x70\x59\x14\xee\xe0\xb2\x0f\x49\xa3\x96\x4b\x97\xbf\x00\x5d\x4b\x4f\xfc\xbb\x2b\xee\x92\xb9\x17\xb5\xaa\xb8\x0b\x97\x17\x9b\x43\xfd\xd6\xc2\xb2\xc2\x2e\x29\xcf\xfd\x87\x4a\x55\xda\x25\x63\x1f\x5a\x65\x69\x2b\x2d\x3d\x67\xe9\x41\xae\x5e\xc1\x6e\x2b\xd4\xdb\x3e\xa8\xd3\x26\xd2\x48\x92\x24\xca\x61\x86\x8f\x8c\xbb\xf2\x8e\x91\xdf\x1f\x06\x19\x33\xf3\x03\x4d\xba\xcd\xe2\x2d\xfb\x69\xe9\x16\x15\x13\xd5\x56\x85\x4e\x3c\x5b\x8a\xbf\x25\x72\x83\xee\x5e\x20\x22\xf2\xc8\xaa\x7b\xdb\x8e\xe4\x29\x58\xca\x38\xb7\x3f\x2e\x59\xb8\xbd\xa8\x16\x16\xf7\xdb\x79\x51\x9f\x5a\xb4\x8d\x87\x3a\x6e\xbc\x3e\xc5\xb4\xcd\x58\xf9\xf5\x3c\xb9\x6f\x49\xaf\x57\xc1\xfa\x1c\x5d\x6d\x88\x8a\x8b\xd3\x28\xcc\xb7\xef\x10\x8a\x4a\x74\xa9\x4a\xa7\x62\xbf\x0d\x76\x23\x6f\x59\xd9\x31\xee\x40\x11\xfb\x28\xec\x8d\x22\x1c\x13\x5a\x64\x94\x23\x16\x60\xbb\xd2\x7c\xa0\x98\xb2\xe5\x6e\xbc\x54\x33\xe0\x3e\xb9\x52\x17\xdb\xb7\x1b\xc8\x12\x20\x8c\x23\xca\x64\x7e\x78\xa3\x62\x5b\x75\x56\xd9\x9e\x2a\x91\x27\xb0\x70\x34\x1f\x90\x89\xb5\x86\x73\x7e\x71\xda\x1e\xfb\x3a\x72\xdc\x5e\x79\x88\xcb\x74\x79\xd9\x64\xe4\xd4\xc2\x9e\xce\xb1\xfe\x85\x5a\xc0\xe9\x0c\x34\x3d\xd0\x43\xce\xa1\x36\x39\xd5\xa1\x4e\xf5\xf8\xb1\xa9\x23\x08\x75\x84\xac\x53\x6c\x3a\xc5\xa6\x53\x6c\x3a\xc5\xa6\x7f\xc5\xd8\xf4\x51\xfd\xff\x25\x4e\xfa\x33\x05\xbe\x9d\x60\xd2\x04\x93\x6a\x5f\x33\x9b\x98\x50\xd2\xe1\x50\x52\xc6\xcc\xdb\x38\x91\xdb\xe6\xaa\xa2\x8f\xa1\x6a\xa6\xd4\xc6\x56\xd6\x8c\x40\x02\x68\x48\xe8\x1a\xe1\x9a\xd9\x2e\xb7\x05\xc3\x34\xda\x2a\xbb\xcd\x12\x36\x98\x22\x50\x4c\xa1\x1b\xc5\xd5\x84\xf0\xbe\x24\x84\xf7\x2f\x22\x37\xef\x94\xd7\x9f\xa0\xde\x04\xf5\x26\xa8\x37\x41\x3d\x64\x40\x3d\xe5\xf2\xde\x60\x89\x27\xb4\x37\xa1\xbd\xda\xd7\xd2\x2c\x26\xc0\x37\x01\x3e\x1b\xef\x5f\x06\xe0\x6b\x7c\x5c\x91\x08\x26\x10\x38\x81\xc0\x09\x04\x76\x4a\x3d\x81\xc0\xbf\x12\x08\x4c\xb0\xdc\x7c\x99\x00\xd0\x75\x70\xb4\xf8\x5a\x7c\xea\xde\x3e\x39\x08\x30\x5a\x27\x35\xed\xb4\x65\xad\x69\x74\x10\x88\x79\xe2\x30\x52\x19\xd6\x04\x21\xa7\x95\xd5\x0e\x03\xf8\xda\x20\xd7\x84\xb4\x26\xa4\x35\x21\xad\x09\x69\x21\x03\x69\x51\x46\xff\xff\x18\x9b\x54\xed\x87\x47\x06\x9d\x4e\x73\x6e\x9a\xb3\xa9\xce\x83\x5e\x4b\xc6\x71\x20\x45\xd7\x72\xf5\x40\x72\x0e\x34\x6c\xf4\x6c\xf3\xba\x5e\x4b\x97\x0e\x52\xb8\xbe\x8b\x79\xa0\x10\x86\xa1\x75\xb0\x6f\xec\xc8\xf4\x3d\x4d\x7b\x86\xc2\x02\x31\x12\x51\xbf\x07\x94\xad\x10\xd6\x2e\x79\xcf\xe9\x1c\xf5\x1e\x31\x23\x5c\x18\xfb\x9c\xfb\x70\xe0\x62\xbd\xf7\xb5\x94\xcf\xf3\xf6\xfa\xc5\x4e\x9c\x85\x76\x1d\xae\x37\xbc\xde\xa3\x41\xcb\x29\xd0\x5e\x70\x67\x50\x93\x6d\x98\xa8\xd3\x67\x0f\x68\xb1\xeb\x38\x47\x07\x10\x1b\xd2\xe2\x18\x68\x6d\x40\xbb\xa3\x40\xba\x21\xf2\x8e\x81\xfb\xf6\x92\x77\x2f\x70\xe8\xdb\xb2\x36\xbf\x30\x91\xc5\x21\xe7\x45\xcc\x34\x0c\x48\x8e\xd0\xf2\x9b\x7c\x3c\xbd\x1c\x04\x3e\x07\xe8\x7c\x2f\x84\x7a\x48\x4d\x1f\xba\xe1\x76\x45\x7b\x60\xe0\x01\xca\xee\x04\xca\x31\xbe\x73\x5f\xa3\x70\x0c\xad\x1f\xa5\xf5\x76\xd5\xbb\xd2\x7e\xfb\x30\x90\xcf\xfa\x67\x7a\xe6\xc3\x37\x42\x19\xe2\xc9\x9c\x61\x4c\xe7\xd1\x77\x55\x86\x6e\x8f\x7b\x85\x42\x33\xa3\xaa\x57\xae\xfd\xd5\xcc\x9c\x56\x68\xe2\xde\x0e\xa8\x2c\xa9\xb0\x7d\xf0\x54\x2d\x80\xf2\x48\x39\x3d\x98\x1a\x6d\x0b\x9d\xba\x53\xfb\xce\xf8\xd1\x7e\xbb\x60\x4f\x06\xf5\xce\xda\xab\xeb\xca\xcb\xd5\xac\x20\xda\x72\x3b\xa2\x4b\x38\xd7\xb5\x89\xbe\x42\xd9\xb9\x73\xc4\x0c\x6d\xb7\xd9\xf8\x8d\xbd\x3e\x9c\xf5\x53\x68\x48\x14\x36\x8f\x09\xc5\x92\xf1\x21\xd1\x09\x07\x1c\xbe\xa7\x91\xf3\x6a\xc8\xc1\x57\xb0\xdd\xc5\xc6\x1d\xad\x76\x1d\xa8\x82\x0e\x4c\x38\xfe\xa5\x8c\xc5\x0a\x40\x5d\xa1\xbb\x98\xd1\xfb\x74\x61\xed\x1a\x98\xaf\x3c\x8c\x1e\xe3\xc2\x92\x29\x74\x3e\x99\xd0\xf9\x41\x50\xd0\x38\x4b\x57\x7e\x5b\x7a\x0e\xe6\xce\x4e\xd7\x19\x35\x57\xbb\x3c\x3c\xd2\x5e\x4f\x4b\x4c\xf7\x0f\x4d\x2b\x91\x5d\x94\xa6\x95\xc8\x69\x25\x72\x5a\x89\x7c\xb8\x95\xc8\x07\x80\x8c\xda\x9c\x64\x7b\xb7\x71\xdf\x57\x12\x4b\x9a\x1f\x72\x0c\x13\x03\xad\x3c\xd5\x4e\xde\x8e\x57\x13\x6d\x34\x86\xcf\x97\xe6\xa4\x68\xc4\xb0\xf6\xc9\xc2\xeb\x8d\x0b\xd7\xcd\xfe\xba\xa6\xf5\x30\xeb\x30\x33\xbe\xc7\x56\x27\xab\x08\xd9\x6d\xbb\x09\xee\x7c\x2d\xcf\xee\x87\x38\xac\xc8\xdd\x90\x9a\x58\x4a\x4e\x96\xa9\x79\x79\xf3\xde\x20\xf0\x96\xe3\x24\x19\xeb\xba\xf2\x53\x19\xab\x12\xaf\x47\xb3\xa0\x3e\xef\x9b\x8d\x6d\x6d\x7b\xde\x3b\x3b\x1a\xc0\x3f\x95\x7e\xed\x78\xfb\x76\xb8\xaf\xb3\xdd\xc5\xeb\x95\xed\x5a\x62\x41\x82\xb3\x54\x6e\x80\x4a\x92\x6f\x36\xbd\x34\xae\xde\x6f\xa4\xc0\xbc\x08\xe3\x84\xfc\x1d\xb6\xe3\xd0\x62\x38\x95\x9b\x57\xe7\x71\x12\x91\x80\xc8\x31\x69\x5e\x60\x21\x6e\x19\x0f\xc7\xa4\x79\x96\x28\x3e\x47\x54\x65\x41\x36\x08\x40\x88\x1f\x58\x08\x56\xaa\xd5\xbf\xaf\xad\x96\xd7\xd6\xcf\x87\xf5\x34\x0f\x71\x93\x6e\x26\xed\x98\x5b\x9f\x4f\xcf\x95\x34\xc6\xd7\x11\xfa\xb0\x81\x22\x1a\xdb\xdf\x8e\xdc\xc3\xb9\xf8\xdd\x5d\x3c\x74\xe6\xea\xb7\x8b\xbf\xf5\x6e\xb3\x46\x2e\x64\xf4\xab\x3c\x4e\xcf\x36\x1d\xfe\xfa\xb8\x36\xba\x8a\xd8\xad\xf6\xc6\x41\x2a\x37\x8c\x17\x0f\xda\xfe\xda\xe7\x65\xbc\x71\x2c\x36\x57\x8a\x47\x12\x4c\xf1\xbd\x77\x6b\xa4\x50\x7e\x77\x7b\x22\x60\x89\xef\xcd\xf5\xb9\x0c\x97\x79\x0d\x2b\x35\x43\xcb\x3d\x24\xf1\x78\xfc\xf8\xcb\x1f\x15\x06\xe2\x78\xd8\x51\x21\xd9\x1f\xf0\xf5\x8f\x86\xa4\x50\xfa\xb1\x47\x43\xa5\xdd\x69\x14\xe8\xa3\xc0\x86\x91\xa7\x81\x50\xb4\x7c\xc0\x81\x80\x77\x7a\x9f\xc6\xc2\xa9\x8c\x05\x33\xb0\x3b\x31\xa4\xf4\xd7\x1b\x26\x55\x97\x7c\x65\xf8\x69\x1a\x84\x8e\x41\x78\xd9\xec\xc5\x11\x16\x1e\x74\x91\xf5\x56\xf5\x57\x49\x47\x5c\x92\xa9\x1e\x99\x36\xf4\xdb\xb1\x0e\xd3\x78\x02\xb0\x9b\x25\xcb\xe9\xe9\x1d\x0d\x44\x01\x42\x08\x91\x64\xd9\xdd\x37\x08\x17\xef\xf9\xe5\x0f\xbd\x46\x91\xf5\xf9\x89\x92\x37\xdd\x89\x59\x44\x1f\x9c\xee\x34\x1e\xbe\x47\x83\x32\x72\x8e\x37\xdf\xac\x69\x38\xef\x75\xb0\xda\xdb\xac\x83\x94\x2f\x39\xa6\x62\x05\x1c\x25\x9c\x49\x16\xb0\xa8\x3c\xc7\x7e\x76\x71\x3e\x6f\xb5\x24\xe7\xe8\xb7\xb9\xc7\x6c\x43\x92\xee\x21\xd4\x17\xa1\x7f\xba\x35\xfe\xae\x39\xbc\xde\xba\x69\xd9\x8e\xe1\x62\xde\x64\x7d\x16\x88\x1b\xed\x29\x11\xfd\x4f\xa9\xff\x99\x90\xc4\xf6\xf4\xf9\x6e\xe9\x28\x23\xd7\xca\xe5\xee\xee\x9f\x63\xb1\x5b\xfb\x10\xd7\x2f\x1d\xf2\xe3\xbf\xb9\xb5\x6f\xa4\x6d\x7d\x25\x79\xfb\x24\x31\xea\x56\xbe\x5d\x53\xcd\x2d\x36\xa3\x6d\xdf\xab\x1c\xb8\x6d\x6f\xc0\x98\xa7\xdd\xaa\x86\x8c\x1d\x39\xa3\x9d\x70\x2b\x9b\x68\xd9\xfd\x33\xfe\xa9\xb6\x4a\x2e\x63\x0f\xcf\x68\x27\xd9\x4c\xb9\x46\x6d\xcb\xbe\xa1\xa8\xd6\x5f\xc6\xd6\x9f\xf1\x4f\xf4\xd4\xb4\x78\xd0\xd6\xf4\x13\x3c\x3b\xac\xd0\xdc\x90\x34\xda\xc9\xb4\x9a\x1a\x8d\xbd\x93\x87\xd4\xe2\x21\x1b\xb3\x2b\xd1\xbe\xe7\x69\xd4\x53\x67\xd5\x40\xa0\xe3\x19\x3f\x6d\x1a\xbc\x0e\x86\x3c\x10\xb4\x3d\x2a\xcd\x78\x32\xe6\xab\xbd\x36\xc9\xf4\x3a\x58\xae\xc3\xf4\x47\xea\xbf\xfb\x47\xff\x0d\x00\x00\xff\xff\xd2\x32\x5a\x28\x38\x9d\x00\x00") - -func v2SchemaJsonBytes() ([]byte, error) { - return bindataRead( - _v2SchemaJson, - "v2/schema.json", - ) -} - -func v2SchemaJson() (*asset, error) { - bytes, err := v2SchemaJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "v2/schema.json", size: 40248, mode: os.FileMode(0640), modTime: time.Unix(1568964748, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x88, 0x5e, 0xf, 0xbf, 0x17, 0x74, 0x0, 0xb2, 0x5a, 0x7f, 0xbc, 0x58, 0xcd, 0xc, 0x25, 0x73, 0xd5, 0x29, 0x1c, 0x7a, 0xd0, 0xce, 0x79, 0xd4, 0x89, 0x31, 0x27, 0x90, 0xf2, 0xff, 0xe6}} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - canonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[canonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// AssetString returns the asset contents as a string (instead of a []byte). -func AssetString(name string) (string, error) { - data, err := Asset(name) - return string(data), err -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// MustAssetString is like AssetString but panics when Asset would return an -// error. It simplifies safe initialization of global variables. -func MustAssetString(name string) string { - return string(MustAsset(name)) -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - canonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[canonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetDigest returns the digest of the file with the given name. It returns an -// error if the asset could not be found or the digest could not be loaded. -func AssetDigest(name string) ([sha256.Size]byte, error) { - canonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[canonicalName]; ok { - a, err := f() - if err != nil { - return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) - } - return a.digest, nil - } - return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) -} - -// Digests returns a map of all known files and their checksums. -func Digests() (map[string][sha256.Size]byte, error) { - mp := make(map[string][sha256.Size]byte, len(_bindata)) - for name := range _bindata { - a, err := _bindata[name]() - if err != nil { - return nil, err - } - mp[name] = a.digest - } - return mp, nil -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "jsonschema-draft-04.json": jsonschemaDraft04Json, - - "v2/schema.json": v2SchemaJson, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"}, -// AssetDir("data/img") would return []string{"a.png", "b.png"}, -// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - canonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(canonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "jsonschema-draft-04.json": &bintree{jsonschemaDraft04Json, map[string]*bintree{}}, - "v2": &bintree{nil, map[string]*bintree{ - "schema.json": &bintree{v2SchemaJson, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory. -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) -} - -// RestoreAssets restores an asset under the given directory recursively. -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - canonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) -} diff --git a/vendor/github.com/go-openapi/spec/cache.go b/vendor/github.com/go-openapi/spec/cache.go deleted file mode 100644 index 3fada0daef1..00000000000 --- a/vendor/github.com/go-openapi/spec/cache.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import "sync" - -// ResolutionCache a cache for resolving urls -type ResolutionCache interface { - Get(string) (interface{}, bool) - Set(string, interface{}) -} - -type simpleCache struct { - lock sync.RWMutex - store map[string]interface{} -} - -// Get retrieves a cached URI -func (s *simpleCache) Get(uri string) (interface{}, bool) { - debugLog("getting %q from resolution cache", uri) - s.lock.RLock() - v, ok := s.store[uri] - debugLog("got %q from resolution cache: %t", uri, ok) - - s.lock.RUnlock() - return v, ok -} - -// Set caches a URI -func (s *simpleCache) Set(uri string, data interface{}) { - s.lock.Lock() - s.store[uri] = data - s.lock.Unlock() -} - -var resCache ResolutionCache - -func init() { - resCache = initResolutionCache() -} - -// initResolutionCache initializes the URI resolution cache -func initResolutionCache() ResolutionCache { - return &simpleCache{store: map[string]interface{}{ - "http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(), - "http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(), - }} -} diff --git a/vendor/github.com/go-openapi/spec/contact_info.go b/vendor/github.com/go-openapi/spec/contact_info.go deleted file mode 100644 index f285970aa19..00000000000 --- a/vendor/github.com/go-openapi/spec/contact_info.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -// ContactInfo contact information for the exposed API. -// -// For more information: http://goo.gl/8us55a#contactObject -type ContactInfo struct { - Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` - Email string `json:"email,omitempty"` -} diff --git a/vendor/github.com/go-openapi/spec/debug.go b/vendor/github.com/go-openapi/spec/debug.go deleted file mode 100644 index 389c528ff61..00000000000 --- a/vendor/github.com/go-openapi/spec/debug.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "fmt" - "log" - "os" - "path/filepath" - "runtime" -) - -var ( - // Debug is true when the SWAGGER_DEBUG env var is not empty. - // It enables a more verbose logging of this package. - Debug = os.Getenv("SWAGGER_DEBUG") != "" - // specLogger is a debug logger for this package - specLogger *log.Logger -) - -func init() { - debugOptions() -} - -func debugOptions() { - specLogger = log.New(os.Stdout, "spec:", log.LstdFlags) -} - -func debugLog(msg string, args ...interface{}) { - // A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog() - if Debug { - _, file1, pos1, _ := runtime.Caller(1) - specLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...)) - } -} diff --git a/vendor/github.com/go-openapi/spec/expander.go b/vendor/github.com/go-openapi/spec/expander.go deleted file mode 100644 index 043720d7d8e..00000000000 --- a/vendor/github.com/go-openapi/spec/expander.go +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "fmt" - "strings" -) - -// ExpandOptions provides options for spec expand -type ExpandOptions struct { - RelativeBase string - SkipSchemas bool - ContinueOnError bool - AbsoluteCircularRef bool -} - -// ResolveRefWithBase resolves a reference against a context root with preservation of base path -func ResolveRefWithBase(root interface{}, ref *Ref, opts *ExpandOptions) (*Schema, error) { - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return nil, err - } - specBasePath := "" - if opts != nil && opts.RelativeBase != "" { - specBasePath, _ = absPath(opts.RelativeBase) - } - - result := new(Schema) - if err := resolver.Resolve(ref, result, specBasePath); err != nil { - return nil, err - } - return result, nil -} - -// ResolveRef resolves a reference against a context root -// ref is guaranteed to be in root (no need to go to external files) -// ResolveRef is ONLY called from the code generation module -func ResolveRef(root interface{}, ref *Ref) (*Schema, error) { - res, _, err := ref.GetPointer().Get(root) - if err != nil { - panic(err) - } - switch sch := res.(type) { - case Schema: - return &sch, nil - case *Schema: - return sch, nil - case map[string]interface{}: - b, _ := json.Marshal(sch) - newSch := new(Schema) - _ = json.Unmarshal(b, newSch) - return newSch, nil - default: - return nil, fmt.Errorf("unknown type for the resolved reference") - } -} - -// ResolveParameter resolves a parameter reference against a context root -func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) { - return ResolveParameterWithBase(root, ref, nil) -} - -// ResolveParameterWithBase resolves a parameter reference against a context root and base path -func ResolveParameterWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Parameter, error) { - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return nil, err - } - - result := new(Parameter) - if err := resolver.Resolve(&ref, result, ""); err != nil { - return nil, err - } - return result, nil -} - -// ResolveResponse resolves response a reference against a context root -func ResolveResponse(root interface{}, ref Ref) (*Response, error) { - return ResolveResponseWithBase(root, ref, nil) -} - -// ResolveResponseWithBase resolves response a reference against a context root and base path -func ResolveResponseWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Response, error) { - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return nil, err - } - - result := new(Response) - if err := resolver.Resolve(&ref, result, ""); err != nil { - return nil, err - } - return result, nil -} - -// ResolveItems resolves parameter items reference against a context root and base path. -// -// NOTE: stricly speaking, this construct is not supported by Swagger 2.0. -// Similarly, $ref are forbidden in response headers. -func ResolveItems(root interface{}, ref Ref, opts *ExpandOptions) (*Items, error) { - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return nil, err - } - basePath := "" - if opts.RelativeBase != "" { - basePath = opts.RelativeBase - } - result := new(Items) - if err := resolver.Resolve(&ref, result, basePath); err != nil { - return nil, err - } - return result, nil -} - -// ResolvePathItem resolves response a path item against a context root and base path -func ResolvePathItem(root interface{}, ref Ref, opts *ExpandOptions) (*PathItem, error) { - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return nil, err - } - basePath := "" - if opts.RelativeBase != "" { - basePath = opts.RelativeBase - } - result := new(PathItem) - if err := resolver.Resolve(&ref, result, basePath); err != nil { - return nil, err - } - return result, nil -} - -// ExpandSpec expands the references in a swagger spec -func ExpandSpec(spec *Swagger, options *ExpandOptions) error { - resolver, err := defaultSchemaLoader(spec, options, nil, nil) - // Just in case this ever returns an error. - if resolver.shouldStopOnError(err) { - return err - } - - // getting the base path of the spec to adjust all subsequent reference resolutions - specBasePath := "" - if options != nil && options.RelativeBase != "" { - specBasePath, _ = absPath(options.RelativeBase) - } - - if options == nil || !options.SkipSchemas { - for key, definition := range spec.Definitions { - var def *Schema - var err error - if def, err = expandSchema(definition, []string{fmt.Sprintf("#/definitions/%s", key)}, resolver, specBasePath); resolver.shouldStopOnError(err) { - return err - } - if def != nil { - spec.Definitions[key] = *def - } - } - } - - for key := range spec.Parameters { - parameter := spec.Parameters[key] - if err := expandParameterOrResponse(¶meter, resolver, specBasePath); resolver.shouldStopOnError(err) { - return err - } - spec.Parameters[key] = parameter - } - - for key := range spec.Responses { - response := spec.Responses[key] - if err := expandParameterOrResponse(&response, resolver, specBasePath); resolver.shouldStopOnError(err) { - return err - } - spec.Responses[key] = response - } - - if spec.Paths != nil { - for key := range spec.Paths.Paths { - path := spec.Paths.Paths[key] - if err := expandPathItem(&path, resolver, specBasePath); resolver.shouldStopOnError(err) { - return err - } - spec.Paths.Paths[key] = path - } - } - - return nil -} - -// baseForRoot loads in the cache the root document and produces a fake "root" base path entry -// for further $ref resolution -func baseForRoot(root interface{}, cache ResolutionCache) string { - // cache the root document to resolve $ref's - const rootBase = "root" - if root != nil { - base, _ := absPath(rootBase) - normalizedBase := normalizeAbsPath(base) - debugLog("setting root doc in cache at: %s", normalizedBase) - if cache == nil { - cache = resCache - } - cache.Set(normalizedBase, root) - return rootBase - } - return "" -} - -// ExpandSchema expands the refs in the schema object with reference to the root object -// go-openapi/validate uses this function -// notice that it is impossible to reference a json schema in a different file other than root -func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error { - opts := &ExpandOptions{ - // when a root is specified, cache the root as an in-memory document for $ref retrieval - RelativeBase: baseForRoot(root, cache), - SkipSchemas: false, - ContinueOnError: false, - // when no base path is specified, remaining $ref (circular) are rendered with an absolute path - AbsoluteCircularRef: true, - } - return ExpandSchemaWithBasePath(schema, cache, opts) -} - -// ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options -func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *ExpandOptions) error { - if schema == nil { - return nil - } - - var basePath string - if opts.RelativeBase != "" { - basePath, _ = absPath(opts.RelativeBase) - } - - resolver, err := defaultSchemaLoader(nil, opts, cache, nil) - if err != nil { - return err - } - - refs := []string{""} - var s *Schema - if s, err = expandSchema(*schema, refs, resolver, basePath); err != nil { - return err - } - *schema = *s - return nil -} - -func expandItems(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { - if target.Items != nil { - if target.Items.Schema != nil { - t, err := expandSchema(*target.Items.Schema, parentRefs, resolver, basePath) - if err != nil { - return nil, err - } - *target.Items.Schema = *t - } - for i := range target.Items.Schemas { - t, err := expandSchema(target.Items.Schemas[i], parentRefs, resolver, basePath) - if err != nil { - return nil, err - } - target.Items.Schemas[i] = *t - } - } - return &target, nil -} - -func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { - if target.Ref.String() == "" && target.Ref.IsRoot() { - // normalizing is important - newRef := normalizeFileRef(&target.Ref, basePath) - target.Ref = *newRef - return &target, nil - - } - - // change the base path of resolution when an ID is encountered - // otherwise the basePath should inherit the parent's - // important: ID can be relative path - if target.ID != "" { - debugLog("schema has ID: %s", target.ID) - // handling the case when id is a folder - // remember that basePath has to be a file - refPath := target.ID - if strings.HasSuffix(target.ID, "/") { - // path.Clean here would not work correctly if basepath is http - refPath = fmt.Sprintf("%s%s", refPath, "placeholder.json") - } - basePath = normalizePaths(refPath, basePath) - } - - var t *Schema - // if Ref is found, everything else doesn't matter - // Ref also changes the resolution scope of children expandSchema - if target.Ref.String() != "" { - // here the resolution scope is changed because a $ref was encountered - normalizedRef := normalizeFileRef(&target.Ref, basePath) - normalizedBasePath := normalizedRef.RemoteURI() - - if resolver.isCircular(normalizedRef, basePath, parentRefs...) { - // this means there is a cycle in the recursion tree: return the Ref - // - circular refs cannot be expanded. We leave them as ref. - // - denormalization means that a new local file ref is set relative to the original basePath - debugLog("shortcut circular ref: basePath: %s, normalizedPath: %s, normalized ref: %s", - basePath, normalizedBasePath, normalizedRef.String()) - if !resolver.options.AbsoluteCircularRef { - target.Ref = *denormalizeFileRef(normalizedRef, normalizedBasePath, resolver.context.basePath) - } else { - target.Ref = *normalizedRef - } - return &target, nil - } - - debugLog("basePath: %s: calling Resolve with target: %#v", basePath, target) - if err := resolver.Resolve(&target.Ref, &t, basePath); resolver.shouldStopOnError(err) { - return nil, err - } - - if t != nil { - parentRefs = append(parentRefs, normalizedRef.String()) - var err error - transitiveResolver, err := resolver.transitiveResolver(basePath, target.Ref) - if transitiveResolver.shouldStopOnError(err) { - return nil, err - } - - basePath = resolver.updateBasePath(transitiveResolver, normalizedBasePath) - - return expandSchema(*t, parentRefs, transitiveResolver, basePath) - } - } - - t, err := expandItems(target, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - target = *t - } - - for i := range target.AllOf { - t, err := expandSchema(target.AllOf[i], parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - target.AllOf[i] = *t - } - for i := range target.AnyOf { - t, err := expandSchema(target.AnyOf[i], parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - target.AnyOf[i] = *t - } - for i := range target.OneOf { - t, err := expandSchema(target.OneOf[i], parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - target.OneOf[i] = *t - } - } - if target.Not != nil { - t, err := expandSchema(*target.Not, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - *target.Not = *t - } - } - for k := range target.Properties { - t, err := expandSchema(target.Properties[k], parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - target.Properties[k] = *t - } - } - if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil { - t, err := expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - *target.AdditionalProperties.Schema = *t - } - } - for k := range target.PatternProperties { - t, err := expandSchema(target.PatternProperties[k], parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - target.PatternProperties[k] = *t - } - } - for k := range target.Dependencies { - if target.Dependencies[k].Schema != nil { - t, err := expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - *target.Dependencies[k].Schema = *t - } - } - } - if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil { - t, err := expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - *target.AdditionalItems.Schema = *t - } - } - for k := range target.Definitions { - t, err := expandSchema(target.Definitions[k], parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return &target, err - } - if t != nil { - target.Definitions[k] = *t - } - } - return &target, nil -} - -func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string) error { - if pathItem == nil { - return nil - } - - parentRefs := []string{} - if err := resolver.deref(pathItem, parentRefs, basePath); resolver.shouldStopOnError(err) { - return err - } - if pathItem.Ref.String() != "" { - transitiveResolver, err := resolver.transitiveResolver(basePath, pathItem.Ref) - if transitiveResolver.shouldStopOnError(err) { - return err - } - basePath = transitiveResolver.updateBasePath(resolver, basePath) - resolver = transitiveResolver - } - pathItem.Ref = Ref{} - - for idx := range pathItem.Parameters { - if err := expandParameterOrResponse(&(pathItem.Parameters[idx]), resolver, basePath); resolver.shouldStopOnError(err) { - return err - } - } - ops := []*Operation{ - pathItem.Get, - pathItem.Head, - pathItem.Options, - pathItem.Put, - pathItem.Post, - pathItem.Patch, - pathItem.Delete, - } - for _, op := range ops { - if err := expandOperation(op, resolver, basePath); resolver.shouldStopOnError(err) { - return err - } - } - return nil -} - -func expandOperation(op *Operation, resolver *schemaLoader, basePath string) error { - if op == nil { - return nil - } - - for i := range op.Parameters { - param := op.Parameters[i] - if err := expandParameterOrResponse(¶m, resolver, basePath); resolver.shouldStopOnError(err) { - return err - } - op.Parameters[i] = param - } - - if op.Responses != nil { - responses := op.Responses - if err := expandParameterOrResponse(responses.Default, resolver, basePath); resolver.shouldStopOnError(err) { - return err - } - for code := range responses.StatusCodeResponses { - response := responses.StatusCodeResponses[code] - if err := expandParameterOrResponse(&response, resolver, basePath); resolver.shouldStopOnError(err) { - return err - } - responses.StatusCodeResponses[code] = response - } - } - return nil -} - -// ExpandResponseWithRoot expands a response based on a root document, not a fetchable document -func ExpandResponseWithRoot(response *Response, root interface{}, cache ResolutionCache) error { - opts := &ExpandOptions{ - RelativeBase: baseForRoot(root, cache), - SkipSchemas: false, - ContinueOnError: false, - // when no base path is specified, remaining $ref (circular) are rendered with an absolute path - AbsoluteCircularRef: true, - } - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return err - } - - return expandParameterOrResponse(response, resolver, opts.RelativeBase) -} - -// ExpandResponse expands a response based on a basepath -// This is the exported version of expandResponse -// all refs inside response will be resolved relative to basePath -func ExpandResponse(response *Response, basePath string) error { - var specBasePath string - if basePath != "" { - specBasePath, _ = absPath(basePath) - } - opts := &ExpandOptions{ - RelativeBase: specBasePath, - } - resolver, err := defaultSchemaLoader(nil, opts, nil, nil) - if err != nil { - return err - } - - return expandParameterOrResponse(response, resolver, opts.RelativeBase) -} - -// ExpandParameterWithRoot expands a parameter based on a root document, not a fetchable document -func ExpandParameterWithRoot(parameter *Parameter, root interface{}, cache ResolutionCache) error { - opts := &ExpandOptions{ - RelativeBase: baseForRoot(root, cache), - SkipSchemas: false, - ContinueOnError: false, - // when no base path is specified, remaining $ref (circular) are rendered with an absolute path - AbsoluteCircularRef: true, - } - resolver, err := defaultSchemaLoader(root, opts, nil, nil) - if err != nil { - return err - } - - return expandParameterOrResponse(parameter, resolver, opts.RelativeBase) -} - -// ExpandParameter expands a parameter based on a basepath. -// This is the exported version of expandParameter -// all refs inside parameter will be resolved relative to basePath -func ExpandParameter(parameter *Parameter, basePath string) error { - var specBasePath string - if basePath != "" { - specBasePath, _ = absPath(basePath) - } - opts := &ExpandOptions{ - RelativeBase: specBasePath, - } - resolver, err := defaultSchemaLoader(nil, opts, nil, nil) - if err != nil { - return err - } - - return expandParameterOrResponse(parameter, resolver, opts.RelativeBase) -} - -func getRefAndSchema(input interface{}) (*Ref, *Schema, error) { - var ref *Ref - var sch *Schema - switch refable := input.(type) { - case *Parameter: - if refable == nil { - return nil, nil, nil - } - ref = &refable.Ref - sch = refable.Schema - case *Response: - if refable == nil { - return nil, nil, nil - } - ref = &refable.Ref - sch = refable.Schema - default: - return nil, nil, fmt.Errorf("expand: unsupported type %T. Input should be of type *Parameter or *Response", input) - } - return ref, sch, nil -} - -func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePath string) error { - ref, _, err := getRefAndSchema(input) - if err != nil { - return err - } - if ref == nil { - return nil - } - parentRefs := []string{} - if err := resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) { - return err - } - ref, sch, _ := getRefAndSchema(input) - if ref.String() != "" { - transitiveResolver, err := resolver.transitiveResolver(basePath, *ref) - if transitiveResolver.shouldStopOnError(err) { - return err - } - basePath = resolver.updateBasePath(transitiveResolver, basePath) - resolver = transitiveResolver - } - - if sch != nil && sch.Ref.String() != "" { - // schema expanded to a $ref in another root - var ern error - sch.Ref, ern = NewRef(normalizePaths(sch.Ref.String(), ref.RemoteURI())) - if ern != nil { - return ern - } - } - if ref != nil { - *ref = Ref{} - } - - if !resolver.options.SkipSchemas && sch != nil { - s, err := expandSchema(*sch, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return err - } - *sch = *s - } - return nil -} diff --git a/vendor/github.com/go-openapi/spec/external_docs.go b/vendor/github.com/go-openapi/spec/external_docs.go deleted file mode 100644 index 88add91b2b8..00000000000 --- a/vendor/github.com/go-openapi/spec/external_docs.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -// ExternalDocumentation allows referencing an external resource for -// extended documentation. -// -// For more information: http://goo.gl/8us55a#externalDocumentationObject -type ExternalDocumentation struct { - Description string `json:"description,omitempty"` - URL string `json:"url,omitempty"` -} diff --git a/vendor/github.com/go-openapi/spec/go.mod b/vendor/github.com/go-openapi/spec/go.mod deleted file mode 100644 index 14e5f2dac3a..00000000000 --- a/vendor/github.com/go-openapi/spec/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module github.com/go-openapi/spec - -require ( - github.com/go-openapi/jsonpointer v0.19.3 - github.com/go-openapi/jsonreference v0.19.2 - github.com/go-openapi/swag v0.19.5 - github.com/stretchr/testify v1.3.0 - golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect - gopkg.in/yaml.v2 v2.2.4 -) - -go 1.13 diff --git a/vendor/github.com/go-openapi/spec/go.sum b/vendor/github.com/go-openapi/spec/go.sum deleted file mode 100644 index c209ff97120..00000000000 --- a/vendor/github.com/go-openapi/spec/go.sum +++ /dev/null @@ -1,49 +0,0 @@ -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-openapi/spec/header.go b/vendor/github.com/go-openapi/spec/header.go deleted file mode 100644 index 39efe452bb0..00000000000 --- a/vendor/github.com/go-openapi/spec/header.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "strings" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -const ( - jsonArray = "array" -) - -// HeaderProps describes a response header -type HeaderProps struct { - Description string `json:"description,omitempty"` -} - -// Header describes a header for a response of the API -// -// For more information: http://goo.gl/8us55a#headerObject -type Header struct { - CommonValidations - SimpleSchema - VendorExtensible - HeaderProps -} - -// ResponseHeader creates a new header instance for use in a response -func ResponseHeader() *Header { - return new(Header) -} - -// WithDescription sets the description on this response, allows for chaining -func (h *Header) WithDescription(description string) *Header { - h.Description = description - return h -} - -// Typed a fluent builder method for the type of parameter -func (h *Header) Typed(tpe, format string) *Header { - h.Type = tpe - h.Format = format - return h -} - -// CollectionOf a fluent builder method for an array item -func (h *Header) CollectionOf(items *Items, format string) *Header { - h.Type = jsonArray - h.Items = items - h.CollectionFormat = format - return h -} - -// WithDefault sets the default value on this item -func (h *Header) WithDefault(defaultValue interface{}) *Header { - h.Default = defaultValue - return h -} - -// WithMaxLength sets a max length value -func (h *Header) WithMaxLength(max int64) *Header { - h.MaxLength = &max - return h -} - -// WithMinLength sets a min length value -func (h *Header) WithMinLength(min int64) *Header { - h.MinLength = &min - return h -} - -// WithPattern sets a pattern value -func (h *Header) WithPattern(pattern string) *Header { - h.Pattern = pattern - return h -} - -// WithMultipleOf sets a multiple of value -func (h *Header) WithMultipleOf(number float64) *Header { - h.MultipleOf = &number - return h -} - -// WithMaximum sets a maximum number value -func (h *Header) WithMaximum(max float64, exclusive bool) *Header { - h.Maximum = &max - h.ExclusiveMaximum = exclusive - return h -} - -// WithMinimum sets a minimum number value -func (h *Header) WithMinimum(min float64, exclusive bool) *Header { - h.Minimum = &min - h.ExclusiveMinimum = exclusive - return h -} - -// WithEnum sets a the enum values (replace) -func (h *Header) WithEnum(values ...interface{}) *Header { - h.Enum = append([]interface{}{}, values...) - return h -} - -// WithMaxItems sets the max items -func (h *Header) WithMaxItems(size int64) *Header { - h.MaxItems = &size - return h -} - -// WithMinItems sets the min items -func (h *Header) WithMinItems(size int64) *Header { - h.MinItems = &size - return h -} - -// UniqueValues dictates that this array can only have unique items -func (h *Header) UniqueValues() *Header { - h.UniqueItems = true - return h -} - -// AllowDuplicates this array can have duplicates -func (h *Header) AllowDuplicates() *Header { - h.UniqueItems = false - return h -} - -// MarshalJSON marshal this to JSON -func (h Header) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(h.CommonValidations) - if err != nil { - return nil, err - } - b2, err := json.Marshal(h.SimpleSchema) - if err != nil { - return nil, err - } - b3, err := json.Marshal(h.HeaderProps) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b1, b2, b3), nil -} - -// UnmarshalJSON unmarshals this header from JSON -func (h *Header) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &h.CommonValidations); err != nil { - return err - } - if err := json.Unmarshal(data, &h.SimpleSchema); err != nil { - return err - } - if err := json.Unmarshal(data, &h.VendorExtensible); err != nil { - return err - } - return json.Unmarshal(data, &h.HeaderProps) -} - -// JSONLookup look up a value by the json property name -func (h Header) JSONLookup(token string) (interface{}, error) { - if ex, ok := h.Extensions[token]; ok { - return &ex, nil - } - - r, _, err := jsonpointer.GetForToken(h.CommonValidations, token) - if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { - return nil, err - } - if r != nil { - return r, nil - } - r, _, err = jsonpointer.GetForToken(h.SimpleSchema, token) - if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { - return nil, err - } - if r != nil { - return r, nil - } - r, _, err = jsonpointer.GetForToken(h.HeaderProps, token) - return r, err -} diff --git a/vendor/github.com/go-openapi/spec/info.go b/vendor/github.com/go-openapi/spec/info.go deleted file mode 100644 index c458b49b216..00000000000 --- a/vendor/github.com/go-openapi/spec/info.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "strings" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// Extensions vendor specific extensions -type Extensions map[string]interface{} - -// Add adds a value to these extensions -func (e Extensions) Add(key string, value interface{}) { - realKey := strings.ToLower(key) - e[realKey] = value -} - -// GetString gets a string value from the extensions -func (e Extensions) GetString(key string) (string, bool) { - if v, ok := e[strings.ToLower(key)]; ok { - str, ok := v.(string) - return str, ok - } - return "", false -} - -// GetBool gets a string value from the extensions -func (e Extensions) GetBool(key string) (bool, bool) { - if v, ok := e[strings.ToLower(key)]; ok { - str, ok := v.(bool) - return str, ok - } - return false, false -} - -// GetStringSlice gets a string value from the extensions -func (e Extensions) GetStringSlice(key string) ([]string, bool) { - if v, ok := e[strings.ToLower(key)]; ok { - arr, isSlice := v.([]interface{}) - if !isSlice { - return nil, false - } - var strs []string - for _, iface := range arr { - str, isString := iface.(string) - if !isString { - return nil, false - } - strs = append(strs, str) - } - return strs, ok - } - return nil, false -} - -// VendorExtensible composition block. -type VendorExtensible struct { - Extensions Extensions -} - -// AddExtension adds an extension to this extensible object -func (v *VendorExtensible) AddExtension(key string, value interface{}) { - if value == nil { - return - } - if v.Extensions == nil { - v.Extensions = make(map[string]interface{}) - } - v.Extensions.Add(key, value) -} - -// MarshalJSON marshals the extensions to json -func (v VendorExtensible) MarshalJSON() ([]byte, error) { - toser := make(map[string]interface{}) - for k, v := range v.Extensions { - lk := strings.ToLower(k) - if strings.HasPrefix(lk, "x-") { - toser[k] = v - } - } - return json.Marshal(toser) -} - -// UnmarshalJSON for this extensible object -func (v *VendorExtensible) UnmarshalJSON(data []byte) error { - var d map[string]interface{} - if err := json.Unmarshal(data, &d); err != nil { - return err - } - for k, vv := range d { - lk := strings.ToLower(k) - if strings.HasPrefix(lk, "x-") { - if v.Extensions == nil { - v.Extensions = map[string]interface{}{} - } - v.Extensions[k] = vv - } - } - return nil -} - -// InfoProps the properties for an info definition -type InfoProps struct { - Description string `json:"description,omitempty"` - Title string `json:"title,omitempty"` - TermsOfService string `json:"termsOfService,omitempty"` - Contact *ContactInfo `json:"contact,omitempty"` - License *License `json:"license,omitempty"` - Version string `json:"version,omitempty"` -} - -// Info object provides metadata about the API. -// The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience. -// -// For more information: http://goo.gl/8us55a#infoObject -type Info struct { - VendorExtensible - InfoProps -} - -// JSONLookup look up a value by the json property name -func (i Info) JSONLookup(token string) (interface{}, error) { - if ex, ok := i.Extensions[token]; ok { - return &ex, nil - } - r, _, err := jsonpointer.GetForToken(i.InfoProps, token) - return r, err -} - -// MarshalJSON marshal this to JSON -func (i Info) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(i.InfoProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(i.VendorExtensible) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b1, b2), nil -} - -// UnmarshalJSON marshal this from JSON -func (i *Info) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &i.InfoProps); err != nil { - return err - } - return json.Unmarshal(data, &i.VendorExtensible) -} diff --git a/vendor/github.com/go-openapi/spec/items.go b/vendor/github.com/go-openapi/spec/items.go deleted file mode 100644 index 365d1631582..00000000000 --- a/vendor/github.com/go-openapi/spec/items.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "strings" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -const ( - jsonRef = "$ref" -) - -// SimpleSchema describe swagger simple schemas for parameters and headers -type SimpleSchema struct { - Type string `json:"type,omitempty"` - Nullable bool `json:"nullable,omitempty"` - Format string `json:"format,omitempty"` - Items *Items `json:"items,omitempty"` - CollectionFormat string `json:"collectionFormat,omitempty"` - Default interface{} `json:"default,omitempty"` - Example interface{} `json:"example,omitempty"` -} - -// TypeName return the type (or format) of a simple schema -func (s *SimpleSchema) TypeName() string { - if s.Format != "" { - return s.Format - } - return s.Type -} - -// ItemsTypeName yields the type of items in a simple schema array -func (s *SimpleSchema) ItemsTypeName() string { - if s.Items == nil { - return "" - } - return s.Items.TypeName() -} - -// CommonValidations describe common JSON-schema validations -type CommonValidations struct { - Maximum *float64 `json:"maximum,omitempty"` - ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` - Minimum *float64 `json:"minimum,omitempty"` - ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` - MaxLength *int64 `json:"maxLength,omitempty"` - MinLength *int64 `json:"minLength,omitempty"` - Pattern string `json:"pattern,omitempty"` - MaxItems *int64 `json:"maxItems,omitempty"` - MinItems *int64 `json:"minItems,omitempty"` - UniqueItems bool `json:"uniqueItems,omitempty"` - MultipleOf *float64 `json:"multipleOf,omitempty"` - Enum []interface{} `json:"enum,omitempty"` -} - -// Items a limited subset of JSON-Schema's items object. -// It is used by parameter definitions that are not located in "body". -// -// For more information: http://goo.gl/8us55a#items-object -type Items struct { - Refable - CommonValidations - SimpleSchema - VendorExtensible -} - -// NewItems creates a new instance of items -func NewItems() *Items { - return &Items{} -} - -// Typed a fluent builder method for the type of item -func (i *Items) Typed(tpe, format string) *Items { - i.Type = tpe - i.Format = format - return i -} - -// AsNullable flags this schema as nullable. -func (i *Items) AsNullable() *Items { - i.Nullable = true - return i -} - -// CollectionOf a fluent builder method for an array item -func (i *Items) CollectionOf(items *Items, format string) *Items { - i.Type = jsonArray - i.Items = items - i.CollectionFormat = format - return i -} - -// WithDefault sets the default value on this item -func (i *Items) WithDefault(defaultValue interface{}) *Items { - i.Default = defaultValue - return i -} - -// WithMaxLength sets a max length value -func (i *Items) WithMaxLength(max int64) *Items { - i.MaxLength = &max - return i -} - -// WithMinLength sets a min length value -func (i *Items) WithMinLength(min int64) *Items { - i.MinLength = &min - return i -} - -// WithPattern sets a pattern value -func (i *Items) WithPattern(pattern string) *Items { - i.Pattern = pattern - return i -} - -// WithMultipleOf sets a multiple of value -func (i *Items) WithMultipleOf(number float64) *Items { - i.MultipleOf = &number - return i -} - -// WithMaximum sets a maximum number value -func (i *Items) WithMaximum(max float64, exclusive bool) *Items { - i.Maximum = &max - i.ExclusiveMaximum = exclusive - return i -} - -// WithMinimum sets a minimum number value -func (i *Items) WithMinimum(min float64, exclusive bool) *Items { - i.Minimum = &min - i.ExclusiveMinimum = exclusive - return i -} - -// WithEnum sets a the enum values (replace) -func (i *Items) WithEnum(values ...interface{}) *Items { - i.Enum = append([]interface{}{}, values...) - return i -} - -// WithMaxItems sets the max items -func (i *Items) WithMaxItems(size int64) *Items { - i.MaxItems = &size - return i -} - -// WithMinItems sets the min items -func (i *Items) WithMinItems(size int64) *Items { - i.MinItems = &size - return i -} - -// UniqueValues dictates that this array can only have unique items -func (i *Items) UniqueValues() *Items { - i.UniqueItems = true - return i -} - -// AllowDuplicates this array can have duplicates -func (i *Items) AllowDuplicates() *Items { - i.UniqueItems = false - return i -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (i *Items) UnmarshalJSON(data []byte) error { - var validations CommonValidations - if err := json.Unmarshal(data, &validations); err != nil { - return err - } - var ref Refable - if err := json.Unmarshal(data, &ref); err != nil { - return err - } - var simpleSchema SimpleSchema - if err := json.Unmarshal(data, &simpleSchema); err != nil { - return err - } - var vendorExtensible VendorExtensible - if err := json.Unmarshal(data, &vendorExtensible); err != nil { - return err - } - i.Refable = ref - i.CommonValidations = validations - i.SimpleSchema = simpleSchema - i.VendorExtensible = vendorExtensible - return nil -} - -// MarshalJSON converts this items object to JSON -func (i Items) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(i.CommonValidations) - if err != nil { - return nil, err - } - b2, err := json.Marshal(i.SimpleSchema) - if err != nil { - return nil, err - } - b3, err := json.Marshal(i.Refable) - if err != nil { - return nil, err - } - b4, err := json.Marshal(i.VendorExtensible) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b4, b3, b1, b2), nil -} - -// JSONLookup look up a value by the json property name -func (i Items) JSONLookup(token string) (interface{}, error) { - if token == jsonRef { - return &i.Ref, nil - } - - r, _, err := jsonpointer.GetForToken(i.CommonValidations, token) - if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { - return nil, err - } - if r != nil { - return r, nil - } - r, _, err = jsonpointer.GetForToken(i.SimpleSchema, token) - return r, err -} diff --git a/vendor/github.com/go-openapi/spec/license.go b/vendor/github.com/go-openapi/spec/license.go deleted file mode 100644 index f20961b4fd8..00000000000 --- a/vendor/github.com/go-openapi/spec/license.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -// License information for the exposed API. -// -// For more information: http://goo.gl/8us55a#licenseObject -type License struct { - Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` -} diff --git a/vendor/github.com/go-openapi/spec/normalizer.go b/vendor/github.com/go-openapi/spec/normalizer.go deleted file mode 100644 index b8957e7c0c1..00000000000 --- a/vendor/github.com/go-openapi/spec/normalizer.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "fmt" - "net/url" - "os" - "path" - "path/filepath" - "strings" -) - -// normalize absolute path for cache. -// on Windows, drive letters should be converted to lower as scheme in net/url.URL -func normalizeAbsPath(path string) string { - u, err := url.Parse(path) - if err != nil { - debugLog("normalize absolute path failed: %s", err) - return path - } - return u.String() -} - -// base or refPath could be a file path or a URL -// given a base absolute path and a ref path, return the absolute path of refPath -// 1) if refPath is absolute, return it -// 2) if refPath is relative, join it with basePath keeping the scheme, hosts, and ports if exists -// base could be a directory or a full file path -func normalizePaths(refPath, base string) string { - refURL, _ := url.Parse(refPath) - if path.IsAbs(refURL.Path) || filepath.IsAbs(refPath) { - // refPath is actually absolute - if refURL.Host != "" { - return refPath - } - parts := strings.Split(refPath, "#") - result := filepath.FromSlash(parts[0]) - if len(parts) == 2 { - result += "#" + parts[1] - } - return result - } - - // relative refPath - baseURL, _ := url.Parse(base) - if !strings.HasPrefix(refPath, "#") { - // combining paths - if baseURL.Host != "" { - baseURL.Path = path.Join(path.Dir(baseURL.Path), refURL.Path) - } else { // base is a file - newBase := fmt.Sprintf("%s#%s", filepath.Join(filepath.Dir(base), filepath.FromSlash(refURL.Path)), refURL.Fragment) - return newBase - } - - } - // copying fragment from ref to base - baseURL.Fragment = refURL.Fragment - return baseURL.String() -} - -// denormalizePaths returns to simplest notation on file $ref, -// i.e. strips the absolute path and sets a path relative to the base path. -// -// This is currently used when we rewrite ref after a circular ref has been detected -func denormalizeFileRef(ref *Ref, relativeBase, originalRelativeBase string) *Ref { - debugLog("denormalizeFileRef for: %s", ref.String()) - - if ref.String() == "" || ref.IsRoot() || ref.HasFragmentOnly { - return ref - } - // strip relativeBase from URI - relativeBaseURL, _ := url.Parse(relativeBase) - relativeBaseURL.Fragment = "" - - if relativeBaseURL.IsAbs() && strings.HasPrefix(ref.String(), relativeBase) { - // this should work for absolute URI (e.g. http://...): we have an exact match, just trim prefix - r, _ := NewRef(strings.TrimPrefix(ref.String(), relativeBase)) - return &r - } - - if relativeBaseURL.IsAbs() { - // other absolute URL get unchanged (i.e. with a non-empty scheme) - return ref - } - - // for relative file URIs: - originalRelativeBaseURL, _ := url.Parse(originalRelativeBase) - originalRelativeBaseURL.Fragment = "" - if strings.HasPrefix(ref.String(), originalRelativeBaseURL.String()) { - // the resulting ref is in the expanded spec: return a local ref - r, _ := NewRef(strings.TrimPrefix(ref.String(), originalRelativeBaseURL.String())) - return &r - } - - // check if we may set a relative path, considering the original base path for this spec. - // Example: - // spec is located at /mypath/spec.json - // my normalized ref points to: /mypath/item.json#/target - // expected result: item.json#/target - parts := strings.Split(ref.String(), "#") - relativePath, err := filepath.Rel(path.Dir(originalRelativeBaseURL.String()), parts[0]) - if err != nil { - // there is no common ancestor (e.g. different drives on windows) - // leaves the ref unchanged - return ref - } - if len(parts) == 2 { - relativePath += "#" + parts[1] - } - r, _ := NewRef(relativePath) - return &r -} - -// relativeBase could be an ABSOLUTE file path or an ABSOLUTE URL -func normalizeFileRef(ref *Ref, relativeBase string) *Ref { - // This is important for when the reference is pointing to the root schema - if ref.String() == "" { - r, _ := NewRef(relativeBase) - return &r - } - - debugLog("normalizing %s against %s", ref.String(), relativeBase) - - s := normalizePaths(ref.String(), relativeBase) - r, _ := NewRef(s) - return &r -} - -// absPath returns the absolute path of a file -func absPath(fname string) (string, error) { - if strings.HasPrefix(fname, "http") { - return fname, nil - } - if filepath.IsAbs(fname) { - return fname, nil - } - wd, err := os.Getwd() - return filepath.Join(wd, fname), err -} diff --git a/vendor/github.com/go-openapi/spec/operation.go b/vendor/github.com/go-openapi/spec/operation.go deleted file mode 100644 index b1ebd59945b..00000000000 --- a/vendor/github.com/go-openapi/spec/operation.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "bytes" - "encoding/gob" - "encoding/json" - "sort" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -func init() { - //gob.Register(map[string][]interface{}{}) - gob.Register(map[string]interface{}{}) - gob.Register([]interface{}{}) -} - -// OperationProps describes an operation -// -// NOTES: -// - schemes, when present must be from [http, https, ws, wss]: see validate -// - Security is handled as a special case: see MarshalJSON function -type OperationProps struct { - Description string `json:"description,omitempty"` - Consumes []string `json:"consumes,omitempty"` - Produces []string `json:"produces,omitempty"` - Schemes []string `json:"schemes,omitempty"` - Tags []string `json:"tags,omitempty"` - Summary string `json:"summary,omitempty"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` - ID string `json:"operationId,omitempty"` - Deprecated bool `json:"deprecated,omitempty"` - Security []map[string][]string `json:"security,omitempty"` - Parameters []Parameter `json:"parameters,omitempty"` - Responses *Responses `json:"responses,omitempty"` -} - -// MarshalJSON takes care of serializing operation properties to JSON -// -// We use a custom marhaller here to handle a special cases related to -// the Security field. We need to preserve zero length slice -// while omitting the field when the value is nil/unset. -func (op OperationProps) MarshalJSON() ([]byte, error) { - type Alias OperationProps - if op.Security == nil { - return json.Marshal(&struct { - Security []map[string][]string `json:"security,omitempty"` - *Alias - }{ - Security: op.Security, - Alias: (*Alias)(&op), - }) - } - return json.Marshal(&struct { - Security []map[string][]string `json:"security"` - *Alias - }{ - Security: op.Security, - Alias: (*Alias)(&op), - }) -} - -// Operation describes a single API operation on a path. -// -// For more information: http://goo.gl/8us55a#operationObject -type Operation struct { - VendorExtensible - OperationProps -} - -// SuccessResponse gets a success response model -func (o *Operation) SuccessResponse() (*Response, int, bool) { - if o.Responses == nil { - return nil, 0, false - } - - responseCodes := make([]int, 0, len(o.Responses.StatusCodeResponses)) - for k := range o.Responses.StatusCodeResponses { - if k >= 200 && k < 300 { - responseCodes = append(responseCodes, k) - } - } - if len(responseCodes) > 0 { - sort.Ints(responseCodes) - v := o.Responses.StatusCodeResponses[responseCodes[0]] - return &v, responseCodes[0], true - } - - return o.Responses.Default, 0, false -} - -// JSONLookup look up a value by the json property name -func (o Operation) JSONLookup(token string) (interface{}, error) { - if ex, ok := o.Extensions[token]; ok { - return &ex, nil - } - r, _, err := jsonpointer.GetForToken(o.OperationProps, token) - return r, err -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (o *Operation) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &o.OperationProps); err != nil { - return err - } - return json.Unmarshal(data, &o.VendorExtensible) -} - -// MarshalJSON converts this items object to JSON -func (o Operation) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(o.OperationProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(o.VendorExtensible) - if err != nil { - return nil, err - } - concated := swag.ConcatJSON(b1, b2) - return concated, nil -} - -// NewOperation creates a new operation instance. -// It expects an ID as parameter but not passing an ID is also valid. -func NewOperation(id string) *Operation { - op := new(Operation) - op.ID = id - return op -} - -// WithID sets the ID property on this operation, allows for chaining. -func (o *Operation) WithID(id string) *Operation { - o.ID = id - return o -} - -// WithDescription sets the description on this operation, allows for chaining -func (o *Operation) WithDescription(description string) *Operation { - o.Description = description - return o -} - -// WithSummary sets the summary on this operation, allows for chaining -func (o *Operation) WithSummary(summary string) *Operation { - o.Summary = summary - return o -} - -// WithExternalDocs sets/removes the external docs for/from this operation. -// When you pass empty strings as params the external documents will be removed. -// When you pass non-empty string as one value then those values will be used on the external docs object. -// So when you pass a non-empty description, you should also pass the url and vice versa. -func (o *Operation) WithExternalDocs(description, url string) *Operation { - if description == "" && url == "" { - o.ExternalDocs = nil - return o - } - - if o.ExternalDocs == nil { - o.ExternalDocs = &ExternalDocumentation{} - } - o.ExternalDocs.Description = description - o.ExternalDocs.URL = url - return o -} - -// Deprecate marks the operation as deprecated -func (o *Operation) Deprecate() *Operation { - o.Deprecated = true - return o -} - -// Undeprecate marks the operation as not deprected -func (o *Operation) Undeprecate() *Operation { - o.Deprecated = false - return o -} - -// WithConsumes adds media types for incoming body values -func (o *Operation) WithConsumes(mediaTypes ...string) *Operation { - o.Consumes = append(o.Consumes, mediaTypes...) - return o -} - -// WithProduces adds media types for outgoing body values -func (o *Operation) WithProduces(mediaTypes ...string) *Operation { - o.Produces = append(o.Produces, mediaTypes...) - return o -} - -// WithTags adds tags for this operation -func (o *Operation) WithTags(tags ...string) *Operation { - o.Tags = append(o.Tags, tags...) - return o -} - -// AddParam adds a parameter to this operation, when a parameter for that location -// and with that name already exists it will be replaced -func (o *Operation) AddParam(param *Parameter) *Operation { - if param == nil { - return o - } - - for i, p := range o.Parameters { - if p.Name == param.Name && p.In == param.In { - params := append(o.Parameters[:i], *param) - params = append(params, o.Parameters[i+1:]...) - o.Parameters = params - return o - } - } - - o.Parameters = append(o.Parameters, *param) - return o -} - -// RemoveParam removes a parameter from the operation -func (o *Operation) RemoveParam(name, in string) *Operation { - for i, p := range o.Parameters { - if p.Name == name && p.In == in { - o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...) - return o - } - } - return o -} - -// SecuredWith adds a security scope to this operation. -func (o *Operation) SecuredWith(name string, scopes ...string) *Operation { - o.Security = append(o.Security, map[string][]string{name: scopes}) - return o -} - -// WithDefaultResponse adds a default response to the operation. -// Passing a nil value will remove the response -func (o *Operation) WithDefaultResponse(response *Response) *Operation { - return o.RespondsWith(0, response) -} - -// RespondsWith adds a status code response to the operation. -// When the code is 0 the value of the response will be used as default response value. -// When the value of the response is nil it will be removed from the operation -func (o *Operation) RespondsWith(code int, response *Response) *Operation { - if o.Responses == nil { - o.Responses = new(Responses) - } - if code == 0 { - o.Responses.Default = response - return o - } - if response == nil { - delete(o.Responses.StatusCodeResponses, code) - return o - } - if o.Responses.StatusCodeResponses == nil { - o.Responses.StatusCodeResponses = make(map[int]Response) - } - o.Responses.StatusCodeResponses[code] = *response - return o -} - -type opsAlias OperationProps - -type gobAlias struct { - Security []map[string]struct { - List []string - Pad bool - } - Alias *opsAlias - SecurityIsEmpty bool -} - -// GobEncode provides a safe gob encoder for Operation, including empty security requirements -func (o Operation) GobEncode() ([]byte, error) { - raw := struct { - Ext VendorExtensible - Props OperationProps - }{ - Ext: o.VendorExtensible, - Props: o.OperationProps, - } - var b bytes.Buffer - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err -} - -// GobDecode provides a safe gob decoder for Operation, including empty security requirements -func (o *Operation) GobDecode(b []byte) error { - var raw struct { - Ext VendorExtensible - Props OperationProps - } - - buf := bytes.NewBuffer(b) - err := gob.NewDecoder(buf).Decode(&raw) - if err != nil { - return err - } - o.VendorExtensible = raw.Ext - o.OperationProps = raw.Props - return nil -} - -// GobEncode provides a safe gob encoder for Operation, including empty security requirements -func (op OperationProps) GobEncode() ([]byte, error) { - raw := gobAlias{ - Alias: (*opsAlias)(&op), - } - - var b bytes.Buffer - if op.Security == nil { - // nil security requirement - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err - } - - if len(op.Security) == 0 { - // empty, but non-nil security requirement - raw.SecurityIsEmpty = true - raw.Alias.Security = nil - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err - } - - raw.Security = make([]map[string]struct { - List []string - Pad bool - }, 0, len(op.Security)) - for _, req := range op.Security { - v := make(map[string]struct { - List []string - Pad bool - }, len(req)) - for k, val := range req { - v[k] = struct { - List []string - Pad bool - }{ - List: val, - } - } - raw.Security = append(raw.Security, v) - } - - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err -} - -// GobDecode provides a safe gob decoder for Operation, including empty security requirements -func (op *OperationProps) GobDecode(b []byte) error { - var raw gobAlias - - buf := bytes.NewBuffer(b) - err := gob.NewDecoder(buf).Decode(&raw) - if err != nil { - return err - } - if raw.Alias == nil { - return nil - } - - switch { - case raw.SecurityIsEmpty: - // empty, but non-nil security requirement - raw.Alias.Security = []map[string][]string{} - case len(raw.Alias.Security) == 0: - // nil security requirement - raw.Alias.Security = nil - default: - raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security)) - for _, req := range raw.Security { - v := make(map[string][]string, len(req)) - for k, val := range req { - v[k] = make([]string, 0, len(val.List)) - v[k] = append(v[k], val.List...) - } - raw.Alias.Security = append(raw.Alias.Security, v) - } - } - - *op = *(*OperationProps)(raw.Alias) - return nil -} diff --git a/vendor/github.com/go-openapi/spec/parameter.go b/vendor/github.com/go-openapi/spec/parameter.go deleted file mode 100644 index cecdff54568..00000000000 --- a/vendor/github.com/go-openapi/spec/parameter.go +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "strings" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// QueryParam creates a query parameter -func QueryParam(name string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "query"}} -} - -// HeaderParam creates a header parameter, this is always required by default -func HeaderParam(name string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "header", Required: true}} -} - -// PathParam creates a path parameter, this is always required -func PathParam(name string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "path", Required: true}} -} - -// BodyParam creates a body parameter -func BodyParam(name string, schema *Schema) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "body", Schema: schema}, - SimpleSchema: SimpleSchema{Type: "object"}} -} - -// FormDataParam creates a body parameter -func FormDataParam(name string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}} -} - -// FileParam creates a body parameter -func FileParam(name string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}, - SimpleSchema: SimpleSchema{Type: "file"}} -} - -// SimpleArrayParam creates a param for a simple array (string, int, date etc) -func SimpleArrayParam(name, tpe, fmt string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name}, - SimpleSchema: SimpleSchema{Type: jsonArray, CollectionFormat: "csv", - Items: &Items{SimpleSchema: SimpleSchema{Type: "string", Format: fmt}}}} -} - -// ParamRef creates a parameter that's a json reference -func ParamRef(uri string) *Parameter { - p := new(Parameter) - p.Ref = MustCreateRef(uri) - return p -} - -// ParamProps describes the specific attributes of an operation parameter -// -// NOTE: -// - Schema is defined when "in" == "body": see validate -// - AllowEmptyValue is allowed where "in" == "query" || "formData" -type ParamProps struct { - Description string `json:"description,omitempty"` - Name string `json:"name,omitempty"` - In string `json:"in,omitempty"` - Required bool `json:"required,omitempty"` - Schema *Schema `json:"schema,omitempty"` - AllowEmptyValue bool `json:"allowEmptyValue,omitempty"` -} - -// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn). -// -// There are five possible parameter types. -// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part -// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, -// the path parameter is `itemId`. -// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`. -// * Header - Custom headers that are expected as part of the request. -// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be -// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for -// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist -// together for the same operation. -// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or -// `multipart/form-data` are used as the content type of the request (in Swagger's definition, -// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used -// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be -// declared together with a body parameter for the same operation. Form parameters have a different format based on -// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4). -// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. -// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple -// parameters that are being transferred. -// * `multipart/form-data` - each parameter takes a section in the payload with an internal header. -// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is -// `submit-name`. This type of form parameters is more commonly used for file transfers. -// -// For more information: http://goo.gl/8us55a#parameterObject -type Parameter struct { - Refable - CommonValidations - SimpleSchema - VendorExtensible - ParamProps -} - -// JSONLookup look up a value by the json property name -func (p Parameter) JSONLookup(token string) (interface{}, error) { - if ex, ok := p.Extensions[token]; ok { - return &ex, nil - } - if token == jsonRef { - return &p.Ref, nil - } - - r, _, err := jsonpointer.GetForToken(p.CommonValidations, token) - if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { - return nil, err - } - if r != nil { - return r, nil - } - r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token) - if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { - return nil, err - } - if r != nil { - return r, nil - } - r, _, err = jsonpointer.GetForToken(p.ParamProps, token) - return r, err -} - -// WithDescription a fluent builder method for the description of the parameter -func (p *Parameter) WithDescription(description string) *Parameter { - p.Description = description - return p -} - -// Named a fluent builder method to override the name of the parameter -func (p *Parameter) Named(name string) *Parameter { - p.Name = name - return p -} - -// WithLocation a fluent builder method to override the location of the parameter -func (p *Parameter) WithLocation(in string) *Parameter { - p.In = in - return p -} - -// Typed a fluent builder method for the type of the parameter value -func (p *Parameter) Typed(tpe, format string) *Parameter { - p.Type = tpe - p.Format = format - return p -} - -// CollectionOf a fluent builder method for an array parameter -func (p *Parameter) CollectionOf(items *Items, format string) *Parameter { - p.Type = jsonArray - p.Items = items - p.CollectionFormat = format - return p -} - -// WithDefault sets the default value on this parameter -func (p *Parameter) WithDefault(defaultValue interface{}) *Parameter { - p.AsOptional() // with default implies optional - p.Default = defaultValue - return p -} - -// AllowsEmptyValues flags this parameter as being ok with empty values -func (p *Parameter) AllowsEmptyValues() *Parameter { - p.AllowEmptyValue = true - return p -} - -// NoEmptyValues flags this parameter as not liking empty values -func (p *Parameter) NoEmptyValues() *Parameter { - p.AllowEmptyValue = false - return p -} - -// AsOptional flags this parameter as optional -func (p *Parameter) AsOptional() *Parameter { - p.Required = false - return p -} - -// AsRequired flags this parameter as required -func (p *Parameter) AsRequired() *Parameter { - if p.Default != nil { // with a default required makes no sense - return p - } - p.Required = true - return p -} - -// WithMaxLength sets a max length value -func (p *Parameter) WithMaxLength(max int64) *Parameter { - p.MaxLength = &max - return p -} - -// WithMinLength sets a min length value -func (p *Parameter) WithMinLength(min int64) *Parameter { - p.MinLength = &min - return p -} - -// WithPattern sets a pattern value -func (p *Parameter) WithPattern(pattern string) *Parameter { - p.Pattern = pattern - return p -} - -// WithMultipleOf sets a multiple of value -func (p *Parameter) WithMultipleOf(number float64) *Parameter { - p.MultipleOf = &number - return p -} - -// WithMaximum sets a maximum number value -func (p *Parameter) WithMaximum(max float64, exclusive bool) *Parameter { - p.Maximum = &max - p.ExclusiveMaximum = exclusive - return p -} - -// WithMinimum sets a minimum number value -func (p *Parameter) WithMinimum(min float64, exclusive bool) *Parameter { - p.Minimum = &min - p.ExclusiveMinimum = exclusive - return p -} - -// WithEnum sets a the enum values (replace) -func (p *Parameter) WithEnum(values ...interface{}) *Parameter { - p.Enum = append([]interface{}{}, values...) - return p -} - -// WithMaxItems sets the max items -func (p *Parameter) WithMaxItems(size int64) *Parameter { - p.MaxItems = &size - return p -} - -// WithMinItems sets the min items -func (p *Parameter) WithMinItems(size int64) *Parameter { - p.MinItems = &size - return p -} - -// UniqueValues dictates that this array can only have unique items -func (p *Parameter) UniqueValues() *Parameter { - p.UniqueItems = true - return p -} - -// AllowDuplicates this array can have duplicates -func (p *Parameter) AllowDuplicates() *Parameter { - p.UniqueItems = false - return p -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (p *Parameter) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &p.CommonValidations); err != nil { - return err - } - if err := json.Unmarshal(data, &p.Refable); err != nil { - return err - } - if err := json.Unmarshal(data, &p.SimpleSchema); err != nil { - return err - } - if err := json.Unmarshal(data, &p.VendorExtensible); err != nil { - return err - } - return json.Unmarshal(data, &p.ParamProps) -} - -// MarshalJSON converts this items object to JSON -func (p Parameter) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(p.CommonValidations) - if err != nil { - return nil, err - } - b2, err := json.Marshal(p.SimpleSchema) - if err != nil { - return nil, err - } - b3, err := json.Marshal(p.Refable) - if err != nil { - return nil, err - } - b4, err := json.Marshal(p.VendorExtensible) - if err != nil { - return nil, err - } - b5, err := json.Marshal(p.ParamProps) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b3, b1, b2, b4, b5), nil -} diff --git a/vendor/github.com/go-openapi/spec/path_item.go b/vendor/github.com/go-openapi/spec/path_item.go deleted file mode 100644 index 68fc8e90144..00000000000 --- a/vendor/github.com/go-openapi/spec/path_item.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// PathItemProps the path item specific properties -type PathItemProps struct { - Get *Operation `json:"get,omitempty"` - Put *Operation `json:"put,omitempty"` - Post *Operation `json:"post,omitempty"` - Delete *Operation `json:"delete,omitempty"` - Options *Operation `json:"options,omitempty"` - Head *Operation `json:"head,omitempty"` - Patch *Operation `json:"patch,omitempty"` - Parameters []Parameter `json:"parameters,omitempty"` -} - -// PathItem describes the operations available on a single path. -// A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering). -// The path itself is still exposed to the documentation viewer but they will -// not know which operations and parameters are available. -// -// For more information: http://goo.gl/8us55a#pathItemObject -type PathItem struct { - Refable - VendorExtensible - PathItemProps -} - -// JSONLookup look up a value by the json property name -func (p PathItem) JSONLookup(token string) (interface{}, error) { - if ex, ok := p.Extensions[token]; ok { - return &ex, nil - } - if token == jsonRef { - return &p.Ref, nil - } - r, _, err := jsonpointer.GetForToken(p.PathItemProps, token) - return r, err -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (p *PathItem) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &p.Refable); err != nil { - return err - } - if err := json.Unmarshal(data, &p.VendorExtensible); err != nil { - return err - } - return json.Unmarshal(data, &p.PathItemProps) -} - -// MarshalJSON converts this items object to JSON -func (p PathItem) MarshalJSON() ([]byte, error) { - b3, err := json.Marshal(p.Refable) - if err != nil { - return nil, err - } - b4, err := json.Marshal(p.VendorExtensible) - if err != nil { - return nil, err - } - b5, err := json.Marshal(p.PathItemProps) - if err != nil { - return nil, err - } - concated := swag.ConcatJSON(b3, b4, b5) - return concated, nil -} diff --git a/vendor/github.com/go-openapi/spec/paths.go b/vendor/github.com/go-openapi/spec/paths.go deleted file mode 100644 index 9dc82a2901d..00000000000 --- a/vendor/github.com/go-openapi/spec/paths.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/go-openapi/swag" -) - -// Paths holds the relative paths to the individual endpoints. -// The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order -// to construct the full URL. -// The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering). -// -// For more information: http://goo.gl/8us55a#pathsObject -type Paths struct { - VendorExtensible - Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/" -} - -// JSONLookup look up a value by the json property name -func (p Paths) JSONLookup(token string) (interface{}, error) { - if pi, ok := p.Paths[token]; ok { - return &pi, nil - } - if ex, ok := p.Extensions[token]; ok { - return &ex, nil - } - return nil, fmt.Errorf("object has no field %q", token) -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (p *Paths) UnmarshalJSON(data []byte) error { - var res map[string]json.RawMessage - if err := json.Unmarshal(data, &res); err != nil { - return err - } - for k, v := range res { - if strings.HasPrefix(strings.ToLower(k), "x-") { - if p.Extensions == nil { - p.Extensions = make(map[string]interface{}) - } - var d interface{} - if err := json.Unmarshal(v, &d); err != nil { - return err - } - p.Extensions[k] = d - } - if strings.HasPrefix(k, "/") { - if p.Paths == nil { - p.Paths = make(map[string]PathItem) - } - var pi PathItem - if err := json.Unmarshal(v, &pi); err != nil { - return err - } - p.Paths[k] = pi - } - } - return nil -} - -// MarshalJSON converts this items object to JSON -func (p Paths) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(p.VendorExtensible) - if err != nil { - return nil, err - } - - pths := make(map[string]PathItem) - for k, v := range p.Paths { - if strings.HasPrefix(k, "/") { - pths[k] = v - } - } - b2, err := json.Marshal(pths) - if err != nil { - return nil, err - } - concated := swag.ConcatJSON(b1, b2) - return concated, nil -} diff --git a/vendor/github.com/go-openapi/spec/ref.go b/vendor/github.com/go-openapi/spec/ref.go deleted file mode 100644 index 1f31a9ead01..00000000000 --- a/vendor/github.com/go-openapi/spec/ref.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "bytes" - "encoding/gob" - "encoding/json" - "net/http" - "os" - "path/filepath" - - "github.com/go-openapi/jsonreference" -) - -// Refable is a struct for things that accept a $ref property -type Refable struct { - Ref Ref -} - -// MarshalJSON marshals the ref to json -func (r Refable) MarshalJSON() ([]byte, error) { - return r.Ref.MarshalJSON() -} - -// UnmarshalJSON unmarshalss the ref from json -func (r *Refable) UnmarshalJSON(d []byte) error { - return json.Unmarshal(d, &r.Ref) -} - -// Ref represents a json reference that is potentially resolved -type Ref struct { - jsonreference.Ref -} - -// RemoteURI gets the remote uri part of the ref -func (r *Ref) RemoteURI() string { - if r.String() == "" { - return r.String() - } - - u := *r.GetURL() - u.Fragment = "" - return u.String() -} - -// IsValidURI returns true when the url the ref points to can be found -func (r *Ref) IsValidURI(basepaths ...string) bool { - if r.String() == "" { - return true - } - - v := r.RemoteURI() - if v == "" { - return true - } - - if r.HasFullURL { - //#nosec - rr, err := http.Get(v) - if err != nil { - return false - } - defer rr.Body.Close() - - return rr.StatusCode/100 == 2 - } - - if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) { - return false - } - - // check for local file - pth := v - if r.HasURLPathOnly { - base := "." - if len(basepaths) > 0 { - base = filepath.Dir(filepath.Join(basepaths...)) - } - p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth))) - if e != nil { - return false - } - pth = p - } - - fi, err := os.Stat(filepath.ToSlash(pth)) - if err != nil { - return false - } - - return !fi.IsDir() -} - -// Inherits creates a new reference from a parent and a child -// If the child cannot inherit from the parent, an error is returned -func (r *Ref) Inherits(child Ref) (*Ref, error) { - ref, err := r.Ref.Inherits(child.Ref) - if err != nil { - return nil, err - } - return &Ref{Ref: *ref}, nil -} - -// NewRef creates a new instance of a ref object -// returns an error when the reference uri is an invalid uri -func NewRef(refURI string) (Ref, error) { - ref, err := jsonreference.New(refURI) - if err != nil { - return Ref{}, err - } - return Ref{Ref: ref}, nil -} - -// MustCreateRef creates a ref object but panics when refURI is invalid. -// Use the NewRef method for a version that returns an error. -func MustCreateRef(refURI string) Ref { - return Ref{Ref: jsonreference.MustCreateRef(refURI)} -} - -// MarshalJSON marshals this ref into a JSON object -func (r Ref) MarshalJSON() ([]byte, error) { - str := r.String() - if str == "" { - if r.IsRoot() { - return []byte(`{"$ref":""}`), nil - } - return []byte("{}"), nil - } - v := map[string]interface{}{"$ref": str} - return json.Marshal(v) -} - -// UnmarshalJSON unmarshals this ref from a JSON object -func (r *Ref) UnmarshalJSON(d []byte) error { - var v map[string]interface{} - if err := json.Unmarshal(d, &v); err != nil { - return err - } - return r.fromMap(v) -} - -// GobEncode provides a safe gob encoder for Ref -func (r Ref) GobEncode() ([]byte, error) { - var b bytes.Buffer - raw, err := r.MarshalJSON() - if err != nil { - return nil, err - } - err = gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err -} - -// GobDecode provides a safe gob decoder for Ref -func (r *Ref) GobDecode(b []byte) error { - var raw []byte - buf := bytes.NewBuffer(b) - err := gob.NewDecoder(buf).Decode(&raw) - if err != nil { - return err - } - return json.Unmarshal(raw, r) -} - -func (r *Ref) fromMap(v map[string]interface{}) error { - if v == nil { - return nil - } - - if vv, ok := v["$ref"]; ok { - if str, ok := vv.(string); ok { - ref, err := jsonreference.New(str) - if err != nil { - return err - } - *r = Ref{Ref: ref} - } - } - - return nil -} diff --git a/vendor/github.com/go-openapi/spec/response.go b/vendor/github.com/go-openapi/spec/response.go deleted file mode 100644 index 27729c1d93b..00000000000 --- a/vendor/github.com/go-openapi/spec/response.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// ResponseProps properties specific to a response -type ResponseProps struct { - Description string `json:"description,omitempty"` - Schema *Schema `json:"schema,omitempty"` - Headers map[string]Header `json:"headers,omitempty"` - Examples map[string]interface{} `json:"examples,omitempty"` -} - -// Response describes a single response from an API Operation. -// -// For more information: http://goo.gl/8us55a#responseObject -type Response struct { - Refable - ResponseProps - VendorExtensible -} - -// JSONLookup look up a value by the json property name -func (r Response) JSONLookup(token string) (interface{}, error) { - if ex, ok := r.Extensions[token]; ok { - return &ex, nil - } - if token == "$ref" { - return &r.Ref, nil - } - ptr, _, err := jsonpointer.GetForToken(r.ResponseProps, token) - return ptr, err -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (r *Response) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &r.ResponseProps); err != nil { - return err - } - if err := json.Unmarshal(data, &r.Refable); err != nil { - return err - } - return json.Unmarshal(data, &r.VendorExtensible) -} - -// MarshalJSON converts this items object to JSON -func (r Response) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(r.ResponseProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(r.Refable) - if err != nil { - return nil, err - } - b3, err := json.Marshal(r.VendorExtensible) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b1, b2, b3), nil -} - -// NewResponse creates a new response instance -func NewResponse() *Response { - return new(Response) -} - -// ResponseRef creates a response as a json reference -func ResponseRef(url string) *Response { - resp := NewResponse() - resp.Ref = MustCreateRef(url) - return resp -} - -// WithDescription sets the description on this response, allows for chaining -func (r *Response) WithDescription(description string) *Response { - r.Description = description - return r -} - -// WithSchema sets the schema on this response, allows for chaining. -// Passing a nil argument removes the schema from this response -func (r *Response) WithSchema(schema *Schema) *Response { - r.Schema = schema - return r -} - -// AddHeader adds a header to this response -func (r *Response) AddHeader(name string, header *Header) *Response { - if header == nil { - return r.RemoveHeader(name) - } - if r.Headers == nil { - r.Headers = make(map[string]Header) - } - r.Headers[name] = *header - return r -} - -// RemoveHeader removes a header from this response -func (r *Response) RemoveHeader(name string) *Response { - delete(r.Headers, name) - return r -} - -// AddExample adds an example to this response -func (r *Response) AddExample(mediaType string, example interface{}) *Response { - if r.Examples == nil { - r.Examples = make(map[string]interface{}) - } - r.Examples[mediaType] = example - return r -} diff --git a/vendor/github.com/go-openapi/spec/responses.go b/vendor/github.com/go-openapi/spec/responses.go deleted file mode 100644 index 4efb6f868bd..00000000000 --- a/vendor/github.com/go-openapi/spec/responses.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "fmt" - "reflect" - "strconv" - - "github.com/go-openapi/swag" -) - -// Responses is a container for the expected responses of an operation. -// The container maps a HTTP response code to the expected response. -// It is not expected from the documentation to necessarily cover all possible HTTP response codes, -// since they may not be known in advance. However, it is expected from the documentation to cover -// a successful operation response and any known errors. -// -// The `default` can be used a default response object for all HTTP codes that are not covered -// individually by the specification. -// -// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response -// for a successful operation call. -// -// For more information: http://goo.gl/8us55a#responsesObject -type Responses struct { - VendorExtensible - ResponsesProps -} - -// JSONLookup implements an interface to customize json pointer lookup -func (r Responses) JSONLookup(token string) (interface{}, error) { - if token == "default" { - return r.Default, nil - } - if ex, ok := r.Extensions[token]; ok { - return &ex, nil - } - if i, err := strconv.Atoi(token); err == nil { - if scr, ok := r.StatusCodeResponses[i]; ok { - return scr, nil - } - } - return nil, fmt.Errorf("object has no field %q", token) -} - -// UnmarshalJSON hydrates this items instance with the data from JSON -func (r *Responses) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &r.ResponsesProps); err != nil { - return err - } - if err := json.Unmarshal(data, &r.VendorExtensible); err != nil { - return err - } - if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) { - r.ResponsesProps = ResponsesProps{} - } - return nil -} - -// MarshalJSON converts this items object to JSON -func (r Responses) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(r.ResponsesProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(r.VendorExtensible) - if err != nil { - return nil, err - } - concated := swag.ConcatJSON(b1, b2) - return concated, nil -} - -// ResponsesProps describes all responses for an operation. -// It tells what is the default response and maps all responses with a -// HTTP status code. -type ResponsesProps struct { - Default *Response - StatusCodeResponses map[int]Response -} - -// MarshalJSON marshals responses as JSON -func (r ResponsesProps) MarshalJSON() ([]byte, error) { - toser := map[string]Response{} - if r.Default != nil { - toser["default"] = *r.Default - } - for k, v := range r.StatusCodeResponses { - toser[strconv.Itoa(k)] = v - } - return json.Marshal(toser) -} - -// UnmarshalJSON unmarshals responses from JSON -func (r *ResponsesProps) UnmarshalJSON(data []byte) error { - var res map[string]Response - if err := json.Unmarshal(data, &res); err != nil { - return nil - } - if v, ok := res["default"]; ok { - r.Default = &v - delete(res, "default") - } - for k, v := range res { - if nk, err := strconv.Atoi(k); err == nil { - if r.StatusCodeResponses == nil { - r.StatusCodeResponses = map[int]Response{} - } - r.StatusCodeResponses[nk] = v - } - } - return nil -} diff --git a/vendor/github.com/go-openapi/spec/schema.go b/vendor/github.com/go-openapi/spec/schema.go deleted file mode 100644 index 37858ece909..00000000000 --- a/vendor/github.com/go-openapi/spec/schema.go +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "fmt" - "net/url" - "strings" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// BooleanProperty creates a boolean property -func BooleanProperty() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}} -} - -// BoolProperty creates a boolean property -func BoolProperty() *Schema { return BooleanProperty() } - -// StringProperty creates a string property -func StringProperty() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} -} - -// CharProperty creates a string property -func CharProperty() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} -} - -// Float64Property creates a float64/double property -func Float64Property() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}} -} - -// Float32Property creates a float32/float property -func Float32Property() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}} -} - -// Int8Property creates an int8 property -func Int8Property() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}} -} - -// Int16Property creates an int16 property -func Int16Property() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}} -} - -// Int32Property creates an int32 property -func Int32Property() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}} -} - -// Int64Property creates an int64 property -func Int64Property() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}} -} - -// StrFmtProperty creates a property for the named string format -func StrFmtProperty(format string) *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}} -} - -// DateProperty creates a date property -func DateProperty() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}} -} - -// DateTimeProperty creates a date time property -func DateTimeProperty() *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}} -} - -// MapProperty creates a map property -func MapProperty(property *Schema) *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"object"}, - AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}} -} - -// RefProperty creates a ref property -func RefProperty(name string) *Schema { - return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} -} - -// RefSchema creates a ref property -func RefSchema(name string) *Schema { - return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} -} - -// ArrayProperty creates an array property -func ArrayProperty(items *Schema) *Schema { - if items == nil { - return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}} - } - return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}} -} - -// ComposedSchema creates a schema with allOf -func ComposedSchema(schemas ...Schema) *Schema { - s := new(Schema) - s.AllOf = schemas - return s -} - -// SchemaURL represents a schema url -type SchemaURL string - -// MarshalJSON marshal this to JSON -func (r SchemaURL) MarshalJSON() ([]byte, error) { - if r == "" { - return []byte("{}"), nil - } - v := map[string]interface{}{"$schema": string(r)} - return json.Marshal(v) -} - -// UnmarshalJSON unmarshal this from JSON -func (r *SchemaURL) UnmarshalJSON(data []byte) error { - var v map[string]interface{} - if err := json.Unmarshal(data, &v); err != nil { - return err - } - return r.fromMap(v) -} - -func (r *SchemaURL) fromMap(v map[string]interface{}) error { - if v == nil { - return nil - } - if vv, ok := v["$schema"]; ok { - if str, ok := vv.(string); ok { - u, err := url.Parse(str) - if err != nil { - return err - } - - *r = SchemaURL(u.String()) - } - } - return nil -} - -// SchemaProps describes a JSON schema (draft 4) -type SchemaProps struct { - ID string `json:"id,omitempty"` - Ref Ref `json:"-"` - Schema SchemaURL `json:"-"` - Description string `json:"description,omitempty"` - Type StringOrArray `json:"type,omitempty"` - Nullable bool `json:"nullable,omitempty"` - Format string `json:"format,omitempty"` - Title string `json:"title,omitempty"` - Default interface{} `json:"default,omitempty"` - Maximum *float64 `json:"maximum,omitempty"` - ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` - Minimum *float64 `json:"minimum,omitempty"` - ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` - MaxLength *int64 `json:"maxLength,omitempty"` - MinLength *int64 `json:"minLength,omitempty"` - Pattern string `json:"pattern,omitempty"` - MaxItems *int64 `json:"maxItems,omitempty"` - MinItems *int64 `json:"minItems,omitempty"` - UniqueItems bool `json:"uniqueItems,omitempty"` - MultipleOf *float64 `json:"multipleOf,omitempty"` - Enum []interface{} `json:"enum,omitempty"` - MaxProperties *int64 `json:"maxProperties,omitempty"` - MinProperties *int64 `json:"minProperties,omitempty"` - Required []string `json:"required,omitempty"` - Items *SchemaOrArray `json:"items,omitempty"` - AllOf []Schema `json:"allOf,omitempty"` - OneOf []Schema `json:"oneOf,omitempty"` - AnyOf []Schema `json:"anyOf,omitempty"` - Not *Schema `json:"not,omitempty"` - Properties map[string]Schema `json:"properties,omitempty"` - AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"` - PatternProperties map[string]Schema `json:"patternProperties,omitempty"` - Dependencies Dependencies `json:"dependencies,omitempty"` - AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"` - Definitions Definitions `json:"definitions,omitempty"` -} - -// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4) -type SwaggerSchemaProps struct { - Discriminator string `json:"discriminator,omitempty"` - ReadOnly bool `json:"readOnly,omitempty"` - XML *XMLObject `json:"xml,omitempty"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` - Example interface{} `json:"example,omitempty"` -} - -// Schema the schema object allows the definition of input and output data types. -// These types can be objects, but also primitives and arrays. -// This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/) -// and uses a predefined subset of it. -// On top of this subset, there are extensions provided by this specification to allow for more complete documentation. -// -// For more information: http://goo.gl/8us55a#schemaObject -type Schema struct { - VendorExtensible - SchemaProps - SwaggerSchemaProps - ExtraProps map[string]interface{} `json:"-"` -} - -// JSONLookup implements an interface to customize json pointer lookup -func (s Schema) JSONLookup(token string) (interface{}, error) { - if ex, ok := s.Extensions[token]; ok { - return &ex, nil - } - - if ex, ok := s.ExtraProps[token]; ok { - return &ex, nil - } - - r, _, err := jsonpointer.GetForToken(s.SchemaProps, token) - if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) { - return r, err - } - r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token) - return r, err -} - -// WithID sets the id for this schema, allows for chaining -func (s *Schema) WithID(id string) *Schema { - s.ID = id - return s -} - -// WithTitle sets the title for this schema, allows for chaining -func (s *Schema) WithTitle(title string) *Schema { - s.Title = title - return s -} - -// WithDescription sets the description for this schema, allows for chaining -func (s *Schema) WithDescription(description string) *Schema { - s.Description = description - return s -} - -// WithProperties sets the properties for this schema -func (s *Schema) WithProperties(schemas map[string]Schema) *Schema { - s.Properties = schemas - return s -} - -// SetProperty sets a property on this schema -func (s *Schema) SetProperty(name string, schema Schema) *Schema { - if s.Properties == nil { - s.Properties = make(map[string]Schema) - } - s.Properties[name] = schema - return s -} - -// WithAllOf sets the all of property -func (s *Schema) WithAllOf(schemas ...Schema) *Schema { - s.AllOf = schemas - return s -} - -// WithMaxProperties sets the max number of properties an object can have -func (s *Schema) WithMaxProperties(max int64) *Schema { - s.MaxProperties = &max - return s -} - -// WithMinProperties sets the min number of properties an object must have -func (s *Schema) WithMinProperties(min int64) *Schema { - s.MinProperties = &min - return s -} - -// Typed sets the type of this schema for a single value item -func (s *Schema) Typed(tpe, format string) *Schema { - s.Type = []string{tpe} - s.Format = format - return s -} - -// AddType adds a type with potential format to the types for this schema -func (s *Schema) AddType(tpe, format string) *Schema { - s.Type = append(s.Type, tpe) - if format != "" { - s.Format = format - } - return s -} - -// AsNullable flags this schema as nullable. -func (s *Schema) AsNullable() *Schema { - s.Nullable = true - return s -} - -// CollectionOf a fluent builder method for an array parameter -func (s *Schema) CollectionOf(items Schema) *Schema { - s.Type = []string{jsonArray} - s.Items = &SchemaOrArray{Schema: &items} - return s -} - -// WithDefault sets the default value on this parameter -func (s *Schema) WithDefault(defaultValue interface{}) *Schema { - s.Default = defaultValue - return s -} - -// WithRequired flags this parameter as required -func (s *Schema) WithRequired(items ...string) *Schema { - s.Required = items - return s -} - -// AddRequired adds field names to the required properties array -func (s *Schema) AddRequired(items ...string) *Schema { - s.Required = append(s.Required, items...) - return s -} - -// WithMaxLength sets a max length value -func (s *Schema) WithMaxLength(max int64) *Schema { - s.MaxLength = &max - return s -} - -// WithMinLength sets a min length value -func (s *Schema) WithMinLength(min int64) *Schema { - s.MinLength = &min - return s -} - -// WithPattern sets a pattern value -func (s *Schema) WithPattern(pattern string) *Schema { - s.Pattern = pattern - return s -} - -// WithMultipleOf sets a multiple of value -func (s *Schema) WithMultipleOf(number float64) *Schema { - s.MultipleOf = &number - return s -} - -// WithMaximum sets a maximum number value -func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema { - s.Maximum = &max - s.ExclusiveMaximum = exclusive - return s -} - -// WithMinimum sets a minimum number value -func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema { - s.Minimum = &min - s.ExclusiveMinimum = exclusive - return s -} - -// WithEnum sets a the enum values (replace) -func (s *Schema) WithEnum(values ...interface{}) *Schema { - s.Enum = append([]interface{}{}, values...) - return s -} - -// WithMaxItems sets the max items -func (s *Schema) WithMaxItems(size int64) *Schema { - s.MaxItems = &size - return s -} - -// WithMinItems sets the min items -func (s *Schema) WithMinItems(size int64) *Schema { - s.MinItems = &size - return s -} - -// UniqueValues dictates that this array can only have unique items -func (s *Schema) UniqueValues() *Schema { - s.UniqueItems = true - return s -} - -// AllowDuplicates this array can have duplicates -func (s *Schema) AllowDuplicates() *Schema { - s.UniqueItems = false - return s -} - -// AddToAllOf adds a schema to the allOf property -func (s *Schema) AddToAllOf(schemas ...Schema) *Schema { - s.AllOf = append(s.AllOf, schemas...) - return s -} - -// WithDiscriminator sets the name of the discriminator field -func (s *Schema) WithDiscriminator(discriminator string) *Schema { - s.Discriminator = discriminator - return s -} - -// AsReadOnly flags this schema as readonly -func (s *Schema) AsReadOnly() *Schema { - s.ReadOnly = true - return s -} - -// AsWritable flags this schema as writeable (not read-only) -func (s *Schema) AsWritable() *Schema { - s.ReadOnly = false - return s -} - -// WithExample sets the example for this schema -func (s *Schema) WithExample(example interface{}) *Schema { - s.Example = example - return s -} - -// WithExternalDocs sets/removes the external docs for/from this schema. -// When you pass empty strings as params the external documents will be removed. -// When you pass non-empty string as one value then those values will be used on the external docs object. -// So when you pass a non-empty description, you should also pass the url and vice versa. -func (s *Schema) WithExternalDocs(description, url string) *Schema { - if description == "" && url == "" { - s.ExternalDocs = nil - return s - } - - if s.ExternalDocs == nil { - s.ExternalDocs = &ExternalDocumentation{} - } - s.ExternalDocs.Description = description - s.ExternalDocs.URL = url - return s -} - -// WithXMLName sets the xml name for the object -func (s *Schema) WithXMLName(name string) *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Name = name - return s -} - -// WithXMLNamespace sets the xml namespace for the object -func (s *Schema) WithXMLNamespace(namespace string) *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Namespace = namespace - return s -} - -// WithXMLPrefix sets the xml prefix for the object -func (s *Schema) WithXMLPrefix(prefix string) *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Prefix = prefix - return s -} - -// AsXMLAttribute flags this object as xml attribute -func (s *Schema) AsXMLAttribute() *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Attribute = true - return s -} - -// AsXMLElement flags this object as an xml node -func (s *Schema) AsXMLElement() *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Attribute = false - return s -} - -// AsWrappedXML flags this object as wrapped, this is mostly useful for array types -func (s *Schema) AsWrappedXML() *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Wrapped = true - return s -} - -// AsUnwrappedXML flags this object as an xml node -func (s *Schema) AsUnwrappedXML() *Schema { - if s.XML == nil { - s.XML = new(XMLObject) - } - s.XML.Wrapped = false - return s -} - -// MarshalJSON marshal this to JSON -func (s Schema) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(s.SchemaProps) - if err != nil { - return nil, fmt.Errorf("schema props %v", err) - } - b2, err := json.Marshal(s.VendorExtensible) - if err != nil { - return nil, fmt.Errorf("vendor props %v", err) - } - b3, err := s.Ref.MarshalJSON() - if err != nil { - return nil, fmt.Errorf("ref prop %v", err) - } - b4, err := s.Schema.MarshalJSON() - if err != nil { - return nil, fmt.Errorf("schema prop %v", err) - } - b5, err := json.Marshal(s.SwaggerSchemaProps) - if err != nil { - return nil, fmt.Errorf("common validations %v", err) - } - var b6 []byte - if s.ExtraProps != nil { - jj, err := json.Marshal(s.ExtraProps) - if err != nil { - return nil, fmt.Errorf("extra props %v", err) - } - b6 = jj - } - return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil -} - -// UnmarshalJSON marshal this from JSON -func (s *Schema) UnmarshalJSON(data []byte) error { - props := struct { - SchemaProps - SwaggerSchemaProps - }{} - if err := json.Unmarshal(data, &props); err != nil { - return err - } - - sch := Schema{ - SchemaProps: props.SchemaProps, - SwaggerSchemaProps: props.SwaggerSchemaProps, - } - - var d map[string]interface{} - if err := json.Unmarshal(data, &d); err != nil { - return err - } - - _ = sch.Ref.fromMap(d) - _ = sch.Schema.fromMap(d) - - delete(d, "$ref") - delete(d, "$schema") - for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) { - delete(d, pn) - } - - for k, vv := range d { - lk := strings.ToLower(k) - if strings.HasPrefix(lk, "x-") { - if sch.Extensions == nil { - sch.Extensions = map[string]interface{}{} - } - sch.Extensions[k] = vv - continue - } - if sch.ExtraProps == nil { - sch.ExtraProps = map[string]interface{}{} - } - sch.ExtraProps[k] = vv - } - - *s = sch - - return nil -} diff --git a/vendor/github.com/go-openapi/spec/schema_loader.go b/vendor/github.com/go-openapi/spec/schema_loader.go deleted file mode 100644 index 961d477571a..00000000000 --- a/vendor/github.com/go-openapi/spec/schema_loader.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - "fmt" - "log" - "net/url" - "reflect" - "strings" - - "github.com/go-openapi/swag" -) - -// PathLoader function to use when loading remote refs -var PathLoader func(string) (json.RawMessage, error) - -func init() { - PathLoader = func(path string) (json.RawMessage, error) { - data, err := swag.LoadFromFileOrHTTP(path) - if err != nil { - return nil, err - } - return json.RawMessage(data), nil - } -} - -// resolverContext allows to share a context during spec processing. -// At the moment, it just holds the index of circular references found. -type resolverContext struct { - // circulars holds all visited circular references, which allows shortcuts. - // NOTE: this is not just a performance improvement: it is required to figure out - // circular references which participate several cycles. - // This structure is privately instantiated and needs not be locked against - // concurrent access, unless we chose to implement a parallel spec walking. - circulars map[string]bool - basePath string -} - -func newResolverContext(originalBasePath string) *resolverContext { - return &resolverContext{ - circulars: make(map[string]bool), - basePath: originalBasePath, // keep the root base path in context - } -} - -type schemaLoader struct { - root interface{} - options *ExpandOptions - cache ResolutionCache - context *resolverContext - loadDoc func(string) (json.RawMessage, error) -} - -func (r *schemaLoader) transitiveResolver(basePath string, ref Ref) (*schemaLoader, error) { - if ref.IsRoot() || ref.HasFragmentOnly { - return r, nil - } - - baseRef, _ := NewRef(basePath) - currentRef := normalizeFileRef(&ref, basePath) - if strings.HasPrefix(currentRef.String(), baseRef.String()) { - return r, nil - } - - // Set a new root to resolve against - rootURL := currentRef.GetURL() - rootURL.Fragment = "" - root, _ := r.cache.Get(rootURL.String()) - - // shallow copy of resolver options to set a new RelativeBase when - // traversing multiple documents - newOptions := r.options - newOptions.RelativeBase = rootURL.String() - debugLog("setting new root: %s", newOptions.RelativeBase) - return defaultSchemaLoader(root, newOptions, r.cache, r.context) -} - -func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string) string { - if transitive != r { - debugLog("got a new resolver") - if transitive.options != nil && transitive.options.RelativeBase != "" { - basePath, _ = absPath(transitive.options.RelativeBase) - debugLog("new basePath = %s", basePath) - } - } - return basePath -} - -func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string) error { - tgt := reflect.ValueOf(target) - if tgt.Kind() != reflect.Ptr { - return fmt.Errorf("resolve ref: target needs to be a pointer") - } - - refURL := ref.GetURL() - if refURL == nil { - return nil - } - - var res interface{} - var data interface{} - var err error - // Resolve against the root if it isn't nil, and if ref is pointing at the root, or has a fragment only which means - // it is pointing somewhere in the root. - root := r.root - if (ref.IsRoot() || ref.HasFragmentOnly) && root == nil && basePath != "" { - if baseRef, erb := NewRef(basePath); erb == nil { - root, _, _, _ = r.load(baseRef.GetURL()) - } - } - if (ref.IsRoot() || ref.HasFragmentOnly) && root != nil { - data = root - } else { - baseRef := normalizeFileRef(ref, basePath) - debugLog("current ref is: %s", ref.String()) - debugLog("current ref normalized file: %s", baseRef.String()) - data, _, _, err = r.load(baseRef.GetURL()) - if err != nil { - return err - } - } - - res = data - if ref.String() != "" { - res, _, err = ref.GetPointer().Get(data) - if err != nil { - return err - } - } - return swag.DynamicJSONToStruct(res, target) -} - -func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) { - debugLog("loading schema from url: %s", refURL) - toFetch := *refURL - toFetch.Fragment = "" - - normalized := normalizeAbsPath(toFetch.String()) - - data, fromCache := r.cache.Get(normalized) - if !fromCache { - b, err := r.loadDoc(normalized) - if err != nil { - debugLog("unable to load the document: %v", err) - return nil, url.URL{}, false, err - } - - if err := json.Unmarshal(b, &data); err != nil { - return nil, url.URL{}, false, err - } - r.cache.Set(normalized, data) - } - - return data, toFetch, fromCache, nil -} - -// isCircular detects cycles in sequences of $ref. -// It relies on a private context (which needs not be locked). -func (r *schemaLoader) isCircular(ref *Ref, basePath string, parentRefs ...string) (foundCycle bool) { - normalizedRef := normalizePaths(ref.String(), basePath) - if _, ok := r.context.circulars[normalizedRef]; ok { - // circular $ref has been already detected in another explored cycle - foundCycle = true - return - } - foundCycle = swag.ContainsStringsCI(parentRefs, normalizedRef) - if foundCycle { - r.context.circulars[normalizedRef] = true - } - return -} - -// Resolve resolves a reference against basePath and stores the result in target -// Resolve is not in charge of following references, it only resolves ref by following its URL -// if the schema that ref is referring to has more refs in it. Resolve doesn't resolve them -// if basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct -func (r *schemaLoader) Resolve(ref *Ref, target interface{}, basePath string) error { - return r.resolveRef(ref, target, basePath) -} - -func (r *schemaLoader) deref(input interface{}, parentRefs []string, basePath string) error { - var ref *Ref - switch refable := input.(type) { - case *Schema: - ref = &refable.Ref - case *Parameter: - ref = &refable.Ref - case *Response: - ref = &refable.Ref - case *PathItem: - ref = &refable.Ref - default: - return fmt.Errorf("deref: unsupported type %T", input) - } - - curRef := ref.String() - if curRef != "" { - normalizedRef := normalizeFileRef(ref, basePath) - normalizedBasePath := normalizedRef.RemoteURI() - - if r.isCircular(normalizedRef, basePath, parentRefs...) { - return nil - } - - if err := r.resolveRef(ref, input, basePath); r.shouldStopOnError(err) { - return err - } - - // NOTE(fredbi): removed basePath check => needs more testing - if ref.String() != "" && ref.String() != curRef { - parentRefs = append(parentRefs, normalizedRef.String()) - return r.deref(input, parentRefs, normalizedBasePath) - } - } - - return nil -} - -func (r *schemaLoader) shouldStopOnError(err error) bool { - if err != nil && !r.options.ContinueOnError { - return true - } - - if err != nil { - log.Println(err) - } - - return false -} - -func defaultSchemaLoader( - root interface{}, - expandOptions *ExpandOptions, - cache ResolutionCache, - context *resolverContext) (*schemaLoader, error) { - - if cache == nil { - cache = resCache - } - if expandOptions == nil { - expandOptions = &ExpandOptions{} - } - absBase, _ := absPath(expandOptions.RelativeBase) - if context == nil { - context = newResolverContext(absBase) - } - return &schemaLoader{ - root: root, - options: expandOptions, - cache: cache, - context: context, - loadDoc: func(path string) (json.RawMessage, error) { - debugLog("fetching document at %q", path) - return PathLoader(path) - }, - }, nil -} diff --git a/vendor/github.com/go-openapi/spec/security_scheme.go b/vendor/github.com/go-openapi/spec/security_scheme.go deleted file mode 100644 index fe353842a6f..00000000000 --- a/vendor/github.com/go-openapi/spec/security_scheme.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -const ( - basic = "basic" - apiKey = "apiKey" - oauth2 = "oauth2" - implicit = "implicit" - password = "password" - application = "application" - accessCode = "accessCode" -) - -// BasicAuth creates a basic auth security scheme -func BasicAuth() *SecurityScheme { - return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: basic}} -} - -// APIKeyAuth creates an api key auth security scheme -func APIKeyAuth(fieldName, valueSource string) *SecurityScheme { - return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: apiKey, Name: fieldName, In: valueSource}} -} - -// OAuth2Implicit creates an implicit flow oauth2 security scheme -func OAuth2Implicit(authorizationURL string) *SecurityScheme { - return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ - Type: oauth2, - Flow: implicit, - AuthorizationURL: authorizationURL, - }} -} - -// OAuth2Password creates a password flow oauth2 security scheme -func OAuth2Password(tokenURL string) *SecurityScheme { - return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ - Type: oauth2, - Flow: password, - TokenURL: tokenURL, - }} -} - -// OAuth2Application creates an application flow oauth2 security scheme -func OAuth2Application(tokenURL string) *SecurityScheme { - return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ - Type: oauth2, - Flow: application, - TokenURL: tokenURL, - }} -} - -// OAuth2AccessToken creates an access token flow oauth2 security scheme -func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme { - return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ - Type: oauth2, - Flow: accessCode, - AuthorizationURL: authorizationURL, - TokenURL: tokenURL, - }} -} - -// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section -type SecuritySchemeProps struct { - Description string `json:"description,omitempty"` - Type string `json:"type"` - Name string `json:"name,omitempty"` // api key - In string `json:"in,omitempty"` // api key - Flow string `json:"flow,omitempty"` // oauth2 - AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2 - TokenURL string `json:"tokenUrl,omitempty"` // oauth2 - Scopes map[string]string `json:"scopes,omitempty"` // oauth2 -} - -// AddScope adds a scope to this security scheme -func (s *SecuritySchemeProps) AddScope(scope, description string) { - if s.Scopes == nil { - s.Scopes = make(map[string]string) - } - s.Scopes[scope] = description -} - -// SecurityScheme allows the definition of a security scheme that can be used by the operations. -// Supported schemes are basic authentication, an API key (either as a header or as a query parameter) -// and OAuth2's common flows (implicit, password, application and access code). -// -// For more information: http://goo.gl/8us55a#securitySchemeObject -type SecurityScheme struct { - VendorExtensible - SecuritySchemeProps -} - -// JSONLookup implements an interface to customize json pointer lookup -func (s SecurityScheme) JSONLookup(token string) (interface{}, error) { - if ex, ok := s.Extensions[token]; ok { - return &ex, nil - } - - r, _, err := jsonpointer.GetForToken(s.SecuritySchemeProps, token) - return r, err -} - -// MarshalJSON marshal this to JSON -func (s SecurityScheme) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(s.SecuritySchemeProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(s.VendorExtensible) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b1, b2), nil -} - -// UnmarshalJSON marshal this from JSON -func (s *SecurityScheme) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil { - return err - } - return json.Unmarshal(data, &s.VendorExtensible) -} diff --git a/vendor/github.com/go-openapi/spec/spec.go b/vendor/github.com/go-openapi/spec/spec.go deleted file mode 100644 index 0bb045bc06a..00000000000 --- a/vendor/github.com/go-openapi/spec/spec.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import "encoding/json" - -//go:generate curl -L --progress -o ./schemas/v2/schema.json http://swagger.io/v2/schema.json -//go:generate curl -L --progress -o ./schemas/jsonschema-draft-04.json http://json-schema.org/draft-04/schema -//go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/... -//go:generate perl -pi -e s,Json,JSON,g bindata.go - -const ( - // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs - SwaggerSchemaURL = "http://swagger.io/v2/schema.json#" - // JSONSchemaURL the url for the json schema schema - JSONSchemaURL = "http://json-schema.org/draft-04/schema#" -) - -var ( - jsonSchema *Schema - swaggerSchema *Schema -) - -func init() { - jsonSchema = MustLoadJSONSchemaDraft04() - swaggerSchema = MustLoadSwagger20Schema() -} - -// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error -func MustLoadJSONSchemaDraft04() *Schema { - d, e := JSONSchemaDraft04() - if e != nil { - panic(e) - } - return d -} - -// JSONSchemaDraft04 loads the json schema document for json shema draft04 -func JSONSchemaDraft04() (*Schema, error) { - b, err := Asset("jsonschema-draft-04.json") - if err != nil { - return nil, err - } - - schema := new(Schema) - if err := json.Unmarshal(b, schema); err != nil { - return nil, err - } - return schema, nil -} - -// MustLoadSwagger20Schema panics when Swagger20Schema returns an error -func MustLoadSwagger20Schema() *Schema { - d, e := Swagger20Schema() - if e != nil { - panic(e) - } - return d -} - -// Swagger20Schema loads the swagger 2.0 schema from the embedded assets -func Swagger20Schema() (*Schema, error) { - - b, err := Asset("v2/schema.json") - if err != nil { - return nil, err - } - - schema := new(Schema) - if err := json.Unmarshal(b, schema); err != nil { - return nil, err - } - return schema, nil -} diff --git a/vendor/github.com/go-openapi/spec/swagger.go b/vendor/github.com/go-openapi/spec/swagger.go deleted file mode 100644 index 44722ffd5ad..00000000000 --- a/vendor/github.com/go-openapi/spec/swagger.go +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "bytes" - "encoding/gob" - "encoding/json" - "fmt" - "strconv" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// Swagger this is the root document object for the API specification. -// It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier) -// together into one document. -// -// For more information: http://goo.gl/8us55a#swagger-object- -type Swagger struct { - VendorExtensible - SwaggerProps -} - -// JSONLookup look up a value by the json property name -func (s Swagger) JSONLookup(token string) (interface{}, error) { - if ex, ok := s.Extensions[token]; ok { - return &ex, nil - } - r, _, err := jsonpointer.GetForToken(s.SwaggerProps, token) - return r, err -} - -// MarshalJSON marshals this swagger structure to json -func (s Swagger) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(s.SwaggerProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(s.VendorExtensible) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b1, b2), nil -} - -// UnmarshalJSON unmarshals a swagger spec from json -func (s *Swagger) UnmarshalJSON(data []byte) error { - var sw Swagger - if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil { - return err - } - if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil { - return err - } - *s = sw - return nil -} - -// GobEncode provides a safe gob encoder for Swagger, including extensions -func (s Swagger) GobEncode() ([]byte, error) { - var b bytes.Buffer - raw := struct { - Props SwaggerProps - Ext VendorExtensible - }{ - Props: s.SwaggerProps, - Ext: s.VendorExtensible, - } - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err -} - -// GobDecode provides a safe gob decoder for Swagger, including extensions -func (s *Swagger) GobDecode(b []byte) error { - var raw struct { - Props SwaggerProps - Ext VendorExtensible - } - buf := bytes.NewBuffer(b) - err := gob.NewDecoder(buf).Decode(&raw) - if err != nil { - return err - } - s.SwaggerProps = raw.Props - s.VendorExtensible = raw.Ext - return nil -} - -// SwaggerProps captures the top-level properties of an Api specification -// -// NOTE: validation rules -// - the scheme, when present must be from [http, https, ws, wss] -// - BasePath must start with a leading "/" -// - Paths is required -type SwaggerProps struct { - ID string `json:"id,omitempty"` - Consumes []string `json:"consumes,omitempty"` - Produces []string `json:"produces,omitempty"` - Schemes []string `json:"schemes,omitempty"` - Swagger string `json:"swagger,omitempty"` - Info *Info `json:"info,omitempty"` - Host string `json:"host,omitempty"` - BasePath string `json:"basePath,omitempty"` - Paths *Paths `json:"paths"` - Definitions Definitions `json:"definitions,omitempty"` - Parameters map[string]Parameter `json:"parameters,omitempty"` - Responses map[string]Response `json:"responses,omitempty"` - SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"` - Security []map[string][]string `json:"security,omitempty"` - Tags []Tag `json:"tags,omitempty"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` -} - -type swaggerPropsAlias SwaggerProps - -type gobSwaggerPropsAlias struct { - Security []map[string]struct { - List []string - Pad bool - } - Alias *swaggerPropsAlias - SecurityIsEmpty bool -} - -// GobEncode provides a safe gob encoder for SwaggerProps, including empty security requirements -func (o SwaggerProps) GobEncode() ([]byte, error) { - raw := gobSwaggerPropsAlias{ - Alias: (*swaggerPropsAlias)(&o), - } - - var b bytes.Buffer - if o.Security == nil { - // nil security requirement - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err - } - - if len(o.Security) == 0 { - // empty, but non-nil security requirement - raw.SecurityIsEmpty = true - raw.Alias.Security = nil - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err - } - - raw.Security = make([]map[string]struct { - List []string - Pad bool - }, 0, len(o.Security)) - for _, req := range o.Security { - v := make(map[string]struct { - List []string - Pad bool - }, len(req)) - for k, val := range req { - v[k] = struct { - List []string - Pad bool - }{ - List: val, - } - } - raw.Security = append(raw.Security, v) - } - - err := gob.NewEncoder(&b).Encode(raw) - return b.Bytes(), err -} - -// GobDecode provides a safe gob decoder for SwaggerProps, including empty security requirements -func (o *SwaggerProps) GobDecode(b []byte) error { - var raw gobSwaggerPropsAlias - - buf := bytes.NewBuffer(b) - err := gob.NewDecoder(buf).Decode(&raw) - if err != nil { - return err - } - if raw.Alias == nil { - return nil - } - - switch { - case raw.SecurityIsEmpty: - // empty, but non-nil security requirement - raw.Alias.Security = []map[string][]string{} - case len(raw.Alias.Security) == 0: - // nil security requirement - raw.Alias.Security = nil - default: - raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security)) - for _, req := range raw.Security { - v := make(map[string][]string, len(req)) - for k, val := range req { - v[k] = make([]string, 0, len(val.List)) - v[k] = append(v[k], val.List...) - } - raw.Alias.Security = append(raw.Alias.Security, v) - } - } - - *o = *(*SwaggerProps)(raw.Alias) - return nil -} - -// Dependencies represent a dependencies property -type Dependencies map[string]SchemaOrStringArray - -// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property -type SchemaOrBool struct { - Allows bool - Schema *Schema -} - -// JSONLookup implements an interface to customize json pointer lookup -func (s SchemaOrBool) JSONLookup(token string) (interface{}, error) { - if token == "allows" { - return s.Allows, nil - } - r, _, err := jsonpointer.GetForToken(s.Schema, token) - return r, err -} - -var jsTrue = []byte("true") -var jsFalse = []byte("false") - -// MarshalJSON convert this object to JSON -func (s SchemaOrBool) MarshalJSON() ([]byte, error) { - if s.Schema != nil { - return json.Marshal(s.Schema) - } - - if s.Schema == nil && !s.Allows { - return jsFalse, nil - } - return jsTrue, nil -} - -// UnmarshalJSON converts this bool or schema object from a JSON structure -func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { - var nw SchemaOrBool - if len(data) >= 4 { - if data[0] == '{' { - var sch Schema - if err := json.Unmarshal(data, &sch); err != nil { - return err - } - nw.Schema = &sch - } - nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e') - } - *s = nw - return nil -} - -// SchemaOrStringArray represents a schema or a string array -type SchemaOrStringArray struct { - Schema *Schema - Property []string -} - -// JSONLookup implements an interface to customize json pointer lookup -func (s SchemaOrStringArray) JSONLookup(token string) (interface{}, error) { - r, _, err := jsonpointer.GetForToken(s.Schema, token) - return r, err -} - -// MarshalJSON converts this schema object or array into JSON structure -func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) { - if len(s.Property) > 0 { - return json.Marshal(s.Property) - } - if s.Schema != nil { - return json.Marshal(s.Schema) - } - return []byte("null"), nil -} - -// UnmarshalJSON converts this schema object or array from a JSON structure -func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error { - var first byte - if len(data) > 1 { - first = data[0] - } - var nw SchemaOrStringArray - if first == '{' { - var sch Schema - if err := json.Unmarshal(data, &sch); err != nil { - return err - } - nw.Schema = &sch - } - if first == '[' { - if err := json.Unmarshal(data, &nw.Property); err != nil { - return err - } - } - *s = nw - return nil -} - -// Definitions contains the models explicitly defined in this spec -// An object to hold data types that can be consumed and produced by operations. -// These data types can be primitives, arrays or models. -// -// For more information: http://goo.gl/8us55a#definitionsObject -type Definitions map[string]Schema - -// SecurityDefinitions a declaration of the security schemes available to be used in the specification. -// This does not enforce the security schemes on the operations and only serves to provide -// the relevant details for each scheme. -// -// For more information: http://goo.gl/8us55a#securityDefinitionsObject -type SecurityDefinitions map[string]*SecurityScheme - -// StringOrArray represents a value that can either be a string -// or an array of strings. Mainly here for serialization purposes -type StringOrArray []string - -// Contains returns true when the value is contained in the slice -func (s StringOrArray) Contains(value string) bool { - for _, str := range s { - if str == value { - return true - } - } - return false -} - -// JSONLookup implements an interface to customize json pointer lookup -func (s SchemaOrArray) JSONLookup(token string) (interface{}, error) { - if _, err := strconv.Atoi(token); err == nil { - r, _, err := jsonpointer.GetForToken(s.Schemas, token) - return r, err - } - r, _, err := jsonpointer.GetForToken(s.Schema, token) - return r, err -} - -// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string -func (s *StringOrArray) UnmarshalJSON(data []byte) error { - var first byte - if len(data) > 1 { - first = data[0] - } - - if first == '[' { - var parsed []string - if err := json.Unmarshal(data, &parsed); err != nil { - return err - } - *s = StringOrArray(parsed) - return nil - } - - var single interface{} - if err := json.Unmarshal(data, &single); err != nil { - return err - } - if single == nil { - return nil - } - switch v := single.(type) { - case string: - *s = StringOrArray([]string{v}) - return nil - default: - return fmt.Errorf("only string or array is allowed, not %T", single) - } -} - -// MarshalJSON converts this string or array to a JSON array or JSON string -func (s StringOrArray) MarshalJSON() ([]byte, error) { - if len(s) == 1 { - return json.Marshal([]string(s)[0]) - } - return json.Marshal([]string(s)) -} - -// SchemaOrArray represents a value that can either be a Schema -// or an array of Schema. Mainly here for serialization purposes -type SchemaOrArray struct { - Schema *Schema - Schemas []Schema -} - -// Len returns the number of schemas in this property -func (s SchemaOrArray) Len() int { - if s.Schema != nil { - return 1 - } - return len(s.Schemas) -} - -// ContainsType returns true when one of the schemas is of the specified type -func (s *SchemaOrArray) ContainsType(name string) bool { - if s.Schema != nil { - return s.Schema.Type != nil && s.Schema.Type.Contains(name) - } - return false -} - -// MarshalJSON converts this schema object or array into JSON structure -func (s SchemaOrArray) MarshalJSON() ([]byte, error) { - if len(s.Schemas) > 0 { - return json.Marshal(s.Schemas) - } - return json.Marshal(s.Schema) -} - -// UnmarshalJSON converts this schema object or array from a JSON structure -func (s *SchemaOrArray) UnmarshalJSON(data []byte) error { - var nw SchemaOrArray - var first byte - if len(data) > 1 { - first = data[0] - } - if first == '{' { - var sch Schema - if err := json.Unmarshal(data, &sch); err != nil { - return err - } - nw.Schema = &sch - } - if first == '[' { - if err := json.Unmarshal(data, &nw.Schemas); err != nil { - return err - } - } - *s = nw - return nil -} - -// vim:set ft=go noet sts=2 sw=2 ts=2: diff --git a/vendor/github.com/go-openapi/spec/tag.go b/vendor/github.com/go-openapi/spec/tag.go deleted file mode 100644 index faa3d3de1eb..00000000000 --- a/vendor/github.com/go-openapi/spec/tag.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -import ( - "encoding/json" - - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag" -) - -// TagProps describe a tag entry in the top level tags section of a swagger spec -type TagProps struct { - Description string `json:"description,omitempty"` - Name string `json:"name,omitempty"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` -} - -// NewTag creates a new tag -func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag { - return Tag{TagProps: TagProps{Description: description, Name: name, ExternalDocs: externalDocs}} -} - -// Tag allows adding meta data to a single tag that is used by the -// [Operation Object](http://goo.gl/8us55a#operationObject). -// It is not mandatory to have a Tag Object per tag used there. -// -// For more information: http://goo.gl/8us55a#tagObject -type Tag struct { - VendorExtensible - TagProps -} - -// JSONLookup implements an interface to customize json pointer lookup -func (t Tag) JSONLookup(token string) (interface{}, error) { - if ex, ok := t.Extensions[token]; ok { - return &ex, nil - } - - r, _, err := jsonpointer.GetForToken(t.TagProps, token) - return r, err -} - -// MarshalJSON marshal this to JSON -func (t Tag) MarshalJSON() ([]byte, error) { - b1, err := json.Marshal(t.TagProps) - if err != nil { - return nil, err - } - b2, err := json.Marshal(t.VendorExtensible) - if err != nil { - return nil, err - } - return swag.ConcatJSON(b1, b2), nil -} - -// UnmarshalJSON marshal this from JSON -func (t *Tag) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &t.TagProps); err != nil { - return err - } - return json.Unmarshal(data, &t.VendorExtensible) -} diff --git a/vendor/github.com/go-openapi/spec/unused.go b/vendor/github.com/go-openapi/spec/unused.go deleted file mode 100644 index aa12b56f6e4..00000000000 --- a/vendor/github.com/go-openapi/spec/unused.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -/* - -import ( - "net/url" - "os" - "path" - "path/filepath" - - "github.com/go-openapi/jsonpointer" -) - - // Some currently unused functions and definitions that - // used to be part of the expander. - - // Moved here for the record and possible future reuse - -var ( - idPtr, _ = jsonpointer.New("/id") - refPtr, _ = jsonpointer.New("/$ref") -) - -func idFromNode(node interface{}) (*Ref, error) { - if idValue, _, err := idPtr.Get(node); err == nil { - if refStr, ok := idValue.(string); ok && refStr != "" { - idRef, err := NewRef(refStr) - if err != nil { - return nil, err - } - return &idRef, nil - } - } - return nil, nil -} - -func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointer) *Ref { - if startingRef == nil { - return nil - } - - if ptr == nil { - return startingRef - } - - ret := startingRef - var idRef *Ref - node := startingNode - - for _, tok := range ptr.DecodedTokens() { - node, _, _ = jsonpointer.GetForToken(node, tok) - if node == nil { - break - } - - idRef, _ = idFromNode(node) - if idRef != nil { - nw, err := ret.Inherits(*idRef) - if err != nil { - break - } - ret = nw - } - - refRef, _, _ := refPtr.Get(node) - if refRef != nil { - var rf Ref - switch value := refRef.(type) { - case string: - rf, _ = NewRef(value) - } - nw, err := ret.Inherits(rf) - if err != nil { - break - } - nwURL := nw.GetURL() - if nwURL.Scheme == "file" || (nwURL.Scheme == "" && nwURL.Host == "") { - nwpt := filepath.ToSlash(nwURL.Path) - if filepath.IsAbs(nwpt) { - _, err := os.Stat(nwpt) - if err != nil { - nwURL.Path = filepath.Join(".", nwpt) - } - } - } - - ret = nw - } - - } - - return ret -} - -// basePathFromSchemaID returns a new basePath based on an existing basePath and a schema ID -func basePathFromSchemaID(oldBasePath, id string) string { - u, err := url.Parse(oldBasePath) - if err != nil { - panic(err) - } - uid, err := url.Parse(id) - if err != nil { - panic(err) - } - - if path.IsAbs(uid.Path) { - return id - } - u.Path = path.Join(path.Dir(u.Path), uid.Path) - return u.String() -} -*/ - -// type ExtraSchemaProps map[string]interface{} - -// // JSONSchema represents a structure that is a json schema draft 04 -// type JSONSchema struct { -// SchemaProps -// ExtraSchemaProps -// } - -// // MarshalJSON marshal this to JSON -// func (s JSONSchema) MarshalJSON() ([]byte, error) { -// b1, err := json.Marshal(s.SchemaProps) -// if err != nil { -// return nil, err -// } -// b2, err := s.Ref.MarshalJSON() -// if err != nil { -// return nil, err -// } -// b3, err := s.Schema.MarshalJSON() -// if err != nil { -// return nil, err -// } -// b4, err := json.Marshal(s.ExtraSchemaProps) -// if err != nil { -// return nil, err -// } -// return swag.ConcatJSON(b1, b2, b3, b4), nil -// } - -// // UnmarshalJSON marshal this from JSON -// func (s *JSONSchema) UnmarshalJSON(data []byte) error { -// var sch JSONSchema -// if err := json.Unmarshal(data, &sch.SchemaProps); err != nil { -// return err -// } -// if err := json.Unmarshal(data, &sch.Ref); err != nil { -// return err -// } -// if err := json.Unmarshal(data, &sch.Schema); err != nil { -// return err -// } -// if err := json.Unmarshal(data, &sch.ExtraSchemaProps); err != nil { -// return err -// } -// *s = sch -// return nil -// } diff --git a/vendor/github.com/go-openapi/spec/xml_object.go b/vendor/github.com/go-openapi/spec/xml_object.go deleted file mode 100644 index 945a46703d5..00000000000 --- a/vendor/github.com/go-openapi/spec/xml_object.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// 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. - -package spec - -// XMLObject a metadata object that allows for more fine-tuned XML model definitions. -// -// For more information: http://goo.gl/8us55a#xmlObject -type XMLObject struct { - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` - Prefix string `json:"prefix,omitempty"` - Attribute bool `json:"attribute,omitempty"` - Wrapped bool `json:"wrapped,omitempty"` -} - -// WithName sets the xml name for the object -func (x *XMLObject) WithName(name string) *XMLObject { - x.Name = name - return x -} - -// WithNamespace sets the xml namespace for the object -func (x *XMLObject) WithNamespace(namespace string) *XMLObject { - x.Namespace = namespace - return x -} - -// WithPrefix sets the xml prefix for the object -func (x *XMLObject) WithPrefix(prefix string) *XMLObject { - x.Prefix = prefix - return x -} - -// AsAttribute flags this object as xml attribute -func (x *XMLObject) AsAttribute() *XMLObject { - x.Attribute = true - return x -} - -// AsElement flags this object as an xml node -func (x *XMLObject) AsElement() *XMLObject { - x.Attribute = false - return x -} - -// AsWrapped flags this object as wrapped, this is mostly useful for array types -func (x *XMLObject) AsWrapped() *XMLObject { - x.Wrapped = true - return x -} - -// AsUnwrapped flags this object as an xml node -func (x *XMLObject) AsUnwrapped() *XMLObject { - x.Wrapped = false - return x -} diff --git a/vendor/github.com/operator-framework/api/crds/operators.coreos.com_installplans.yaml b/vendor/github.com/operator-framework/api/crds/operators.coreos.com_installplans.yaml index 616f51ba0d2..6aeaaa7bd74 100644 --- a/vendor/github.com/operator-framework/api/crds/operators.coreos.com_installplans.yaml +++ b/vendor/github.com/operator-framework/api/crds/operators.coreos.com_installplans.yaml @@ -222,6 +222,8 @@ spec: - resource - status properties: + optional: + type: boolean resolving: type: string resource: diff --git a/vendor/github.com/operator-framework/api/crds/zz_defs.go b/vendor/github.com/operator-framework/api/crds/zz_defs.go index fc6f90c3684..c925d0174d0 100644 --- a/vendor/github.com/operator-framework/api/crds/zz_defs.go +++ b/vendor/github.com/operator-framework/api/crds/zz_defs.go @@ -1,6 +1,6 @@ // Code generated by go-bindata. (@generated) DO NOT EDIT. -//Package crds generated by go-bindata.// sources: + //Package crds generated by go-bindata.// sources: // operators.coreos.com_catalogsources.yaml // operators.coreos.com_clusterserviceversions.yaml // operators.coreos.com_installplans.yaml @@ -125,7 +125,7 @@ func operatorsCoreosCom_clusterserviceversionsYaml() (*asset, error) { return a, nil } -var _operatorsCoreosCom_installplansYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xdd\x6f\x1b\x37\x12\x7f\xf7\x5f\x31\x70\x1f\xd2\x02\x96\xdc\xe6\x80\xc3\x41\x6f\x39\xf7\x7a\xf0\x5d\x3f\x82\xd8\xcd\x4b\xaf\x0f\xa3\xdd\x91\x96\x35\x97\x64\xf9\x21\x47\x57\xf4\x7f\x3f\x0c\xb9\x9f\xd2\xee\x6a\xe5\x38\x69\x70\xe8\xbe\x24\xde\x1d\x92\xf3\x3d\xbf\x21\x29\x34\xe2\x2d\x59\x27\xb4\x5a\x01\x1a\x41\xef\x3c\x29\xfe\xcb\x2d\x1f\xfe\xe6\x96\x42\x5f\xef\xbe\xba\x78\x10\x2a\x5f\xc1\x4d\x70\x5e\x97\x6f\xc8\xe9\x60\x33\xfa\x9a\x36\x42\x09\x2f\xb4\xba\x28\xc9\x63\x8e\x1e\x57\x17\x00\xa8\x94\xf6\xc8\xaf\x1d\xff\x09\x90\x69\xe5\xad\x96\x92\xec\x62\x4b\x6a\xf9\x10\xd6\xb4\x0e\x42\xe6\x64\xe3\xe4\xf5\xd2\xbb\x2f\x97\x7f\x5d\xbe\xbc\x00\xc8\x2c\xc5\xe1\xf7\xa2\x24\xe7\xb1\x34\x2b\x50\x41\xca\x0b\x00\x85\x25\xad\x40\x28\xe7\x51\x4a\x23\x51\xb9\xa5\x36\x64\xd1\x6b\xeb\x96\x99\xb6\xa4\xf9\x9f\xf2\xc2\x19\xca\x78\xed\xad\xd5\xc1\xac\x60\x90\x26\xcd\x56\xb3\x88\x9e\xb6\xda\x8a\xfa\x6f\x80\x05\x68\x59\xc6\xff\x27\xd1\x6f\xd3\xa2\xaf\x25\xaa\xf8\x56\x0a\xe7\xff\x7d\xf8\xe5\x5b\xe1\x7c\xfc\x6a\x64\xb0\x28\xfb\xac\xc6\x0f\xae\xd0\xd6\x7f\xdf\x2e\xcc\x0b\x09\x93\x3e\x09\xb5\x0d\x12\x6d\x6f\xd4\x05\x80\xcb\xb4\xa1\x15\xc4\x41\x06\x33\xca\x2f\x00\x2a\xa5\x55\x93\x2c\x00\xf3\x3c\x1a\x02\xe5\x6b\x2b\x94\x27\x7b\xa3\x65\x28\x55\xb3\x08\xd3\xe4\xe4\x32\x2b\x8c\x8f\xca\xbe\x2f\x08\x36\xc2\x3a\x0f\x37\x77\x6f\x41\x28\xf0\x05\x45\x99\x40\x6f\x20\x93\xc1\x79\xb2\x77\x64\x77\x22\xa3\xca\x37\xe2\xfa\xcd\x74\x00\xbf\x38\xad\x5e\xa3\x2f\x56\xb0\x64\x75\x2f\xc7\x07\xfd\xf4\xe5\xcf\x9d\x71\xc9\x86\x37\x77\x6f\x3b\xef\xfc\x9e\x25\x74\xde\x0a\xb5\x9d\xe2\x18\x8d\xb1\x7a\x87\x12\x4a\x9d\xd3\x04\x2f\x35\xdd\xd1\xb2\xaf\x8e\x3f\x8c\xac\x3d\x3c\x65\x54\xfe\xd0\x94\xbd\x0f\x69\xca\xb5\xd6\x92\x2a\x6f\xa9\x89\x77\x5f\xa1\x34\x05\x7e\x55\xbd\x74\x59\x41\x25\xb6\x46\xd2\x86\xd4\xab\xd7\xb7\x6f\xff\x72\x77\xf0\x01\xfa\xba\xe8\xb8\x1c\xe4\x1c\x85\xe4\xa2\x01\x2b\xc7\x89\xd1\xc3\x86\x44\x70\x14\x2d\xda\x46\xc0\x11\x9b\x7a\xfd\x0b\x65\xbe\xf3\xda\xd2\xaf\x41\x58\xca\xbb\xab\xb3\x46\xea\x18\x3f\x78\xcd\xda\xe9\xbc\x32\x96\xd7\xf2\x9d\x48\x4a\x4f\x27\xc9\xf4\xde\x1f\x48\xf6\x82\xc5\x4f\x74\x3d\xc9\x2a\x87\xa7\xbc\xd2\x19\x0b\xe5\x0b\xe1\xc0\x92\xb1\xe4\x48\xf9\x56\x68\x55\xc9\xb4\x04\x76\x46\xb2\x8e\xa3\x2e\xc8\x9c\x13\xd1\x8e\xac\x07\x4b\x99\xde\x2a\xf1\xdf\x66\x36\x07\x5e\xa7\x08\x40\x4f\xce\x43\x0c\x21\x85\x12\x76\x28\x03\x5d\x01\xaa\x1c\x4a\xdc\x83\x25\x9e\x17\x82\xea\xcc\x10\x49\xdc\x12\xbe\xd3\x96\x0d\xb0\xd1\x2b\x28\xbc\x37\x6e\x75\x7d\xbd\x15\xbe\x4e\xa1\x99\x2e\xcb\xa0\x84\xdf\x5f\xc7\x6c\x28\xd6\x81\xad\x71\x9d\xd3\x8e\xe4\xb5\x13\xdb\x05\xda\xac\x10\x9e\x32\x1f\x2c\x5d\xa3\x11\x8b\xc8\xac\x8a\x69\x74\x59\xe6\x9f\xd9\x2a\xe9\xba\x17\x07\xea\x1b\xf4\x5f\xa8\xf3\xd6\xa4\xae\x39\x7f\x81\x70\xec\x26\x71\x78\x92\xa5\x55\x29\xbf\x62\xad\xbc\xf9\xc7\xdd\x3d\xd4\x0c\x24\xb5\x27\x0d\xb7\xa4\xae\x55\x36\x2b\x4a\xa8\x0d\xd9\x44\xb9\xb1\xba\x8c\xb3\x90\xca\x8d\x16\xca\xc7\x3f\x32\x29\x48\x79\x70\x61\x5d\x0a\xef\xa2\xcf\x91\xf3\x6c\x87\x25\xdc\xc4\x0a\x02\x6b\x82\x60\x72\xf4\x94\x2f\xe1\x56\xc1\x0d\x96\x24\x6f\xd0\xd1\x07\x57\x35\x6b\xd4\x2d\x58\x7d\xf3\x95\xdd\x2d\x80\xc7\x03\x8e\x62\x0c\xa0\x2e\x51\xa3\xd6\xe9\xc4\xf8\x9d\xa1\xac\x89\x86\x26\xa6\x5f\x19\x23\x45\x96\xdc\xbe\xf1\x0e\x76\xe4\x75\x93\x08\x7a\x59\x69\x92\x9d\xb1\xb0\x87\x54\x5e\x8e\xd3\x66\xff\xd3\xd1\x42\xfc\x69\x56\x19\x81\x89\x9c\x01\x31\x6f\xa4\xa5\x8f\xbf\x1c\xe8\xab\x4e\xed\xec\xd0\xec\x61\xc1\x91\x6d\x0b\x86\xd1\x52\x64\x7b\xd8\x68\xcb\xf9\xa1\xa3\xdb\x25\xdc\x7a\x28\x83\x8b\xfe\xa6\x15\xb1\x66\x2f\x5f\x05\xaf\x4b\xf4\x22\xbb\x04\x6d\xe1\xf2\x3b\x54\x01\xe5\xe5\x72\x80\x85\x51\x87\x68\x79\x1f\x52\xe9\x70\x8d\x68\x9f\x71\xd5\x8d\xcf\x85\xd6\xe2\x7e\xe0\xab\xf0\x54\x0e\x0e\x3b\xc1\xfd\x96\x14\x17\x8d\x81\x8c\xdd\x0e\xe5\x44\xb9\x25\x7b\xf4\x3d\x79\xe3\xf8\xb8\x91\x25\xd3\xb0\x06\xe9\x9c\x35\xde\x79\xf4\xe1\x48\xce\x9e\x8b\x5c\x76\x63\x2a\x92\x77\x12\x58\x55\x40\x37\xda\x96\x29\xa6\x70\xad\x43\x4a\x56\x69\x6a\xf6\x0c\xe7\xc9\xb8\x26\x54\x38\xd8\x32\x5d\x1a\x49\xbe\x5f\x7b\x97\xf0\x1f\x05\xd5\x0a\x9c\x0e\xbd\x45\x21\xe3\x54\x98\xf9\x80\x32\xce\x48\x55\x85\xde\x3b\x4f\xe5\xf2\xf2\x79\x22\x35\x43\x8f\x52\x6f\xef\x52\x36\x18\x20\x30\x05\x3a\x3a\x27\xfe\xbc\x27\x15\x38\x0b\x57\xce\xf8\x2a\xcb\x74\x50\xfe\x0d\x6d\x4e\x87\xe4\xf8\x58\xb0\xb4\x21\x4b\x2a\xab\xea\xbb\x4b\x04\x80\x89\x02\x7c\x81\x9e\x23\x39\xb8\xa4\xe6\x5c\x27\x1c\x9c\x37\x50\xa6\x56\xf8\x78\x54\x0e\x2a\xef\x94\xbc\x30\x89\x55\x86\xc5\x7c\x7d\x5b\xe3\x93\x04\x4b\xa8\x96\xce\x0f\x31\x07\xa7\xa2\x80\x9f\x8d\x20\x99\x47\xfc\x39\x87\x83\x17\xb7\x95\x42\x63\x15\xf7\x1a\x10\x8c\xa0\x8c\x7a\x70\x28\x2a\x8c\x30\xaf\x5e\x72\xc1\xb3\x54\x7d\xbb\x4a\xb5\xba\x82\x01\x2d\x5c\xf2\x28\x14\x20\xe3\x02\x91\xc3\xbf\xee\x7e\xf8\xfe\xfa\x9f\x3a\xf1\xc6\x96\x22\xe7\x92\x27\x97\xa4\xfc\x15\xb8\x90\x15\x80\x8e\x59\x63\xf7\x64\xff\xa7\x65\x89\x4a\x6c\xc8\xf9\x65\x35\x1b\x59\xf7\xd3\xcb\x9f\x97\xf0\x8d\xb6\x40\xef\x90\x83\xe7\x0a\x44\xd2\x5a\x03\x2a\x2a\xd7\x88\xa9\x9c\x85\x69\xc6\xc2\xa3\xf0\x45\x64\xc9\xe8\xbc\x62\xfa\x31\x32\xeb\xf1\x81\xf3\x77\x62\x36\x70\x2f\xf3\x40\x2b\xb8\x4c\xad\x49\xb3\xf4\x6f\x0c\xc3\x7f\xbf\x84\xcf\x1f\x0b\xb2\x04\x97\xfc\xe7\x65\x5a\xb0\xc1\x80\xfc\xae\xb6\x63\xbb\x70\x74\x48\x6f\xc5\x76\x4b\x31\xf2\x19\xd0\x30\x68\xf8\x82\x2b\x84\xd8\x80\xd2\x1d\xe2\x38\x05\xeb\xd3\x50\x26\x36\x82\xf2\x23\x46\x7e\x7a\xf9\xf3\x25\x7c\xde\x97\x0b\x84\xca\xe9\x1d\xbc\x4c\xed\x98\x70\x2c\xe3\x17\x4b\xb8\x8f\x96\xd9\x2b\x8f\xef\x78\xce\xac\xd0\x8e\x14\x68\x25\xf7\xcc\x71\x81\x3b\x02\xa7\x4b\x82\x47\x92\x72\x91\x50\x42\x0e\x8f\xb8\x67\x19\x6a\x55\xb2\x55\x11\x0c\x5a\x7f\x80\x90\xef\x7f\xf8\xfa\x87\x55\x5a\x8d\xcd\xb6\x55\xbc\x04\xa3\xaf\x8d\x60\xfc\xcb\xc0\x37\xa1\xb8\x68\x73\x66\x24\x24\x23\x71\xea\x2b\x50\x6d\xa9\x6e\x1e\x37\x81\xf1\xd4\xf2\x10\x31\xcd\xf6\xf8\x21\xb8\x3a\xec\xec\x11\xb6\x1e\x06\xda\x1f\x08\x0a\x67\x8b\x18\x7b\xc0\x59\x22\x7e\xdf\xf1\xc1\x49\x11\x1f\xc2\x9a\xac\x22\x4f\x51\xca\x5c\x67\x8e\x05\xcc\xc8\x78\x77\xad\x77\x9c\x54\xe9\xf1\xfa\x51\xdb\x07\xa1\xb6\x0b\x76\xb2\x45\xb2\xbc\xbb\x8e\xbb\x1f\xd7\x9f\xc5\x7f\xde\x4b\xa2\xd1\x52\x3d\x2c\x56\x24\xff\x18\xb2\xf1\x3a\xee\xfa\xc9\xa2\xd5\x90\xfa\x9c\x4a\xf0\xe2\x2e\x05\x7c\x76\x38\x9a\xc3\xe5\xb1\x10\x59\x51\x37\xad\x9d\x0c\x57\x62\x9e\x52\x20\xaa\xfd\x07\x77\x63\x56\x60\xb0\xbc\xf6\x7e\x51\xed\xcb\x2d\x50\xe5\xfc\x7f\x27\x9c\xe7\xf7\x4f\xd6\x58\x10\x33\x03\xf8\xc7\xdb\xaf\x3f\x8e\x73\x07\xf1\xc4\x68\x5d\x07\x95\x4b\xfa\x56\xeb\x87\x60\x06\x41\x42\x4f\xa0\xbf\x77\xa9\xeb\xfe\xa3\xea\xd2\x84\x5a\x18\xab\xb7\x96\x6b\x65\xa7\xcb\x05\x13\x64\x4a\xaf\x41\x19\xcc\x1e\x70\x4b\xd5\xa2\xb1\x8c\x70\x6f\x5c\x95\xa3\xaa\x15\x18\x87\x39\x4f\xc0\xfd\xa3\xdc\xa7\xdd\x80\x8a\xcf\x11\x36\xeb\xba\xc8\x3c\x46\x04\x5b\xf1\x7d\x9a\xdf\x93\xc0\x6c\x0a\xdb\xa6\xe7\x00\xe1\xbe\xa1\xcd\x28\xa1\xc8\xd9\xef\x37\x62\xa0\x3d\xa9\x49\x0c\xfa\x62\xf4\xa3\x25\x23\x71\x08\x44\xc3\x0c\x08\x09\x47\x7c\x8e\xd1\x1d\x58\xe3\xe6\x60\x58\x6d\x91\x3a\x61\x54\x5a\xee\x91\xc5\x37\x95\x15\x58\x24\x78\x44\x17\x33\x90\xdc\x51\x1e\x37\x60\xc6\x70\xe8\x0c\x8b\xcc\x93\x16\x66\xc1\xe6\x01\x79\x9f\x00\x9e\xbb\x8c\x4f\xa4\xa3\xf4\x9c\x04\xd2\x03\x3c\xfd\x09\xa7\xff\x84\xd3\x9f\x38\x9c\x3e\x2b\x06\xa6\xa0\xf5\x90\xfb\x7f\xaa\x00\xfb\x2c\xa1\xa7\xc0\xf6\x90\xd0\x9f\x08\xe4\x3e\x5b\xc6\x49\xf8\x3d\x26\xe8\x27\x02\xc2\xcf\x12\x76\x26\x20\x1f\x12\xf9\xff\x19\x96\x9f\xa5\xc3\x09\x88\x3e\xa4\xb7\x4f\x02\xa8\xcf\x16\x30\xd3\x2a\x9d\x82\x4f\xa0\x94\x3e\xd6\x6a\x06\x1c\xee\x03\x33\xd3\x28\x7b\xfb\xb4\x5d\x98\x7c\x0a\x4e\x8d\x41\xf2\xf4\x4c\x00\xf3\xee\x24\x27\x30\xd9\x69\xac\x9c\x9e\x45\xb5\x7d\x7d\x82\x88\xd7\x9c\x20\x99\x87\x00\x01\x24\x3a\x7f\x6f\x51\x39\x51\xdf\xe0\x98\xa6\x3f\xb0\xc8\xb7\xc8\x6d\x87\x28\x9b\x2e\x23\xd9\x07\x7c\x33\x65\x05\x68\xe3\x51\x4d\xb5\x2f\xcf\x98\x46\x69\x5f\x8c\x35\x1d\xed\x33\x33\x4a\xf8\x49\xe7\x00\x2b\xc8\xd1\xd3\x82\x39\x3a\x29\xf6\x8f\xf1\xb0\xf2\xd9\x44\x66\x0c\x6f\xac\x5e\x53\xfe\x87\x49\x55\x92\x73\xb8\x3d\x4f\x9c\x57\x50\x84\x12\x15\x58\xc2\x1c\xd7\x92\xea\x49\x18\x8d\xc5\xd3\x4a\xb5\x85\x9c\x3c\x0a\xe9\x3a\x27\x2c\xad\x7d\x9f\x4d\x58\x4b\xe8\x4e\x55\x09\x38\xbe\x62\x92\x86\xc5\x83\xc2\x9e\x3d\x5e\xb8\x68\xe4\x0f\xc1\xe9\xf0\xc9\xd5\x24\xa7\x77\xcd\x89\x54\x8f\xc9\xab\xfa\x04\xf3\xde\x06\xba\x82\x6f\x50\x3a\xba\x82\x1f\xd5\x83\xd2\x8f\xcf\xc7\x6f\x24\x3c\x4b\xaf\x7b\x13\xb9\x6a\xf8\x7c\x06\x56\xda\xee\x7e\x66\xb2\xbf\x6d\x06\xd4\x3b\x34\x55\x87\xbe\x08\x4a\xfc\x1a\xfa\x8d\x4a\x73\xc8\xf4\xf9\x61\x0b\x73\x73\xf7\x36\x3a\x47\x6a\xb7\x5d\x6a\x64\xea\xd6\xee\xe6\xee\xad\xfb\xe2\x44\x6d\x98\x94\xca\x4c\x36\xaa\x3d\x79\xb8\xa7\x3d\x68\xb5\xa4\xce\x3a\x57\x7f\xda\x6d\x19\x13\xa4\x5c\xc2\xad\x7f\xe1\x98\x07\x91\xa1\x94\x7b\xee\x5a\x44\xc9\x81\xd9\xa0\x9e\x53\x55\x6d\x9a\xf3\x19\x05\xe2\x28\xd8\x68\xb3\xa1\xcc\x8b\x1d\x75\x86\xd7\x8a\x4e\x1b\x4e\x94\x57\x72\xbc\x17\x73\xf5\x56\xce\x4c\xd6\xde\x54\xe4\xb5\xa3\x74\xed\xdf\x6a\xb5\x9a\x34\xf5\x9a\xd1\x69\x14\xc1\x46\x07\x95\x03\xfa\x68\x9e\x27\xf2\xdc\x3f\xc3\xfd\x78\x07\xfe\xd3\xf8\xe9\x79\x36\x1b\x3b\x27\xf0\x0d\xfa\x9a\x02\x5f\x6d\x92\xa3\x77\x94\x85\xce\x1d\xaf\xee\x1d\x8e\xa7\xed\x35\x9e\x76\xd9\x73\xd0\xcc\xac\xf4\x39\xb7\xfe\xce\xc5\x13\xcf\xba\xe8\xc9\x72\x3f\x2b\xd2\xa6\xab\xee\x30\xfe\x7e\x93\x8a\x6e\xdc\xea\xcc\xb0\x24\x99\xa1\xa3\xfc\xb0\x16\x27\x30\x3e\xa7\x00\xcf\x60\xf4\x54\xd1\x9d\x31\xc5\x74\x1d\x3c\xe9\xf6\xb1\x2a\x26\xaa\x75\x7d\x0b\xa2\x69\x37\x7a\xfe\xcd\xf9\x04\x21\x23\x1b\x8b\x4c\xba\x44\x87\xac\xab\xc7\x42\x3f\x39\x33\x4e\x58\xbb\xc7\xfa\x77\x35\x7e\xe3\x05\x23\xb6\x5b\x1c\x61\xbb\xaa\xfe\xb5\xd8\x8e\xf2\xde\x55\x9a\x58\x24\x4b\xdc\xc7\xab\x69\xa5\xd1\xd6\x63\x3a\xe0\x08\x2a\x27\xeb\x3c\xaa\x9c\xc7\x3e\x16\xfb\xa8\x06\xc3\x32\x17\xe8\x40\x78\x07\xa9\x2f\xf6\x95\xc1\xce\xbe\x83\x15\xef\xbb\x9c\x14\xb2\xa3\xec\xd7\x3c\xa0\x81\x08\xbd\xc5\x53\x5d\xed\x19\x66\xd2\x0a\xd3\x8c\x49\x9c\xb8\x58\xf5\xbe\x79\xf6\xce\x93\x39\xcc\xab\x1d\x21\x54\x84\xe3\x3b\x91\xa7\xcb\x48\x64\x40\xa8\xe7\x49\xaa\xa7\x0f\x70\xd2\xc1\xc4\x78\x58\x2d\x9a\x5d\x9a\x51\x82\x89\x8e\xf6\x74\x52\x6f\xd6\x7f\xcf\x44\x37\x7e\xc7\x2d\x3d\x47\xf6\xa8\x7f\x37\x31\x61\x97\xce\x2d\xdb\x78\x8f\xd3\xdb\x0a\x03\xed\x67\x59\x07\xe6\x6e\x1e\xcc\xd9\x3a\x58\xa4\x9f\x4f\x4c\x52\x3c\x08\x75\x7c\xf3\xb3\x4b\xc0\xd0\x69\x92\xa0\xbd\xf2\x37\x93\x2c\x6e\x29\x4e\xd2\x56\xc7\x49\xef\x79\x9a\x95\x7e\x3b\xf2\x71\xb6\xdf\x67\x4e\x54\x1f\xfe\x3c\xcb\x64\xa7\xf7\xc7\x67\x4e\xd4\x9a\xe6\x99\xa7\x9b\xb1\xb3\x3d\x73\xce\xdd\x9c\x2d\xe3\x67\x00\x0d\x47\x21\x5f\xf5\xe9\x13\xd5\xc4\xa0\xf5\x22\x0b\x12\x6d\x1b\xfb\x31\x3d\x1f\xfd\xe2\xe8\x6c\x9e\x9d\x47\xeb\xc7\xf0\xe3\xe1\x76\x42\xa2\xac\x39\x8d\xfb\x51\x8f\x05\xa9\xe6\xd8\x2e\xfd\x80\x0b\xd6\xb4\xe5\xb2\x67\x8c\xdc\xd7\xbf\x0e\x68\xef\x9e\x4b\xe1\x7c\xac\xfc\x6d\x15\x9f\x7b\x89\x61\x54\xed\x63\xe0\xd5\x91\xdd\x51\xbe\x02\x6f\x43\xf3\xca\x6b\xcb\x88\xa6\xf7\x2e\xac\x1b\xfe\x5a\x35\x54\x76\x84\xdf\x7e\xbf\xf8\x5f\x00\x00\x00\xff\xff\xaa\x07\xfe\xc9\xfd\x36\x00\x00") +var _operatorsCoreosCom_installplansYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\xdd\x6f\x1b\x37\x12\x7f\xf7\x5f\x31\x70\x1f\xd2\x02\x96\xdc\xe6\x80\xc3\x41\x6f\x39\xf7\x7a\xf0\x5d\x3f\x82\xd8\xcd\x4b\xaf\x0f\xa3\xdd\x91\x96\x35\x97\x64\xf9\x21\x47\x57\xf4\x7f\x3f\x0c\xb9\x9f\xd2\xee\x6a\xe5\x38\x69\x70\xe8\xbe\x24\xde\x1d\x92\xf3\x3d\xbf\x21\x29\x34\xe2\x2d\x59\x27\xb4\x5a\x01\x1a\x41\xef\x3c\x29\xfe\xcb\x2d\x1f\xfe\xe6\x96\x42\x5f\xef\xbe\xba\x78\x10\x2a\x5f\xc1\x4d\x70\x5e\x97\x6f\xc8\xe9\x60\x33\xfa\x9a\x36\x42\x09\x2f\xb4\xba\x28\xc9\x63\x8e\x1e\x57\x17\x00\xa8\x94\xf6\xc8\xaf\x1d\xff\x09\x90\x69\xe5\xad\x96\x92\xec\x62\x4b\x6a\xf9\x10\xd6\xb4\x0e\x42\xe6\x64\xe3\xe4\xf5\xd2\xbb\x2f\x97\x7f\x5d\xbe\xbc\x00\xc8\x2c\xc5\xe1\xf7\xa2\x24\xe7\xb1\x34\x2b\x50\x41\xca\x0b\x00\x85\x25\xad\x40\x28\xe7\x51\x4a\x23\x51\xb9\xa5\x36\x64\xd1\x6b\xeb\x96\x99\xb6\xa4\xf9\x9f\xf2\xc2\x19\xca\x78\xed\xad\xd5\xc1\xac\x60\x90\x26\xcd\x56\xb3\x88\x9e\xb6\xda\x8a\xfa\x6f\x80\x05\x68\x59\xc6\xff\x27\xd1\x6f\xd3\xa2\xaf\x25\xaa\xf8\x56\x0a\xe7\xff\x7d\xf8\xe5\x5b\xe1\x7c\xfc\x6a\x64\xb0\x28\xfb\xac\xc6\x0f\xae\xd0\xd6\x7f\xdf\x2e\xcc\x0b\x09\x93\x3e\x09\xb5\x0d\x12\x6d\x6f\xd4\x05\x80\xcb\xb4\xa1\x15\xc4\x41\x06\x33\xca\x2f\x00\x2a\xa5\x55\x93\x2c\x00\xf3\x3c\x1a\x02\xe5\x6b\x2b\x94\x27\x7b\xa3\x65\x28\x55\xb3\x08\xd3\xe4\xe4\x32\x2b\x8c\x8f\xca\xbe\x2f\x08\x36\xc2\x3a\x0f\x37\x77\x6f\x41\x28\xf0\x05\x45\x99\x40\x6f\x20\x93\xc1\x79\xb2\x77\x64\x77\x22\xa3\xca\x37\xe2\xfa\xcd\x74\x00\xbf\x38\xad\x5e\xa3\x2f\x56\xb0\x64\x75\x2f\xc7\x07\xfd\xf4\xe5\xcf\x9d\x71\xc9\x86\x37\x77\x6f\x3b\xef\xfc\x9e\x25\x74\xde\x0a\xb5\x9d\xe2\x18\x8d\xb1\x7a\x87\x12\x4a\x9d\xd3\x04\x2f\x35\xdd\xd1\xb2\xaf\x8e\x3f\x8c\xac\x3d\x3c\x65\x54\xfe\xd0\x94\xbd\x0f\x69\xca\xb5\xd6\x92\x2a\x6f\xa9\x89\x77\x5f\xa1\x34\x05\x7e\x55\xbd\x74\x59\x41\x25\xb6\x46\xd2\x86\xd4\xab\xd7\xb7\x6f\xff\x72\x77\xf0\x01\xfa\xba\xe8\xb8\x1c\xe4\x1c\x85\xe4\xa2\x01\x2b\xc7\x89\xd1\xc3\x86\x44\x70\x14\x2d\xda\x46\xc0\x11\x9b\x7a\xfd\x0b\x65\xbe\xf3\xda\xd2\xaf\x41\x58\xca\xbb\xab\xb3\x46\xea\x18\x3f\x78\xcd\xda\xe9\xbc\x32\x96\xd7\xf2\x9d\x48\x4a\x4f\x27\xc9\xf4\xde\x1f\x48\xf6\x82\xc5\x4f\x74\x3d\xc9\x2a\x87\xa7\xbc\xd2\x19\x0b\xe5\x0b\xe1\xc0\x92\xb1\xe4\x48\xf9\x56\x68\x55\xc9\xb4\x04\x76\x46\xb2\x8e\xa3\x2e\xc8\x9c\x13\xd1\x8e\xac\x07\x4b\x99\xde\x2a\xf1\xdf\x66\x36\x07\x5e\xa7\x08\x40\x4f\xce\x43\x0c\x21\x85\x12\x76\x28\x03\x5d\x01\xaa\x1c\x4a\xdc\x83\x25\x9e\x17\x82\xea\xcc\x10\x49\xdc\x12\xbe\xd3\x96\x0d\xb0\xd1\x2b\x28\xbc\x37\x6e\x75\x7d\xbd\x15\xbe\x4e\xa1\x99\x2e\xcb\xa0\x84\xdf\x5f\xc7\x6c\x28\xd6\x81\xad\x71\x9d\xd3\x8e\xe4\xb5\x13\xdb\x05\xda\xac\x10\x9e\x32\x1f\x2c\x5d\xa3\x11\x8b\xc8\xac\x8a\x69\x74\x59\xe6\x9f\xd9\x2a\xe9\xba\x17\x07\xea\x1b\xf4\x5f\xa8\xf3\xd6\xa4\xae\x39\x7f\x81\x70\xec\x26\x71\x78\x92\xa5\x55\x29\xbf\x62\xad\xbc\xf9\xc7\xdd\x3d\xd4\x0c\x24\xb5\x27\x0d\xb7\xa4\xae\x55\x36\x2b\x4a\xa8\x0d\xd9\x44\xb9\xb1\xba\x8c\xb3\x90\xca\x8d\x16\xca\xc7\x3f\x32\x29\x48\x79\x70\x61\x5d\x0a\xef\xa2\xcf\x91\xf3\x6c\x87\x25\xdc\xc4\x0a\x02\x6b\x82\x60\x72\xf4\x94\x2f\xe1\x56\xc1\x0d\x96\x24\x6f\xd0\xd1\x07\x57\x35\x6b\xd4\x2d\x58\x7d\xf3\x95\xdd\x2d\x80\xc7\x03\x8e\x62\x0c\xa0\x2e\x51\xa3\xd6\xe9\xc4\xf8\x9d\xa1\xac\x89\x86\x26\xa6\x5f\x19\x23\x45\x96\xdc\xbe\xf1\x0e\x76\xe4\x75\x93\x08\x7a\x59\x69\x92\x9d\xb1\xb0\x87\x54\x5e\x8e\xd3\x66\xff\xd3\xd1\x42\xfc\x69\x56\x19\x81\x89\x9c\x01\x31\x6f\xa4\xa5\x8f\xbf\x1c\xe8\xab\x4e\xed\xec\xd0\xec\x61\xc1\x91\x6d\x0b\x86\xd1\x52\x64\x7b\xd8\x68\xcb\xf9\xa1\xa3\xdb\x25\xdc\x7a\x28\x83\x8b\xfe\xa6\x15\xb1\x66\x2f\x5f\x05\xaf\x4b\xf4\x22\xbb\x04\x6d\xe1\xf2\x3b\x54\x01\xe5\xe5\x72\x80\x85\x51\x87\x68\x79\x1f\x52\xe9\x70\x8d\x68\x9f\x71\xd5\x8d\xcf\x85\xd6\xe2\x7e\xe0\xab\xf0\x54\x0e\x0e\x3b\xc1\xfd\x96\x14\x17\x8d\x81\x8c\xdd\x0e\xe5\x44\xb9\x25\x7b\xf4\x3d\x79\xe3\xf8\xb8\x91\x25\xd3\xb0\x06\xe9\x9c\x35\xde\x79\xf4\xe1\x48\xce\x9e\x8b\x5c\x76\x63\x2a\x92\x77\x12\x58\x55\x40\x37\xda\x96\x29\xa6\x70\xad\x43\x4a\x56\x69\x6a\xf6\x0c\xe7\xc9\xb8\x26\x54\x38\xd8\x32\x5d\x1a\x49\xbe\x5f\x7b\x97\xf0\x1f\x05\xd5\x0a\x9c\x0e\xbd\x45\x21\xe3\x54\x98\xf9\x80\x32\xce\x48\x55\x85\xde\x3b\x4f\xe5\xf2\xf2\x79\x22\x35\x43\x8f\x52\x6f\xef\x52\x36\x18\x20\x30\x05\x3a\x3a\x27\xfe\xbc\x27\x15\x38\x0b\x57\xce\xf8\x2a\xcb\x74\x50\xfe\x0d\x6d\x4e\x87\xe4\xf8\x58\xb0\xb4\x21\x4b\x2a\xab\xea\xbb\x4b\x04\x80\x89\x02\x7c\x81\x9e\x23\x39\xb8\xa4\xe6\x5c\x27\x1c\x9c\x37\x50\xa6\x56\xf8\x78\x54\x0e\x2a\xef\x94\xbc\x30\x89\x55\x86\xc5\x7c\x7d\x5b\xe3\x93\x04\x4b\xa8\x96\xce\x0f\x31\x07\xa7\xa2\x80\x9f\x8d\x20\x99\x47\xfc\x39\x87\x83\x17\xb7\x95\x42\x63\x15\xf7\x1a\x10\x8c\xa0\x8c\x7a\x70\x28\x2a\x8c\x30\xaf\x5e\x72\xc1\xb3\x54\x7d\xbb\x4a\xb5\xba\x82\x01\x2d\x5c\xf2\x28\x14\x20\xe3\x02\x91\xc3\xbf\xee\x7e\xf8\xfe\xfa\x9f\x3a\xf1\xc6\x96\x22\xe7\x92\x27\x97\xa4\xfc\x15\xb8\x90\x15\x80\x8e\x59\x63\xf7\x64\xff\xa7\x65\x89\x4a\x6c\xc8\xf9\x65\x35\x1b\x59\xf7\xd3\xcb\x9f\x97\xf0\x8d\xb6\x40\xef\x90\x83\xe7\x0a\x44\xd2\x5a\x03\x2a\x2a\xd7\x88\xa9\x9c\x85\x69\xc6\xc2\xa3\xf0\x45\x64\xc9\xe8\xbc\x62\xfa\x31\x32\xeb\xf1\x81\xf3\x77\x62\x36\x70\x2f\xf3\x40\x2b\xb8\x4c\xad\x49\xb3\xf4\x6f\x0c\xc3\x7f\xbf\x84\xcf\x1f\x0b\xb2\x04\x97\xfc\xe7\x65\x5a\xb0\xc1\x80\xfc\xae\xb6\x63\xbb\x70\x74\x48\x6f\xc5\x76\x4b\x31\xf2\x19\xd0\x30\x68\xf8\x82\x2b\x84\xd8\x80\xd2\x1d\xe2\x38\x05\xeb\xd3\x50\x26\x36\x82\xf2\x23\x46\x7e\x7a\xf9\xf3\x25\x7c\xde\x97\x0b\x84\xca\xe9\x1d\xbc\x4c\xed\x98\x70\x2c\xe3\x17\x4b\xb8\x8f\x96\xd9\x2b\x8f\xef\x78\xce\xac\xd0\x8e\x14\x68\x25\xf7\xcc\x71\x81\x3b\x02\xa7\x4b\x82\x47\x92\x72\x91\x50\x42\x0e\x8f\xb8\x67\x19\x6a\x55\xb2\x55\x11\x0c\x5a\x7f\x80\x90\xef\x7f\xf8\xfa\x87\x55\x5a\x8d\xcd\xb6\x55\xbc\x04\xa3\xaf\x8d\x60\xfc\xcb\xc0\x37\xa1\xb8\x68\x73\x66\x24\x24\x23\x71\xea\x2b\x50\x6d\xa9\x6e\x1e\x37\x81\xf1\xd4\xf2\x10\x31\xcd\xf6\xf8\x21\xb8\x3a\xec\xec\x11\xb6\x1e\x06\xda\x1f\x08\x0a\x67\x8b\x18\x7b\xc0\x59\x22\x7e\xdf\xf1\xc1\x49\x11\x1f\xc2\x9a\xac\x22\x4f\x51\xca\x5c\x67\x8e\x05\xcc\xc8\x78\x77\xad\x77\x9c\x54\xe9\xf1\xfa\x51\xdb\x07\xa1\xb6\x0b\x76\xb2\x45\xb2\xbc\xbb\x8e\xbb\x1f\xd7\x9f\xc5\x7f\xde\x4b\xa2\xd1\x52\x3d\x2c\x56\x24\xff\x18\xb2\xf1\x3a\xee\xfa\xc9\xa2\xd5\x90\xfa\x9c\x4a\xf0\xe2\x2e\x05\x7c\x76\x38\x9a\xc3\xe5\xb1\x10\x59\x51\x37\xad\x9d\x0c\x57\x62\x9e\x52\x20\xaa\xfd\x07\x77\x63\x56\x60\xb0\xbc\xf6\x7e\x51\xed\xcb\x2d\x50\xe5\xfc\x7f\x27\x9c\xe7\xf7\x4f\xd6\x58\x10\x33\x03\xf8\xc7\xdb\xaf\x3f\x8e\x73\x07\xf1\xc4\x68\x5d\x07\x95\x4b\xfa\x56\xeb\x87\x60\x06\x41\x42\x4f\xa0\xbf\x77\xa9\xeb\xfe\xa3\xea\xd2\x84\x5a\x18\xab\xb7\x96\x6b\x65\xa7\xcb\x05\x13\x64\x4a\xaf\x41\x19\xcc\x1e\x70\x4b\xd5\xa2\xb1\x8c\x70\x6f\x5c\x95\xa3\xaa\x15\x18\x87\x39\x4f\xc0\xfd\xa3\xdc\xa7\xdd\x80\x8a\xcf\x11\x36\xeb\xba\xc8\x3c\x46\x04\x5b\xf1\x7d\x9a\xdf\x93\xc0\x6c\x0a\xdb\xa6\xe7\x00\xe1\xbe\xa1\xcd\x28\xa1\xc8\xd9\xef\x37\x62\xa0\x3d\xa9\x49\x0c\xfa\x62\xf4\xa3\x25\x23\x71\x08\x44\xc3\x0c\x08\x09\x47\x7c\x8e\xd1\x1d\x58\xe3\xe6\x60\x58\x6d\x91\x3a\x61\x54\x5a\xee\x91\xc5\x37\x95\x15\x58\x24\x78\x44\x17\x33\x90\xdc\x51\x1e\x37\x60\xc6\x70\xe8\x0c\x8b\xcc\x93\x16\x66\xc1\xe6\x01\x79\x9f\x00\x9e\xbb\x8c\x4f\xa4\xa3\xf4\x9c\x04\xd2\x03\x3c\xfd\x09\xa7\xff\x84\xd3\x9f\x38\x9c\x3e\x2b\x06\xa6\xa0\xf5\x90\xfb\x7f\xaa\x00\xfb\x2c\xa1\xa7\xc0\xf6\x90\xd0\x9f\x08\xe4\x3e\x5b\xc6\x49\xf8\x3d\x26\xe8\x27\x02\xc2\xcf\x12\x76\x26\x20\x1f\x12\xf9\xff\x19\x96\x9f\xa5\xc3\x09\x88\x3e\xa4\xb7\x4f\x02\xa8\xcf\x16\x30\xd3\x2a\x9d\x82\x4f\xa0\x94\x3e\xd6\x6a\x06\x1c\xee\x03\x33\xd3\x28\x7b\xfb\xb4\x5d\x98\x7c\x0a\x4e\x8d\x41\xf2\xf4\x4c\x00\xf3\xee\x24\x27\x30\xd9\x69\xac\x9c\x9e\x45\xb5\x7d\x7d\x82\x88\xd7\x9c\x20\x99\x87\x00\x01\x24\x3a\x7f\x6f\x51\x39\x51\xdf\xe0\x98\xa6\x3f\xb0\xc8\xb7\xc8\x6d\x87\x28\x9b\x2e\x23\xd9\x07\x7c\x33\x65\x05\x68\xe3\x51\x4d\xb5\x2f\xcf\x98\x46\x69\x5f\x8c\x35\x1d\xed\x33\x33\x4a\xf8\x49\xe7\x00\x2b\xc8\xd1\xd3\x82\x39\x3a\x29\xf6\x8f\xf1\xb0\xf2\xd9\x44\x66\x0c\x6f\xac\x5e\x53\xfe\x87\x49\x55\x92\x73\xb8\x3d\x4f\x9c\x57\x50\x84\x12\x15\x58\xc2\x1c\xd7\x92\xea\x49\x18\x8d\xc5\xd3\x4a\xb5\x85\x9c\x3c\x0a\xe9\x3a\x27\x2c\xad\x7d\x9f\x4d\x58\x4b\xe8\x4e\x55\x09\x38\xbe\x62\x92\x86\xc5\x83\xc2\x9e\x3d\x5e\xb8\x68\xe4\x0f\xc1\xe9\xf0\xc9\xd5\x24\xa7\x77\xcd\x89\x54\x8f\xc9\xab\xfa\x04\xf3\xde\x06\xba\x82\x6f\x50\x3a\xba\x82\x1f\xd5\x83\xd2\x8f\xcf\xc7\x6f\x24\x3c\x4b\xaf\x7b\x13\xb9\x6a\xf8\x7c\x06\x56\xda\xee\x7e\x66\xb2\xbf\x6d\x06\xd4\x3b\x34\x55\x87\xbe\x08\x4a\xfc\x1a\xfa\x8d\x4a\x73\xc8\xf4\xf9\x61\x0b\x73\x73\xf7\x36\x3a\x47\x6a\xb7\x5d\x6a\x64\xea\xd6\xee\xe6\xee\xad\xfb\xe2\x44\x6d\x98\x94\xca\x4c\x36\xaa\x3d\x79\xb8\xa7\x3d\x68\xb5\xa4\xce\x3a\x57\x7f\xda\x6d\x19\x13\xa4\x5c\xc2\xad\x7f\xe1\x98\x07\x91\xa1\x94\x7b\xee\x5a\x44\xc9\x81\xd9\xa0\x9e\x53\x55\x6d\x9a\xf3\x19\x05\xe2\x28\xd8\x68\xb3\xa1\xcc\x8b\x1d\x75\x86\xd7\x8a\x4e\x1b\x4e\x94\x57\x72\xbc\x17\x73\xf5\x56\xce\x4c\xd6\xde\x54\xe4\xb5\xa3\x74\xed\xdf\x6a\xb5\x9a\x34\xf5\x9a\xd1\x69\x14\xc1\x46\x07\x95\x03\xfa\x68\x9e\x27\xf2\xdc\x3f\xc3\xfd\x78\x07\xfe\xd3\xf8\xe9\x79\x36\x1b\x3b\x27\xf0\x0d\xfa\x9a\x02\x5f\x6d\x92\xa3\x77\x94\x85\xce\x1d\xaf\xee\x1d\x8e\xa7\xed\x35\x9e\x76\xd9\x73\xd0\xcc\xac\xf4\x39\xb7\xfe\xce\xc5\x13\xcf\xba\xe8\xc9\x72\x3f\x2b\xd2\xa6\xab\xee\x30\xfe\x7e\x93\x8a\x6e\xdc\xea\xcc\xb0\x24\x99\xa1\xa3\xfc\xb0\x16\x27\x30\x3e\xa7\x00\xcf\x60\xf4\x54\xd1\x9d\x31\xc5\x74\x1d\x3c\xe9\xf6\xb1\x2a\x26\xaa\x75\x7d\x0b\xa2\x69\x37\x7a\xfe\xcd\xf9\x04\x21\x23\x1b\x8b\x4c\xba\x44\x87\xac\xab\xc7\x42\x3f\x39\x33\x4e\x58\xbb\xc7\xfa\x77\x35\x7e\xe3\x05\x23\xb6\x5b\x1c\x61\xbb\xaa\xfe\xb5\xd8\x8e\xf2\xde\x55\x9a\x58\x24\x4b\xdc\xc7\xab\x69\xa5\xd1\xd6\x63\x3a\xe0\x08\x2a\x27\xeb\x3c\xaa\x9c\xc7\x3e\x16\xfb\xa8\x06\xc3\x32\x17\xe8\x40\x78\x07\xa9\x2f\xf6\x95\xc1\xce\xbe\x83\x15\xef\xbb\x9c\x14\xb2\xa3\xec\xd7\x3c\xa0\x81\x08\xbd\xc5\x53\x5d\xed\x19\x66\xd2\x0a\xd3\x8c\x49\x9c\xb8\x58\xf5\xbe\x79\xf6\xce\x93\x39\xcc\xab\x1d\x21\x54\x84\xe3\x3b\x91\xa7\xcb\x48\x64\x40\xa8\xe7\x49\xaa\xa7\x0f\x70\xd2\xc1\xc4\x78\x58\x2d\x9a\x5d\x9a\x51\x82\x89\x8e\xf6\x74\x52\xd7\x26\xdd\x94\x3f\x15\xfb\x63\x77\xf3\xd2\xd3\x48\xf1\x9e\xe9\x72\xfc\xa6\x5c\x7a\x8e\xac\x5a\xff\xfa\x62\xc2\xba\x9d\xbb\xba\xf1\x36\xa8\xb7\x15\x92\xda\xcf\xb2\x31\xcc\xdd\x82\x98\xb3\x01\xb1\x48\x3f\xc2\x98\xa4\x78\x10\xea\xf8\xfe\x68\x97\x80\x01\xd8\x24\x41\x7b\x71\x70\x26\x59\xdc\x98\x9c\xa4\xad\x0e\xa5\xde\xf3\x4c\x2c\xfd\x02\xe5\xe3\x6c\xe2\xcf\x9c\xa8\x3e\x42\x7a\x96\xc9\x4e\xef\xb2\xcf\x9c\xa8\x35\xcd\x33\x4f\x37\x63\x7f\x7c\xe6\x9c\xbb\x39\x1b\xcf\xcf\x00\x3d\x8e\x42\xbe\xea\xf6\x27\x6a\x92\x41\xeb\x45\x16\x24\xda\x36\xf6\x63\x92\x3f\xfa\xdd\xd2\xd9\x3c\x3b\x8f\xd6\x8f\xa1\xd0\xc3\x4d\x89\x44\x59\x73\x1a\x77\xb5\x1e\x0b\x52\xcd\xe1\x5f\xfa\x19\x18\xac\x69\xcb\xc5\xd3\x18\xb9\xaf\x7f\x63\xd0\xde\x60\x97\xc2\xf9\x88\x1f\x5a\x2c\x30\xf7\x2a\xc4\xa8\xda\xc7\x20\xb0\x23\xbb\xa3\x7c\x05\xde\x86\xe6\x95\xd7\x96\x71\x51\xef\x5d\x58\x37\xfc\xb5\x6a\xa8\xec\x08\xbf\xfd\x7e\xf1\xbf\x00\x00\x00\xff\xff\xf1\x28\xdb\xb0\x43\x37\x00\x00") func operatorsCoreosCom_installplansYamlBytes() ([]byte, error) { return bindataRead( diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go index 26afb9d0308..89a3007bc1c 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/installplan_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/installplan_types.go index 6b56a5d7278..5210436d982 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/installplan_types.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/installplan_types.go @@ -71,6 +71,7 @@ const ( StepStatusNotPresent StepStatus = "NotPresent" StepStatusPresent StepStatus = "Present" StepStatusCreated StepStatus = "Created" + StepStatusNotCreated StepStatus = "NotCreated" StepStatusWaitingForAPI StepStatus = "WaitingForApi" StepStatusUnsupportedResource StepStatus = "UnsupportedResource" ) @@ -227,6 +228,7 @@ func ConditionMet(cond InstallPlanConditionType, now *metav1.Time) InstallPlanCo type Step struct { Resolving string `json:"resolving"` Resource StepResource `json:"resource"` + Optional bool `json:"optional,omitempty"` Status StepStatus `json:"status"` } diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go index 080b350ee7c..c094738eed1 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha2/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha2/zz_generated.deepcopy.go index 807a963162b..3d81e86ed47 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha2/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha2/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go index 06fbb625a1d..8f7498c356a 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/vendor/github.com/operator-framework/operator-registry/internal/model/error.go b/vendor/github.com/operator-framework/operator-registry/alpha/model/error.go similarity index 100% rename from vendor/github.com/operator-framework/operator-registry/internal/model/error.go rename to vendor/github.com/operator-framework/operator-registry/alpha/model/error.go diff --git a/vendor/github.com/operator-framework/operator-registry/internal/model/model.go b/vendor/github.com/operator-framework/operator-registry/alpha/model/model.go similarity index 81% rename from vendor/github.com/operator-framework/operator-registry/internal/model/model.go rename to vendor/github.com/operator-framework/operator-registry/alpha/model/model.go index 330ea84db19..75042469a28 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/model/model.go +++ b/vendor/github.com/operator-framework/operator-registry/alpha/model/model.go @@ -3,14 +3,17 @@ package model import ( "errors" "fmt" + "sort" "strings" + "github.com/blang/semver/v4" "github.com/h2non/filetype" "github.com/h2non/filetype/matchers" "github.com/h2non/filetype/types" svg "github.com/h2non/go-is-svg" + "k8s.io/apimachinery/pkg/util/sets" - "github.com/operator-framework/operator-registry/internal/property" + "github.com/operator-framework/operator-registry/alpha/property" ) func init() { @@ -160,6 +163,7 @@ func (c Channel) Head() (*Bundle, error) { for _, head := range heads { headNames = append(headNames, head.Name) } + sort.Strings(headNames) return nil, fmt.Errorf("multiple channel heads found in graph: %s", strings.Join(headNames, ", ")) } return heads[0], nil @@ -181,7 +185,7 @@ func (c *Channel) Validate() error { } if len(c.Bundles) > 0 { - if _, err := c.Head(); err != nil { + if err := c.validateReplacesChain(); err != nil { result.subErrors = append(result.subErrors, err) } } @@ -200,6 +204,51 @@ func (c *Channel) Validate() error { return result.orNil() } +// validateReplacesChain checks the replaces chain of a channel. +// Specifically the following rules must be followed: +// 1. There must be exactly 1 channel head. +// 2. Beginning at the head, the replaces chain must reach all non-skipped entries. +// Non-skipped entries are defined as entries that are not skipped by any other entry in the channel. +// 3. There must be no cycles in the replaces chain. +// 4. The tail entry in the replaces chain is permitted to replace a non-existent entry. +func (c *Channel) validateReplacesChain() error { + head, err := c.Head() + if err != nil { + return err + } + + allBundles := sets.NewString() + skippedBundles := sets.NewString() + for _, b := range c.Bundles { + allBundles = allBundles.Insert(b.Name) + skippedBundles = skippedBundles.Insert(b.Skips...) + } + + chainFrom := map[string][]string{} + replacesChainFromHead := sets.NewString(head.Name) + cur := head + for cur != nil { + if _, ok := chainFrom[cur.Name]; !ok { + chainFrom[cur.Name] = []string{cur.Name} + } + for k := range chainFrom { + chainFrom[k] = append(chainFrom[k], cur.Replaces) + } + if replacesChainFromHead.Has(cur.Replaces) { + return fmt.Errorf("detected cycle in replaces chain of upgrade graph: %s", strings.Join(chainFrom[cur.Replaces], " -> ")) + } + replacesChainFromHead = replacesChainFromHead.Insert(cur.Replaces) + cur = c.Bundles[cur.Replaces] + } + + strandedBundles := allBundles.Difference(replacesChainFromHead).Difference(skippedBundles).List() + if len(strandedBundles) > 0 { + return fmt.Errorf("channel contains one or more stranded bundles: %s", strings.Join(strandedBundles, ", ")) + } + + return nil +} + type Bundle struct { Package *Package Channel *Channel @@ -207,6 +256,7 @@ type Bundle struct { Image string Replaces string Skips []string + SkipRange string Properties []property.Property RelatedImages []RelatedImage @@ -215,6 +265,10 @@ type Bundle struct { // backwards-compatible way. Objects []string CsvJSON string + + // These fields are used to compare bundles in a diff. + PropertiesP *property.Properties + Version semver.Version } func (b *Bundle) Validate() error { diff --git a/vendor/github.com/operator-framework/operator-registry/internal/property/errors.go b/vendor/github.com/operator-framework/operator-registry/alpha/property/errors.go similarity index 100% rename from vendor/github.com/operator-framework/operator-registry/internal/property/errors.go rename to vendor/github.com/operator-framework/operator-registry/alpha/property/errors.go diff --git a/vendor/github.com/operator-framework/operator-registry/internal/property/property.go b/vendor/github.com/operator-framework/operator-registry/alpha/property/property.go similarity index 80% rename from vendor/github.com/operator-framework/operator-registry/internal/property/property.go rename to vendor/github.com/operator-framework/operator-registry/alpha/property/property.go index 5f535eea36d..c8bc6ad78e6 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/property/property.go +++ b/vendor/github.com/operator-framework/operator-registry/alpha/property/property.go @@ -44,11 +44,6 @@ type PackageRequired struct { VersionRange string `json:"versionRange"` } -type Channel struct { - Name string `json:"name"` - Replaces string `json:"replaces,omitempty"` -} - type GVK struct { Group string `json:"group"` Kind string `json:"kind"` @@ -61,9 +56,6 @@ type GVKRequired struct { Version string `json:"version"` } -type Skips string -type SkipRange string - type BundleObject struct { File `json:",inline"` } @@ -121,26 +113,20 @@ func (f File) GetData(root fs.FS, cwd string) ([]byte, error) { } type Properties struct { - Packages []Package - PackagesRequired []PackageRequired - Channels []Channel - GVKs []GVK - GVKsRequired []GVKRequired - Skips []Skips - SkipRanges []SkipRange - BundleObjects []BundleObject + Packages []Package `hash:"set"` + PackagesRequired []PackageRequired `hash:"set"` + GVKs []GVK `hash:"set"` + GVKsRequired []GVKRequired `hash:"set"` + BundleObjects []BundleObject `hash:"set"` - Others []Property + Others []Property `hash:"set"` } const ( TypePackage = "olm.package" TypePackageRequired = "olm.package.required" - TypeChannel = "olm.channel" TypeGVK = "olm.gvk" TypeGVKRequired = "olm.gvk.required" - TypeSkips = "olm.skips" - TypeSkipRange = "olm.skipRange" TypeBundleObject = "olm.bundle.object" ) @@ -160,12 +146,6 @@ func Parse(in []Property) (*Properties, error) { return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} } out.PackagesRequired = append(out.PackagesRequired, p) - case TypeChannel: - var p Channel - if err := json.Unmarshal(prop.Value, &p); err != nil { - return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} - } - out.Channels = append(out.Channels, p) case TypeGVK: var p GVK if err := json.Unmarshal(prop.Value, &p); err != nil { @@ -178,18 +158,6 @@ func Parse(in []Property) (*Properties, error) { return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} } out.GVKsRequired = append(out.GVKsRequired, p) - case TypeSkips: - var p Skips - if err := json.Unmarshal(prop.Value, &p); err != nil { - return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} - } - out.Skips = append(out.Skips, p) - case TypeSkipRange: - var p SkipRange - if err := json.Unmarshal(prop.Value, &p); err != nil { - return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} - } - out.SkipRanges = append(out.SkipRanges, p) case TypeBundleObject: var p BundleObject if err := json.Unmarshal(prop.Value, &p); err != nil { @@ -285,23 +253,12 @@ func MustBuildPackage(name, version string) Property { func MustBuildPackageRequired(name, versionRange string) Property { return MustBuild(&PackageRequired{name, versionRange}) } -func MustBuildChannel(name, replaces string) Property { - return MustBuild(&Channel{name, replaces}) -} func MustBuildGVK(group, version, kind string) Property { return MustBuild(&GVK{group, kind, version}) } func MustBuildGVKRequired(group, version, kind string) Property { return MustBuild(&GVKRequired{group, kind, version}) } -func MustBuildSkips(skips string) Property { - s := Skips(skips) - return MustBuild(&s) -} -func MustBuildSkipRange(skipRange string) Property { - s := SkipRange(skipRange) - return MustBuild(&s) -} func MustBuildBundleObjectRef(ref string) Property { return MustBuild(&BundleObject{File: File{ref: ref}}) } diff --git a/vendor/github.com/operator-framework/operator-registry/internal/property/scheme.go b/vendor/github.com/operator-framework/operator-registry/alpha/property/scheme.go similarity index 77% rename from vendor/github.com/operator-framework/operator-registry/internal/property/scheme.go rename to vendor/github.com/operator-framework/operator-registry/alpha/property/scheme.go index c2fc7d3b9fe..b2d89366061 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/property/scheme.go +++ b/vendor/github.com/operator-framework/operator-registry/alpha/property/scheme.go @@ -6,17 +6,11 @@ import ( ) func init() { - skips := Skips("") - skipRange := SkipRange("") - scheme = map[reflect.Type]string{ reflect.TypeOf(&Package{}): TypePackage, reflect.TypeOf(&PackageRequired{}): TypePackageRequired, - reflect.TypeOf(&Channel{}): TypeChannel, reflect.TypeOf(&GVK{}): TypeGVK, reflect.TypeOf(&GVKRequired{}): TypeGVKRequired, - reflect.TypeOf(&skips): TypeSkips, - reflect.TypeOf(&skipRange): TypeSkipRange, reflect.TypeOf(&BundleObject{}): TypeBundleObject, } } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/api_to_model.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/api_to_model.go index eccbbcf0e50..d203f40b4a5 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/api/api_to_model.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/api_to_model.go @@ -5,8 +5,8 @@ import ( "fmt" "sort" - "github.com/operator-framework/operator-registry/internal/model" - "github.com/operator-framework/operator-registry/internal/property" + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/alpha/property" ) func ConvertAPIBundleToModelBundle(b *Bundle) (*model.Bundle, error) { @@ -25,6 +25,7 @@ func ConvertAPIBundleToModelBundle(b *Bundle) (*model.Bundle, error) { Image: b.BundlePath, Replaces: b.Replaces, Skips: b.Skips, + SkipRange: b.SkipRange, CsvJSON: b.CsvJson, Objects: b.Object, Properties: bundleProps, @@ -35,16 +36,6 @@ func ConvertAPIBundleToModelBundle(b *Bundle) (*model.Bundle, error) { func convertAPIBundleToModelProperties(b *Bundle) ([]property.Property, error) { var out []property.Property - for _, skip := range b.Skips { - out = append(out, property.MustBuildSkips(skip)) - } - - if b.SkipRange != "" { - out = append(out, property.MustBuildSkipRange(b.SkipRange)) - } - - out = append(out, property.MustBuildChannel(b.ChannelName, b.Replaces)) - providedGVKs := map[property.GVK]struct{}{} requiredGVKs := map[property.GVKRequired]struct{}{} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go index ad805a7cfa9..26f8b745c3d 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" - "github.com/operator-framework/operator-registry/internal/model" - "github.com/operator-framework/operator-registry/internal/property" + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/alpha/property" ) func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) { @@ -13,10 +13,6 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) { if err != nil { return nil, fmt.Errorf("parse properties: %v", err) } - skipRange := "" - if len(props.SkipRanges) > 0 { - skipRange = string(props.SkipRanges[0]) - } apiDeps, err := convertModelPropertiesToAPIDependencies(b.Properties) if err != nil { @@ -30,7 +26,7 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) { ProvidedApis: gvksProvidedtoAPIGVKs(props.GVKs), RequiredApis: gvksRequirestoAPIGVKs(props.GVKsRequired), Version: props.Packages[0].Version, - SkipRange: skipRange, + SkipRange: b.SkipRange, Dependencies: apiDeps, Properties: convertModelPropertiesToAPIProperties(b.Properties), Replaces: b.Replaces, @@ -50,10 +46,6 @@ func parseProperties(in []property.Property) (*property.Properties, error) { return nil, fmt.Errorf("expected exactly 1 property of type %q, found %d", property.TypePackage, len(props.Packages)) } - if len(props.SkipRanges) > 1 { - return nil, fmt.Errorf("multiple properties of type %q not allowed", property.TypeSkipRange) - } - return props, nil } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto index ac7e3b9e1f9..5f1daa9a7ce 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto +++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto @@ -8,7 +8,9 @@ service Registry { rpc ListPackages(ListPackageRequest) returns (stream PackageName) {} rpc GetPackage(GetPackageRequest) returns (Package) {} rpc GetBundle(GetBundleRequest) returns (Bundle) {} - rpc GetBundleForChannel(GetBundleInChannelRequest) returns (Bundle) {} + rpc GetBundleForChannel(GetBundleInChannelRequest) returns (Bundle) { + option deprecated = true; + } rpc GetChannelEntriesThatReplace(GetAllReplacementsRequest) returns (stream ChannelEntry) {} rpc GetBundleThatReplaces(GetReplacementRequest) returns (Bundle) {} rpc GetChannelEntriesThatProvide(GetAllProvidersRequest) returns (stream ChannelEntry) {} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go index 0c95407e2fd..01995af1e03 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go @@ -32,7 +32,9 @@ type BundleLoader struct { // creates an operator registry Bundle object. // If the Data section has a PackageManifest resource then it is also // deserialized and included in the result. -func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, err error) { +// The filenames contained in the ConfigMap are also returned. +// bundle.Object and filenames share the same index. +func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, filenames []string, err error) { if cm == nil { err = errors.New("ConfigMap must not be ") return @@ -42,7 +44,7 @@ func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, err error "configmap": fmt.Sprintf("%s/%s", cm.GetNamespace(), cm.GetName()), }) - bundle, skipped, bundleErr := loadBundle(logger, cm) + bundle, skipped, filenames, bundleErr := loadBundle(logger, cm) if bundleErr != nil { err = fmt.Errorf("failed to extract bundle from configmap - %v", bundleErr) return @@ -51,10 +53,13 @@ func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, err error return } -func loadBundle(entry *logrus.Entry, cm *corev1.ConfigMap) (bundle *api.Bundle, skipped map[string]string, err error) { +// loadBundle returns an API bundle built from a ConfigMap. +// it also returns the list of filenames and a list of files that have been skipped +// bundle.Object and filenames share the same index +func loadBundle(entry *logrus.Entry, cm *corev1.ConfigMap) (bundle *api.Bundle, skipped map[string]string, filenames []string, err error) { bundle = &api.Bundle{Object: []string{}} skipped = map[string]string{} - + filenames = []string{} data := cm.Data if hasGzipEncodingAnnotation(cm) { entry.Debug("Decoding gzip-encoded bundle data") @@ -62,7 +67,7 @@ func loadBundle(entry *logrus.Entry, cm *corev1.ConfigMap) (bundle *api.Bundle, var err error data, err = decodeGzipBinaryData(cm) if err != nil { - return nil, nil, err + return nil, nil, nil, err } } @@ -86,11 +91,14 @@ func loadBundle(entry *logrus.Entry, cm *corev1.ConfigMap) (bundle *api.Bundle, if resource.GetKind() == "ClusterServiceVersion" { csvBytes, err := resource.MarshalJSON() if err != nil { - return nil, nil, err + return nil, nil, nil, err } bundle.CsvJson = string(csvBytes) bundle.CsvName = resource.GetName() } + // Surface the file name for enabling manifest specific logic at a higher level + // This cannot be added to content as it is a plain string + filenames = append(filenames, name) bundle.Object = append(bundle.Object, content) logger.Infof("added to bundle, Kind=%s", resource.GetKind()) } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go index 4e1a21d40ee..2ec06f41d2b 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go @@ -8,9 +8,10 @@ import ( ) const ( - defaultBinarySourceImage = "quay.io/operator-framework/upstream-opm-builder" + DefaultBinarySourceImage = "quay.io/operator-framework/opm:latest" DefaultDbLocation = "/database/index.db" DbLocationLabel = "operators.operatorframework.io.index.database.v1" + ConfigsLocationLabel = "operators.operatorframework.io.index.configs.v1" ) // DockerfileGenerator defines functions to generate index dockerfiles @@ -36,7 +37,7 @@ func (g *IndexDockerfileGenerator) GenerateIndexDockerfile(binarySourceImage, da var dockerfile string if binarySourceImage == "" { - binarySourceImage = defaultBinarySourceImage + binarySourceImage = DefaultBinarySourceImage } g.Logger.Info("Generating dockerfile") diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/supported_resources.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/supported_resources.go index 534e6568c1a..94b5fd01dfd 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/supported_resources.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/supported_resources.go @@ -16,7 +16,10 @@ const ( PodDisruptionBudgetKind = "PodDisruptionBudget" PriorityClassKind = "PriorityClass" VerticalPodAutoscalerKind = "VerticalPodAutoscaler" - ConsoleYamlSampleKind = "ConsoleYamlSample" + ConsoleYAMLSampleKind = "ConsoleYAMLSample" + ConsoleQuickStartKind = "ConsoleQuickStart" + ConsoleCLIDownloadKind = "ConsoleCLIDownload" + ConsoleLinkKind = "ConsoleLink" ) // Namespaced indicates whether the resource is namespace scoped (true) or cluster-scoped (false). @@ -40,7 +43,10 @@ var supportedResources = map[string]Namespaced{ PodDisruptionBudgetKind: true, PriorityClassKind: false, VerticalPodAutoscalerKind: false, - ConsoleYamlSampleKind: false, + ConsoleYAMLSampleKind: false, + ConsoleQuickStartKind: false, + ConsoleCLIDownloadKind: false, + ConsoleLinkKind: false, } // IsSupported checks if the object kind is OLM-supported and if it is namespaced diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go index 0d0aa7a347d..fb8ca0368d5 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go @@ -237,6 +237,8 @@ func validateDependencies(dependenciesFile *registry.DependenciesFile) []error { errs = dp.Validate() case registry.LabelDependency: errs = dp.Validate() + case registry.CelConstraint: + errs = dp.Validate() default: errs = append(errs, fmt.Errorf("unsupported dependency type %s", d.GetType())) } @@ -343,6 +345,8 @@ func (i imageValidator) ValidateBundleContent(manifestDir string) error { } } case v1beta1CRDapiVersion: + i.logger.Warnf("GroupVersionKind apiextensions.k8s.io/v1beta1, Kind=CustomResourceDefinition was deprecated in Kubernetes 1.16+, removed in 1.22. Support" + + "for apiextensions.k8s.io/v1beta1 CustomResourceDefinitions will be removed in the future in favor of apiextensions.k8s.io/v1 CustomResourceDefinitions.") crd := &apiextensionsv1beta1.CustomResourceDefinition{} err := dec.Decode(crd) if err != nil { diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/semver/semver.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/semver/semver.go index 033bb5419e4..6875566d08d 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/semver/semver.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/semver/semver.go @@ -3,7 +3,7 @@ package semver import ( "fmt" - "github.com/blang/semver" + "github.com/blang/semver/v4" ) // BuildIdCompare compares two versions and returns negative one if the first arg is less than the second arg, positive one if it is larger, and zero if they are equal. diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundlegraphloader.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundlegraphloader.go index 05d8abf0641..e8664c4e84e 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundlegraphloader.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundlegraphloader.go @@ -3,7 +3,7 @@ package registry import ( "fmt" - "github.com/blang/semver" + "github.com/blang/semver/v4" ) // BundleGraphLoader generates updated graphs by adding bundles to them, updating diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go index a3b5ebc1916..ec6f3e32399 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go @@ -50,7 +50,7 @@ const ( description = "description" // The yaml attribute that specifies the version of the ClusterServiceVersion - // expected to be semver and parseable by blang/semver + // expected to be semver and parseable by blang/semver/v4 version = "version" // The yaml attribute that specifies the related images of the ClusterServiceVersion diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/decode.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/decode.go index 392d5dd8878..0a9587d0922 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/decode.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/decode.go @@ -6,6 +6,7 @@ import ( "io" "io/fs" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/yaml" ) @@ -44,7 +45,7 @@ func DecodePackageManifest(reader io.Reader) (manifest *PackageManifest, err err return } -func decodeFileFS(root fs.FS, path string, into interface{}) error { +func decodeFileFS(root fs.FS, path string, into interface{}, log *logrus.Entry) error { fileReader, err := root.Open(path) if err != nil { return fmt.Errorf("unable to read file %s: %s", path, err) @@ -53,5 +54,16 @@ func decodeFileFS(root fs.FS, path string, into interface{}) error { decoder := yaml.NewYAMLOrJSONDecoder(fileReader, 30) - return decoder.Decode(into) + errRet := decoder.Decode(into) + + if errRet == nil { + // Look for and warn about extra documents + extraDocument := &map[string]interface{}{} + err = decoder.Decode(extraDocument) + if err == nil && log != nil { + log.Warnf("found more than one document inside %s, using only the first one", path) + } + } + + return errRet } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go index 03efa4d63f5..b639c08b5ed 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go @@ -8,7 +8,7 @@ import ( "path/filepath" "sort" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/onsi/gomega/gstruct/errors" ) diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/empty.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/empty.go index fd4676eb6c1..936f39ccab7 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/empty.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/empty.go @@ -100,6 +100,10 @@ func (EmptyQuery) ListBundles(ctx context.Context) ([]*api.Bundle, error) { return nil, errors.New("empty querier: cannot list bundles") } +func (EmptyQuery) SendBundles(ctx context.Context, stream BundleSender) error { + return errors.New("empty querier: cannot stream bundles") +} + func (EmptyQuery) GetDependenciesForBundle(ctx context.Context, name, version, path string) (dependencies []*api.Dependency, err error) { return nil, errors.New("empty querier: cannot get dependencies for bundle") } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go index fd77636117e..93df40c61a3 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go @@ -17,10 +17,17 @@ type Load interface { ClearNonHeadBundles() error } +type BundleSender interface { + Send(*api.Bundle) error +} + type GRPCQuery interface { // List all available package names in the index ListPackages(ctx context.Context) ([]string, error) + // Sends all available bundles in the index + SendBundles(ctx context.Context, stream BundleSender) error + // List all available bundles in the index ListBundles(ctx context.Context) (bundles []*api.Bundle, err error) @@ -30,7 +37,10 @@ type GRPCQuery interface { // Get a bundle by its package name, channel name and csv name from the index GetBundle(ctx context.Context, pkgName, channelName, csvName string) (*api.Bundle, error) - // Get the bundle in the specified package at the head of the specified channel + // Get the bundle in the specified package at the head of the + // specified channel. DEPRECATED. Returned bundles may have + // only the "name" and "csvJson" fields populated in order to + // support legacy usage. GetBundleForChannel(ctx context.Context, pkgName string, channelName string) (*api.Bundle, error) // Get all channel entries that say they replace this one @@ -94,3 +104,7 @@ type GraphLoader interface { type RegistryPopulator interface { Populate() error } + +type HeadOverwriter interface { + RemoveOverwrittenChannelHead(pkg, bundle string) error +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/parse.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/parse.go index 984517cc047..4b13ef76736 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/parse.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/parse.go @@ -6,10 +6,9 @@ import ( "io/fs" "strings" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" ) type bundleParser struct { @@ -74,7 +73,7 @@ func (b *bundleParser) addManifests(manifests fs.FS, bundle *Bundle) error { } obj := &unstructured.Unstructured{} - if err = decodeFileFS(manifests, name, obj); err != nil { + if err = decodeFileFS(manifests, name, obj, b.log); err != nil { b.log.Warnf("failed to decode: %s", err) continue } @@ -128,7 +127,7 @@ func (b *bundleParser) addMetadata(metadata fs.FS, bundle *Bundle) error { name := f.Name() if af == nil { decoded := AnnotationsFile{} - if err = decodeFileFS(metadata, name, &decoded); err == nil { + if err = decodeFileFS(metadata, name, &decoded, b.log); err == nil { if decoded != (AnnotationsFile{}) { af = &decoded } @@ -136,7 +135,7 @@ func (b *bundleParser) addMetadata(metadata fs.FS, bundle *Bundle) error { } if df == nil { decoded := DependenciesFile{} - if err = decodeFileFS(metadata, name, &decoded); err == nil { + if err = decodeFileFS(metadata, name, &decoded, b.log); err == nil { if len(decoded.Dependencies) > 0 { df = &decoded } @@ -144,7 +143,7 @@ func (b *bundleParser) addMetadata(metadata fs.FS, bundle *Bundle) error { } if pf == nil { decoded := PropertiesFile{} - if err = decodeFileFS(metadata, name, &decoded); err == nil { + if err = decodeFileFS(metadata, name, &decoded, b.log); err == nil { if len(decoded.Properties) > 0 { pf = &decoded } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/populator.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/populator.go index ad65e78b2d6..4a236da793f 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/populator.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/populator.go @@ -5,8 +5,9 @@ import ( "errors" "fmt" "os" + "sort" - "github.com/blang/semver" + "github.com/blang/semver/v4" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/yaml" @@ -20,22 +21,20 @@ type Dependencies struct { // DirectoryPopulator loads an unpacked operator bundle from a directory into the database. type DirectoryPopulator struct { - loader Load - graphLoader GraphLoader - querier Query - imageDirMap map[image.Reference]string - overwriteDirMap map[string]map[image.Reference]string - overwrite bool + loader Load + graphLoader GraphLoader + querier Query + imageDirMap map[image.Reference]string + overwrittenImages map[string][]string } -func NewDirectoryPopulator(loader Load, graphLoader GraphLoader, querier Query, imageDirMap map[image.Reference]string, overwriteDirMap map[string]map[image.Reference]string, overwrite bool) *DirectoryPopulator { +func NewDirectoryPopulator(loader Load, graphLoader GraphLoader, querier Query, imageDirMap map[image.Reference]string, overwrittenImages map[string][]string) *DirectoryPopulator { return &DirectoryPopulator{ - loader: loader, - graphLoader: graphLoader, - querier: querier, - imageDirMap: imageDirMap, - overwriteDirMap: overwriteDirMap, - overwrite: overwrite, + loader: loader, + graphLoader: graphLoader, + querier: querier, + imageDirMap: imageDirMap, + overwrittenImages: overwrittenImages, } } @@ -52,24 +51,11 @@ func (i *DirectoryPopulator) Populate(mode Mode) error { imagesToAdd = append(imagesToAdd, imageInput) } - imagesToReAdd := make([]*ImageInput, 0) - for pkg := range i.overwriteDirMap { - for to, from := range i.overwriteDirMap[pkg] { - imageInput, err := NewImageInput(to, from) - if err != nil { - errs = append(errs, err) - continue - } - - imagesToReAdd = append(imagesToReAdd, imageInput) - } - } - if len(errs) > 0 { return utilerrors.NewAggregate(errs) } - err := i.loadManifests(imagesToAdd, imagesToReAdd, mode) + err := i.loadManifests(imagesToAdd, mode) if err != nil { return err } @@ -78,6 +64,7 @@ func (i *DirectoryPopulator) Populate(mode Mode) error { } func (i *DirectoryPopulator) globalSanityCheck(imagesToAdd []*ImageInput) error { + overwrite := len(i.overwrittenImages) > 0 var errs []error images := make(map[string]struct{}) for _, image := range imagesToAdd { @@ -111,7 +98,7 @@ func (i *DirectoryPopulator) globalSanityCheck(imagesToAdd []*ImageInput) error continue } if bundle != nil { - if !i.overwrite { + if !overwrite { // raise error that this package + channel + csv combo is already in the db errs = append(errs, PackageVersionAlreadyAddedErr{ErrorString: "Bundle already added that provides package and csv"}) break @@ -142,10 +129,13 @@ func (i *DirectoryPopulator) globalSanityCheck(imagesToAdd []*ImageInput) error } } + if err := i.ValidateEdgeBundlePackage(imagesToAdd); err != nil { + errs = append(errs, err) + } return utilerrors.NewAggregate(errs) } -func (i *DirectoryPopulator) loadManifests(imagesToAdd []*ImageInput, imagesToReAdd []*ImageInput, mode Mode) error { +func (i *DirectoryPopulator) loadManifests(imagesToAdd []*ImageInput, mode Mode) error { // global sanity checks before insertion if err := i.globalSanityCheck(imagesToAdd); err != nil { return err @@ -153,17 +143,30 @@ func (i *DirectoryPopulator) loadManifests(imagesToAdd []*ImageInput, imagesToRe switch mode { case ReplacesMode: - for pkg := range i.overwriteDirMap { - // TODO: If this succeeds but the add fails there will be a disconnect between - // the registry and the index. Loading the bundles in a single transactions as - // described above would allow us to do the removable in that same transaction - // and ensure that rollback is possible. - if err := i.loader.RemovePackage(pkg); err != nil { - return err + // TODO: If this succeeds but the add fails there will be a disconnect between + // the registry and the index. Loading the bundles in a single transactions as + // described above would allow us to do the removable in that same transaction + // and ensure that rollback is possible. + + // globalSanityCheck should have verified this to be a head without anything replacing it + // and that we have a single overwrite per package + + if len(i.overwrittenImages) > 0 { + if overwriter, ok := i.loader.(HeadOverwriter); ok { + // Assume loader has some way to handle overwritten heads if HeadOverwriter isn't implemented explicitly + for pkg, imgToDelete := range i.overwrittenImages { + if len(imgToDelete) == 0 { + continue + } + // delete old head bundle and swap it with the previous real bundle in its replaces chain + if err := overwriter.RemoveOverwrittenChannelHead(pkg, imgToDelete[0]); err != nil { + return err + } + } } } - return i.loadManifestsReplaces(append(imagesToAdd, imagesToReAdd...)) + return i.loadManifestsReplaces(imagesToAdd) case SemVerMode: for _, image := range imagesToAdd { if err := i.loadManifestsSemver(image.Bundle, false); err != nil { @@ -408,3 +411,54 @@ func DecodeFile(path string, into interface{}) error { return decoder.Decode(into) } + +// ValidateEdgeBundlePackage ensures that all bundles in the input will only skip or replace bundles in the same package. +func (i *DirectoryPopulator) ValidateEdgeBundlePackage(images []*ImageInput) error { + // track packages for encountered bundles + expectedBundlePackages := map[string]string{} + for _, b := range images { + r, err := b.Bundle.Replaces() + if err != nil { + return fmt.Errorf("failed to validate replaces for bundle %s(%s): %v", b.Bundle.Name, b.Bundle.BundleImage, err) + } + + skipped, err := b.Bundle.Skips() + if err != nil { + return fmt.Errorf("failed to validate skipped entries for bundle %s(%s): %v", b.Bundle.Name, b.Bundle.BundleImage, err) + } + + for _, bndl := range append(skipped, r, b.Bundle.Name) { + if len(bndl) == 0 { + continue + } + + if pkg, ok := expectedBundlePackages[bndl]; ok && pkg != b.Bundle.Package { + pkgs := []string{pkg, b.Bundle.Package} + sort.Strings(pkgs) + return fmt.Errorf("bundle %s must belong to exactly one package, found on: %v", bndl, pkgs) + } + expectedBundlePackages[bndl] = b.Bundle.Package + } + } + if len(expectedBundlePackages) == 0 { + return nil + } + + pkgs, err := i.querier.ListPackages(context.TODO()) + if err != nil { + return fmt.Errorf("unable to verify bundle packages: %v", err) + } + for _, pkg := range pkgs { + entries, err := i.querier.GetChannelEntriesFromPackage(context.TODO(), pkg) + if err != nil { + return fmt.Errorf("unable to verify bundles for package %v", err) + } + for _, b := range entries { + if bundlePkg, ok := expectedBundlePackages[b.BundleName]; ok && bundlePkg != b.PackageName { + return fmt.Errorf("bundle %s belongs to package %s on index, cannot be added as an edge for package %s", b.BundleName, b.PackageName, bundlePkg) + } + } + } + + return nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/query.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/query.go index 9acd9d48fa0..4ccf7eba4fa 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/query.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/query.go @@ -2,23 +2,97 @@ package registry import ( "context" + "encoding/json" "fmt" + "os" + "path/filepath" "sort" - "github.com/operator-framework/operator-registry/internal/model" + "github.com/operator-framework/operator-registry/alpha/model" "github.com/operator-framework/operator-registry/pkg/api" ) type Querier struct { pkgs model.Model + + tmpDir string + apiBundles map[apiBundleKey]string +} + +func (q Querier) Close() error { + return os.RemoveAll(q.tmpDir) +} + +type apiBundleKey struct { + pkgName string + chName string + name string +} + +type SliceBundleSender []*api.Bundle + +func (s *SliceBundleSender) Send(b *api.Bundle) error { + + *s = append(*s, b) + return nil } var _ GRPCQuery = &Querier{} -func NewQuerier(packages model.Model) *Querier { - return &Querier{ - pkgs: packages, +func NewQuerier(packages model.Model) (*Querier, error) { + q := &Querier{} + + tmpDir, err := os.MkdirTemp("", "opm-registry-querier-") + if err != nil { + return nil, err } + q.tmpDir = tmpDir + + q.apiBundles = map[apiBundleKey]string{} + for _, pkg := range packages { + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + apiBundle, err := api.ConvertModelBundleToAPIBundle(*b) + if err != nil { + return q, err + } + jsonBundle, err := json.Marshal(apiBundle) + if err != nil { + return q, err + } + filename := filepath.Join(tmpDir, fmt.Sprintf("%s_%s_%s.json", pkg.Name, ch.Name, b.Name)) + if err := os.WriteFile(filename, jsonBundle, 0666); err != nil { + return q, err + } + q.apiBundles[apiBundleKey{pkg.Name, ch.Name, b.Name}] = filename + packages[pkg.Name].Channels[ch.Name].Bundles[b.Name] = &model.Bundle{ + Package: pkg, + Channel: ch, + Name: b.Name, + Replaces: b.Replaces, + Skips: b.Skips, + } + } + } + } + q.pkgs = packages + return q, nil +} + +func (q Querier) loadAPIBundle(k apiBundleKey) (*api.Bundle, error) { + filename, ok := q.apiBundles[k] + if !ok { + return nil, fmt.Errorf("package %q, channel %q, bundle %q not found", k.pkgName, k.chName, k.name) + } + d, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + var b api.Bundle + if err := json.Unmarshal(d, &b); err != nil { + return nil, err + } + return &b, nil } func (q Querier) ListPackages(_ context.Context) ([]string, error) { @@ -29,21 +103,40 @@ func (q Querier) ListPackages(_ context.Context) ([]string, error) { return packages, nil } -func (q Querier) ListBundles(_ context.Context) ([]*api.Bundle, error) { - var bundles []*api.Bundle +func (q Querier) ListBundles(ctx context.Context) ([]*api.Bundle, error) { + var bundleSender SliceBundleSender + + err := q.SendBundles(ctx, &bundleSender) + if err != nil { + return nil, err + } + + return bundleSender, nil +} +func (q Querier) SendBundles(_ context.Context, s BundleSender) error { for _, pkg := range q.pkgs { for _, ch := range pkg.Channels { for _, b := range ch.Bundles { - apiBundle, err := api.ConvertModelBundleToAPIBundle(*b) + apiBundle, err := q.loadAPIBundle(apiBundleKey{pkg.Name, ch.Name, b.Name}) if err != nil { - return nil, fmt.Errorf("convert bundle %q: %v", b.Name, err) + return fmt.Errorf("convert bundle %q: %v", b.Name, err) + } + if apiBundle.BundlePath != "" { + // The SQLite-based server + // configures its querier to + // omit these fields when + // bundle path is set. + apiBundle.CsvJson = "" + apiBundle.Object = nil + } + if err := s.Send(apiBundle); err != nil { + return err } - bundles = append(bundles, apiBundle) } } } - return bundles, nil + return nil } func (q Querier) GetPackage(_ context.Context, name string) (*PackageManifest, error) { @@ -83,7 +176,7 @@ func (q Querier) GetBundle(_ context.Context, pkgName, channelName, csvName stri if !ok { return nil, fmt.Errorf("package %q, channel %q, bundle %q not found", pkgName, channelName, csvName) } - apiBundle, err := api.ConvertModelBundleToAPIBundle(*b) + apiBundle, err := q.loadAPIBundle(apiBundleKey{pkg.Name, ch.Name, b.Name}) if err != nil { return nil, fmt.Errorf("convert bundle %q: %v", b.Name, err) } @@ -107,7 +200,7 @@ func (q Querier) GetBundleForChannel(_ context.Context, pkgName string, channelN if err != nil { return nil, fmt.Errorf("package %q, channel %q has invalid head: %v", pkgName, channelName, err) } - apiBundle, err := api.ConvertModelBundleToAPIBundle(*head) + apiBundle, err := q.loadAPIBundle(apiBundleKey{pkg.Name, ch.Name, head.Name}) if err != nil { return nil, fmt.Errorf("convert bundle %q: %v", head.Name, err) } @@ -150,7 +243,7 @@ func (q Querier) GetBundleThatReplaces(_ context.Context, name, pkgName, channel // implementation to be non-deterministic as well. for _, b := range ch.Bundles { if bundleReplaces(*b, name) { - apiBundle, err := api.ConvertModelBundleToAPIBundle(*b) + apiBundle, err := q.loadAPIBundle(apiBundleKey{pkg.Name, ch.Name, b.Name}) if err != nil { return nil, fmt.Errorf("convert bundle %q: %v", b.Name, err) } @@ -170,7 +263,7 @@ func (q Querier) GetChannelEntriesThatProvide(_ context.Context, group, version, for _, pkg := range q.pkgs { for _, ch := range pkg.Channels { for _, b := range ch.Bundles { - provides, err := doesModelBundleProvide(*b, group, version, kind) + provides, err := q.doesModelBundleProvide(*b, group, version, kind) if err != nil { return nil, err } @@ -209,7 +302,7 @@ func (q Querier) GetLatestChannelEntriesThatProvide(_ context.Context, group, ve return nil, fmt.Errorf("package %q, channel %q has invalid head: %v", pkg.Name, ch.Name, err) } - provides, err := doesModelBundleProvide(*b, group, version, kind) + provides, err := q.doesModelBundleProvide(*b, group, version, kind) if err != nil { return nil, err } @@ -251,8 +344,8 @@ func (q Querier) GetBundleThatProvides(ctx context.Context, group, version, kind return nil, fmt.Errorf("no entry found that provides group:%q version:%q kind:%q", group, version, kind) } -func doesModelBundleProvide(b model.Bundle, group, version, kind string) (bool, error) { - apiBundle, err := api.ConvertModelBundleToAPIBundle(b) +func (q Querier) doesModelBundleProvide(b model.Bundle, group, version, kind string) (bool, error) { + apiBundle, err := q.loadAPIBundle(apiBundleKey{b.Package.Name, b.Channel.Name, b.Name}) if err != nil { return false, fmt.Errorf("convert bundle %q: %v", b.Name, err) } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/registry_to_model.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/registry_to_model.go index 8d921a29e3a..b45fdf88287 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/registry_to_model.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/registry_to_model.go @@ -4,118 +4,11 @@ import ( "encoding/json" "fmt" "sort" - "strings" - "github.com/operator-framework/operator-registry/internal/model" - "github.com/operator-framework/operator-registry/internal/property" + "github.com/operator-framework/operator-registry/alpha/property" ) -func ConvertRegistryBundleToModelBundles(b *Bundle) ([]model.Bundle, error) { - var bundles []model.Bundle - desc, err := b.csv.GetDescription() - if err != nil { - return nil, fmt.Errorf("Could not get description from bundle CSV:%s", err) - } - - i, err := b.csv.GetIcons() - if err != nil { - return nil, fmt.Errorf("Could not get icon from bundle CSV:%s", err) - } - mIcon := &model.Icon{ - MediaType: "", - Data: []byte{}, - } - if len(i) > 0 { - mIcon.MediaType = i[0].MediaType - mIcon.Data = []byte(i[0].Base64data) - } - - pkg := &model.Package{ - Name: b.Annotations.PackageName, - Description: desc, - Icon: mIcon, - Channels: make(map[string]*model.Channel), - } - - mb, err := registryBundleToModelBundle(b) - mb.Package = pkg - if err != nil { - return nil, err - } - - for _, ch := range extractChannels(b.Annotations.Channels) { - newCh := &model.Channel{ - Name: ch, - } - chBundle := mb - chBundle.Channel = newCh - bundles = append(bundles, *chBundle) - } - return bundles, nil -} - -func registryBundleToModelBundle(b *Bundle) (*model.Bundle, error) { - bundleProps, err := PropertiesFromBundle(b) - if err != nil { - return nil, fmt.Errorf("error converting properties for internal model: %v", err) - } - - csv, err := b.ClusterServiceVersion() - if err != nil { - return nil, fmt.Errorf("Could not get CVS for bundle: %s", err) - } - replaces, err := csv.GetReplaces() - if err != nil { - return nil, fmt.Errorf("Could not get Replaces from CSV for bundle: %s", err) - } - skips, err := csv.GetSkips() - if err != nil { - return nil, fmt.Errorf("Could not get Skips from CSV for bundle: %s", err) - } - relatedImages, err := convertToModelRelatedImages(csv) - if err != nil { - return nil, fmt.Errorf("Could not get Related images from bundle: %v", err) - } - - return &model.Bundle{ - Name: csv.Name, - Image: b.BundleImage, - Replaces: replaces, - Skips: skips, - Properties: bundleProps, - RelatedImages: relatedImages, - }, nil -} - -func PropertiesFromBundle(b *Bundle) ([]property.Property, error) { - csv, err := b.ClusterServiceVersion() - if err != nil { - return nil, fmt.Errorf("get csv: %v", err) - } - - skips, err := csv.GetSkips() - if err != nil { - return nil, fmt.Errorf("get csv skips: %v", err) - } - - var graphProps []property.Property - replaces, err := csv.GetReplaces() - if err != nil { - return nil, fmt.Errorf("get csv replaces: %v", err) - } - for _, ch := range b.Channels { - graphProps = append(graphProps, property.MustBuildChannel(ch, replaces)) - } - - for _, skip := range skips { - graphProps = append(graphProps, property.MustBuildSkips(skip)) - } - - skipRange := csv.GetSkipRange() - if skipRange != "" { - graphProps = append(graphProps, property.MustBuildSkipRange(skipRange)) - } - +func ObjectsAndPropertiesFromBundle(b *Bundle) ([]string, []property.Property, error) { providedGVKs := map[property.GVK]struct{}{} requiredGVKs := map[property.GVKRequired]struct{}{} @@ -127,14 +20,14 @@ func PropertiesFromBundle(b *Bundle) ([]property.Property, error) { case property.TypeGVK: var v property.GVK if err := json.Unmarshal(p.Value, &v); err != nil { - return nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} + return nil, nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} } k := property.GVK{Group: v.Group, Kind: v.Kind, Version: v.Version} providedGVKs[k] = struct{}{} case property.TypePackage: var v property.Package if err := json.Unmarshal(p.Value, &v); err != nil { - return nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} + return nil, nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} } p := property.MustBuildPackage(v.PackageName, v.Version) packageProvidedProperty = &p @@ -152,14 +45,14 @@ func PropertiesFromBundle(b *Bundle) ([]property.Property, error) { case property.TypeGVK: var v property.GVK if err := json.Unmarshal(p.Value, &v); err != nil { - return nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} + return nil, nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} } k := property.GVKRequired{Group: v.Group, Kind: v.Kind, Version: v.Version} requiredGVKs[k] = struct{}{} case property.TypePackage: var v property.Package if err := json.Unmarshal(p.Value, &v); err != nil { - return nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} + return nil, nil, property.ParseError{Idx: i, Typ: p.Type, Err: err} } packageRequiredProps = append(packageRequiredProps, property.MustBuildPackageRequired(v.PackageName, v.Version)) } @@ -167,12 +60,12 @@ func PropertiesFromBundle(b *Bundle) ([]property.Property, error) { version, err := b.Version() if err != nil { - return nil, fmt.Errorf("get version: %v", err) + return nil, nil, fmt.Errorf("get version: %v", err) } providedApis, err := b.ProvidedAPIs() if err != nil { - return nil, fmt.Errorf("get provided apis: %v", err) + return nil, nil, fmt.Errorf("get provided apis: %v", err) } for p := range providedApis { @@ -183,7 +76,7 @@ func PropertiesFromBundle(b *Bundle) ([]property.Property, error) { } requiredApis, err := b.RequiredAPIs() if err != nil { - return nil, fmt.Errorf("get required apis: %v", err) + return nil, nil, fmt.Errorf("get required apis: %v", err) } for p := range requiredApis { k := property.GVKRequired{Group: p.Group, Kind: p.Kind, Version: p.Version} @@ -192,68 +85,42 @@ func PropertiesFromBundle(b *Bundle) ([]property.Property, error) { } } - var out []property.Property + var ( + props []property.Property + objects []string + ) + for _, obj := range b.Objects { + objData, err := json.Marshal(obj) + if err != nil { + return nil, nil, fmt.Errorf("marshal object %s/%s (%s) to json: %v", obj.GetName(), obj.GetNamespace(), obj.GroupVersionKind(), err) + } + props = append(props, property.MustBuildBundleObjectData(objData)) + objects = append(objects, string(objData)) + } + if packageProvidedProperty == nil { p := property.MustBuildPackage(b.Package, version) packageProvidedProperty = &p } - out = append(out, *packageProvidedProperty) - out = append(out, graphProps...) + props = append(props, *packageProvidedProperty) for p := range providedGVKs { - out = append(out, property.MustBuildGVK(p.Group, p.Version, p.Kind)) + props = append(props, property.MustBuildGVK(p.Group, p.Version, p.Kind)) } for p := range requiredGVKs { - out = append(out, property.MustBuildGVKRequired(p.Group, p.Version, p.Kind)) + props = append(props, property.MustBuildGVKRequired(p.Group, p.Version, p.Kind)) } - out = append(out, packageRequiredProps...) - out = append(out, otherProps...) + props = append(props, packageRequiredProps...) + props = append(props, otherProps...) - sort.Slice(out, func(i, j int) bool { - if out[i].Type != out[j].Type { - return out[i].Type < out[j].Type + sort.Slice(props, func(i, j int) bool { + if props[i].Type != props[j].Type { + return props[i].Type < props[j].Type } - return string(out[i].Value) < string(out[j].Value) + return string(props[i].Value) < string(props[j].Value) }) - return out, nil -} - -func convertToModelRelatedImages(csv *ClusterServiceVersion) ([]model.RelatedImage, error) { - var objmap map[string]*json.RawMessage - if err := json.Unmarshal(csv.Spec, &objmap); err != nil { - return nil, err - } - - rawValue, ok := objmap[relatedImages] - if !ok || rawValue == nil { - return nil, nil - } - - type relatedImage struct { - Name string `json:"name"` - Ref string `json:"image"` - } - var relatedImages []relatedImage - if err := json.Unmarshal(*rawValue, &relatedImages); err != nil { - return nil, err - } - mrelatedImages := []model.RelatedImage{} - for _, img := range relatedImages { - mrelatedImages = append(mrelatedImages, model.RelatedImage{Name: img.Name, Image: img.Ref}) - } - return mrelatedImages, nil -} - -func extractChannels(annotationChannels string) []string { - var channels []string - for _, ch := range strings.Split(annotationChannels, ",") { - c := strings.TrimSpace(ch) - if c != "" { - channels = append(channels, ch) - } - } - return channels + return objects, props, nil } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go index 719127cfba0..42908e50873 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go @@ -7,7 +7,8 @@ import ( "sort" "strings" - "github.com/blang/semver" + "github.com/blang/semver/v4" + "github.com/operator-framework/api/pkg/constraints" ) var ( @@ -55,6 +56,7 @@ const ( DeprecatedType = "olm.deprecated" LabelType = "olm.label" PropertyKey = "olm.properties" + ConstraintType = "olm.constraint" ) // APIKey stores GroupVersionKind for use as map keys @@ -220,6 +222,16 @@ type LabelDependency struct { Label string `json:"label" yaml:"label"` } +type CelConstraint struct { + // Constraint message that surfaces in resolution + // This field is optional + Message string `json:"message" yaml:"message"` + + // The cel struct that contraints CEL expression + // This field is required + Cel *constraints.Cel `json:"cel" yaml:"cel"` +} + type GVKProperty struct { // The group of GVK based property Group string `json:"group" yaml:"group"` @@ -289,6 +301,25 @@ func (pd *PackageDependency) Validate() []error { return errs } +// Validate will validate constraint type and return error(s) +func (cc *CelConstraint) Validate() []error { + errs := []error{} + if cc.Cel == nil { + errs = append(errs, fmt.Errorf("The CEL field is missing")) + } else { + if cc.Cel.Rule == "" { + errs = append(errs, fmt.Errorf("The CEL expression is missing")) + return errs + } + validator := constraints.NewCelEnvironment() + _, err := validator.Validate(cc.Cel.Rule) + if err != nil { + errs = append(errs, fmt.Errorf("Invalid CEL expression: %s", err.Error())) + } + } + return errs +} + // GetDependencies returns the list of dependency func (d *DependenciesFile) GetDependencies() []*Dependency { var dependencies []*Dependency @@ -329,6 +360,13 @@ func (e *Dependency) GetTypeValue() interface{} { return nil } return dep + case ConstraintType: + dep := CelConstraint{} + err := json.Unmarshal([]byte(e.GetValue()), &dep) + if err != nil { + return nil + } + return dep } return nil } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/server/server.go b/vendor/github.com/operator-framework/operator-registry/pkg/server/server.go index 9fe1592c3e3..64b87ce70e5 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/server/server.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/server/server.go @@ -33,17 +33,7 @@ func (s *RegistryServer) ListPackages(req *api.ListPackageRequest, stream api.Re } func (s *RegistryServer) ListBundles(req *api.ListBundlesRequest, stream api.Registry_ListBundlesServer) error { - bundles, err := s.store.ListBundles(stream.Context()) - if err != nil { - return err - } - for _, b := range bundles { - if err := stream.Send(b); err != nil { - return err - } - } - - return nil + return s.store.SendBundles(stream.Context(), stream) } func (s *RegistryServer) GetPackage(ctx context.Context, req *api.GetPackageRequest) (*api.Package, error) { diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/conversion.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/conversion.go index 7c4fa49095b..e94d052cf04 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/conversion.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/conversion.go @@ -10,7 +10,7 @@ import ( "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/sirupsen/logrus" - "github.com/operator-framework/operator-registry/internal/model" + "github.com/operator-framework/operator-registry/alpha/model" "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/registry" ) @@ -51,10 +51,10 @@ func initializeModelPackages(ctx context.Context, q *SQLQuerier) (model.Model, e pkgs := model.Model{} for _, rPkg := range rPkgs { pkg := model.Package{ - Name: rPkg.PackageName, + Name: rPkg.PackageName, + Channels: map[string]*model.Channel{}, } - pkg.Channels = map[string]*model.Channel{} for _, ch := range rPkg.Channels { channel := &model.Channel{ Package: &pkg, diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecate.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecate.go index a8cdb24fa9e..4ac3d61ebf2 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecate.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecate.go @@ -1,6 +1,7 @@ package sqlite import ( + "context" "errors" "fmt" @@ -20,7 +21,14 @@ type BundleDeprecator struct { bundles []string } +// PackageDeprecator removes bundles and optionally entire packages from the index +type PackageDeprecator struct { + *BundleDeprecator + querier *SQLQuerier +} + var _ SQLDeprecator = &BundleDeprecator{} +var _ SQLDeprecator = &PackageDeprecator{} func NewSQLDeprecatorForBundles(store registry.Load, bundles []string) *BundleDeprecator { return &BundleDeprecator{ @@ -29,6 +37,13 @@ func NewSQLDeprecatorForBundles(store registry.Load, bundles []string) *BundleDe } } +func NewSQLDeprecatorForBundlesAndPackages(deprecator *BundleDeprecator, querier *SQLQuerier) *PackageDeprecator { + return &PackageDeprecator{ + BundleDeprecator: deprecator, + querier: querier, + } +} + func (d *BundleDeprecator) Deprecate() error { log := logrus.WithField("bundles", d.bundles) log.Info("deprecating bundles") @@ -45,3 +60,87 @@ func (d *BundleDeprecator) Deprecate() error { return utilerrors.NewAggregate(errs) } + +// MaybeRemovePackages queries the DB to establish if any provided bundles are the head of the default channel of a package. +// If so, the list of bundles must also contain the head of all other channels in the package, otherwise an error is produced. +// If the heads of all channels are being deprecated (including the default channel), the package is removed entirely from the index. +// MaybeRemovePackages deletes all bundles from the associated package from the bundles array, so that the subsequent +// Deprecate() call can proceed with deprecating other potential bundles from other packages. +func (d *PackageDeprecator) MaybeRemovePackages() error { + log := logrus.WithField("bundles", d.bundles) + log.Info("allow-package-removal enabled: checking default channel heads for package removal") + + var errs []error + var removedBundlePaths []string + var remainingBundlePaths []string + + // Iterate over bundles list - see if any bundle is the head of a default channel in a package + var packages []string + for _, bundle := range d.bundles { + found, err := d.querier.PackageFromDefaultChannelHeadBundle(context.TODO(), bundle) + if err != nil { + errs = append(errs, fmt.Errorf("error checking if bundle is default channel head %s: %s", bundle, err)) + } + if found != "" { + packages = append(packages, found) + } + } + + if len(packages) == 0 { + log.Info("no head of default channel found - skipping package removal") + return nil + } + + // If so, ensure list contains head of all other channels in that package + // If not, return error + for _, pkg := range packages { + channels, err := d.querier.ListChannels(context.TODO(), pkg) + if err != nil { + errs = append(errs, fmt.Errorf("error listing channels for package %s: %s", pkg, err)) + } + for _, channel := range channels { + found, err := d.querier.BundlePathForChannelHead(context.TODO(), pkg, channel) + if err != nil { + errs = append(errs, fmt.Errorf("error listing channel head for package %s: %s", pkg, err)) + } + if !contains(found, d.bundles) { + // terminal error + errs = append(errs, fmt.Errorf("cannot deprecate default channel head from package without removing all other channel heads in package %s: must deprecate %s, head of channel %s", pkg, found, channel)) + return utilerrors.NewAggregate(errs) + } + removedBundlePaths = append(removedBundlePaths, found) + } + } + + // Remove associated package from index + log.Infof("removing packages %#v", packages) + for _, pkg := range packages { + err := d.store.RemovePackage(pkg) + if err != nil { + errs = append(errs, fmt.Errorf("error removing package %s: %s", pkg, err)) + } + } + + // Remove bundles from the removed package from the deprecation request + // This enables other bundles to be deprecated via the expected flow + // Build a new array with just the outstanding bundles + for _, bundlePath := range d.bundles { + if contains(bundlePath, removedBundlePaths) { + continue + } + remainingBundlePaths = append(remainingBundlePaths, bundlePath) + } + d.bundles = remainingBundlePaths + log.Infof("remaining bundles to deprecate %#v", d.bundles) + + return utilerrors.NewAggregate(errs) +} + +func contains(bundlePath string, bundles []string) bool { + for _, b := range bundles { + if b == bundlePath { + return true + } + } + return false +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecationmessage.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecationmessage.go new file mode 100644 index 00000000000..20a1389b71d --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/deprecationmessage.go @@ -0,0 +1,19 @@ +package sqlite + +import ( + "fmt" + + "github.com/sirupsen/logrus" +) + +const noticeColor = "\033[1;33m%s\033[0m" + +func LogSqliteDeprecation() { + log := logrus.New() + log.Warnf(DeprecationMessage) +} + +var DeprecationMessage = fmt.Sprintf(noticeColor, `DEPRECATION NOTICE: +Sqlite-based catalogs and their related subcommands are deprecated. Support for +them will be removed in a future release. Please migrate your catalog workflows +to the new file-based catalog format.`) diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go index cfb3b7015a0..47540b1811c 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - "github.com/blang/semver" + "github.com/blang/semver/v4" _ "github.com/mattn/go-sqlite3" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -28,7 +28,13 @@ type MigratableLoader interface { var _ MigratableLoader = &sqlLoader{} -func NewSQLLiteLoader(db *sql.DB, opts ...DbOption) (MigratableLoader, error) { +// startDepth is the depth that channel heads should be assigned +// in the channel_entry table. This const exists so that all +// add modes (replaces, semver, and semver-skippatch) are +// consistent. +const startDepth = 0 + +func newSQLLoader(db *sql.DB, opts ...DbOption) (*sqlLoader, error) { options := defaultDBOptions() for _, o := range opts { o(options) @@ -46,6 +52,10 @@ func NewSQLLiteLoader(db *sql.DB, opts ...DbOption) (MigratableLoader, error) { return &sqlLoader{db: db, migrator: migrator, enableAlpha: options.EnableAlpha}, nil } +func NewSQLLiteLoader(db *sql.DB, opts ...DbOption) (MigratableLoader, error) { + return newSQLLoader(db, opts...) +} + func (s *sqlLoader) Migrate(ctx context.Context) error { if s.migrator == nil { return fmt.Errorf("no migrator configured") @@ -420,7 +430,7 @@ func (s *sqlLoader) AddPackageChannelsFromGraph(graph *registry.Package) error { // update each channel's graph for channelName, channel := range graph.Channels { currentNode := channel.Head - depth := 1 + depth := startDepth var previousNodeID int64 @@ -491,7 +501,12 @@ func (s *sqlLoader) AddPackageChannelsFromGraph(graph *registry.Package) error { // we got to the end of the channel graph if nextNode.IsEmpty() { - if len(channel.Nodes) != depth { + // expectedDepth is: + // + - 1 + // For example, if the number of nodes is 3 and the startDepth is 0, the expected depth is 2 (0, 1, 2) + // If the number of nodes is 5 and the startDepth is 3, the expected depth is 7 (3, 4, 5, 6, 7) + expectedDepth := len(channel.Nodes) + startDepth - 1 + if expectedDepth != depth { err := fmt.Errorf("Invalid graph: some (non-bottom) nodes defined in the graph were not mentioned as replacements of any node") errs = append(errs, err) } @@ -604,7 +619,7 @@ func (s *sqlLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani } for _, c := range channels { - res, err := addChannelEntry.Exec(c.Name, manifest.PackageName, c.CurrentCSVName, 0) + res, err := addChannelEntry.Exec(c.Name, manifest.PackageName, c.CurrentCSVName, startDepth) if err != nil { errs = append(errs, fmt.Errorf("failed to add channel %q in package %q: %s", c.Name, manifest.PackageName, err.Error())) continue @@ -616,7 +631,10 @@ func (s *sqlLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani } channelEntryCSVName := c.CurrentCSVName - depth := 1 + + // depth is set to `startDepth + 1` here because we already added the channel head + // with depth `startDepth` above. + depth := startDepth + 1 // Since this loop depends on following 'replaces', keep track of where it's been replaceCycle := map[string]bool{channelEntryCSVName: true} @@ -640,6 +658,16 @@ func (s *sqlLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani break } + deprecated, err := s.deprecated(tx, channelEntryCSVName) + if err != nil { + errs = append(errs, err) + break + } + if deprecated { + // The package is truncated below this point, we're done! + break + } + for _, skip := range skips { // add dummy channel entry for the skipped version skippedChannelEntry, err := addChannelEntry.Exec(c.Name, manifest.PackageName, skip, depth) @@ -703,15 +731,6 @@ func (s *sqlLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani errs = append(errs, err) break } - deprecated, err := s.deprecated(tx, channelEntryCSVName) - if err != nil { - errs = append(errs, err) - break - } - if deprecated { - // The package is truncated below this point, we're done! - break - } if _, _, _, err := s.getBundleSkipsReplacesVersion(tx, replaces); err != nil { errs = append(errs, fmt.Errorf("Invalid bundle %s, replaces nonexistent bundle %s", c.CurrentCSVName, replaces)) break @@ -963,6 +982,7 @@ func (s *sqlLoader) RemovePackage(packageName string) error { if _, err := deleteChannel.Exec(packageName); err != nil { return err } + return tx.Commit() }(); err != nil { return err @@ -1275,38 +1295,35 @@ func (s *sqlLoader) addBundleProperties(tx *sql.Tx, bundle *registry.Bundle) err return nil } -func (s *sqlLoader) rmChannelEntry(tx *sql.Tx, csvName string) error { - rows, err := tx.Query(`SELECT entry_id FROM channel_entry WHERE operatorbundle_name=?`, csvName) - if err != nil { - return err - } - - var entryIDs []int64 - for rows.Next() { - var entryID sql.NullInt64 - rows.Scan(&entryID) - entryIDs = append(entryIDs, entryID.Int64) - } - if err := rows.Close(); err != nil { - return err +func (s *sqlLoader) rmSharedChannelEntry(tx *sql.Tx, csvName, unsharedCsv string) error { + if len(unsharedCsv) == 0 { + return nil } - updateChannelEntry, err := tx.Prepare(`UPDATE channel_entry SET replaces=NULL WHERE replaces=?`) - if err != nil { - return err - } - for _, id := range entryIDs { - if _, err := updateChannelEntry.Exec(id); err != nil { - updateChannelEntry.Close() - return err - } - } - err = updateChannelEntry.Close() + // remove any edges that replace bundle to be removed on the channels of the unsharedCsv + _, err := tx.Exec(` + UPDATE channel_entry + SET replaces=NULL + WHERE replaces IN ( + SELECT entry_id FROM channel_entry + WHERE operatorbundle_name = ? + AND channel_name IN ( + SELECT channel_name FROM channel_entry + WHERE operatorbundle_name = ? + ))`, csvName, unsharedCsv) if err != nil { return err } - _, err = tx.Exec(`DELETE FROM channel WHERE head_operatorbundle_name=?`, csvName) + // delete the channel entries on the shared channel list + _, err = tx.Exec(` + DELETE FROM channel_entry + WHERE operatorbundle_name = ? + AND channel_name IN ( + SELECT channel_name + FROM channel_entry + WHERE operatorbundle_name = ? + )`, csvName, unsharedCsv) if err != nil { return err } @@ -1314,82 +1331,124 @@ func (s *sqlLoader) rmChannelEntry(tx *sql.Tx, csvName string) error { return nil } -func getTailFromBundle(tx *sql.Tx, head string) (bundles []string, err error) { - getReplacesSkips := `SELECT replaces, skips FROM operatorbundle WHERE name=?` - isDefaultChannelHead := `SELECT head_operatorbundle_name FROM channel - INNER JOIN package ON channel.name = package.default_channel - WHERE channel.head_operatorbundle_name = ?` +type tailBundle struct { + name string + version string + bundlepath string + channels []string + replaces []string // in addition to the replaces chain, there may also be real skipped entries + replacedBy []string // to handle any chain where a skipped entry may be a part of another channel that should not be truncated +} - visited := map[string]struct{}{} - next := []string{head} +func getTailFromBundle(tx *sql.Tx, head string) (bundles map[string]tailBundle, err error) { + // traverse replaces chain and collect channel list for each bundle. + // This assumes that replaces chain for a bundle is the same across channels. + // only real bundles with entries in the operator_bundle table are returned. + getReplacesChain := ` + WITH RECURSIVE + replaces_entry (operatorbundle_name, replaces, replaced_by, channel_name, package_name) AS ( + SELECT channel_entry.operatorbundle_name, replaces.operatorbundle_name, replaced_by.operatorbundle_name, channel_entry.channel_name, channel_entry.package_name + FROM channel_entry + LEFT OUTER JOIN channel_entry AS replaces + ON replaces.entry_id = channel_entry.replaces + LEFT OUTER JOIN channel_entry AS replaced_by + ON channel_entry.entry_id = replaced_by.replaces + WHERE channel_entry.operatorbundle_name = ? + UNION + SELECT channel_entry.operatorbundle_name, replaces.operatorbundle_name, replaced_by.operatorbundle_name, channel_entry.channel_name, channel_entry.package_name + FROM channel_entry + JOIN replaces_entry + ON replaces_entry.replaces = channel_entry.operatorbundle_name + LEFT OUTER JOIN channel_entry AS replaces + ON channel_entry.replaces = replaces.entry_id + LEFT OUTER JOIN channel_entry AS replaced_by + ON channel_entry.entry_id = replaced_by.replaces + ) + SELECT + replaces_entry.operatorbundle_name, + operatorbundle.version, + operatorbundle.bundlepath, + GROUP_CONCAT(DISTINCT replaces_entry.channel_name), + GROUP_CONCAT(DISTINCT replaces_entry.replaces), + GROUP_CONCAT(DISTINCT replaces_entry.replaced_by) + FROM replaces_entry + LEFT OUTER JOIN operatorbundle + ON operatorbundle.name = replaces_entry.operatorbundle_name + GROUP BY replaces_entry.operatorbundle_name, replaces_entry.package_name + ORDER BY replaces_entry.channel_name, replaces_entry.replaces, replaces_entry.replaced_by` - for len(next) > 0 { - // Pop the next bundle off of the queue - bundle := next[0] - next = next[1:] // Potentially inefficient queue implementation, but this function is only used when deprecate is called + getDefaultChannelHead := ` + SELECT head_operatorbundle_name FROM channel + INNER JOIN package ON channel.name = package.default_channel AND channel.package_name = package.name + INNER JOIN channel_entry on channel.package_name = channel_entry.package_name + WHERE channel_entry.operatorbundle_name = ? + LIMIT 1` - // Check if next is the head of the defaultChannel - // If it is, the defaultChannel would be removed -- this is not allowed because we cannot know which channel to promote as the new default - var err error - if row := tx.QueryRow(isDefaultChannelHead, bundle); row != nil { - err = row.Scan(&sql.NullString{}) - } - if err == nil { - // A nil error indicates that next is the default channel head - return nil, registry.ErrRemovingDefaultChannelDuringDeprecation - } else if err != sql.ErrNoRows { - return nil, err - } - - rows, err := tx.QueryContext(context.TODO(), getReplacesSkips, bundle) - if err != nil { - return nil, err - } + row := tx.QueryRow(getDefaultChannelHead, head) + if row == nil { + return nil, fmt.Errorf("could not find default channel head for %s", head) + } + var defaultChannelHead sql.NullString + err = row.Scan(&defaultChannelHead) + if err != nil { + return nil, fmt.Errorf("error getting default channel head for %s: %v", head, err) + } + if !defaultChannelHead.Valid || len(defaultChannelHead.String) == 0 { + return nil, fmt.Errorf("invalid default channel head '%s' for %s", defaultChannelHead.String, head) + } + rows, err := tx.QueryContext(context.TODO(), getReplacesChain, head) + if err != nil { + return nil, err + } + replacesChain := map[string]tailBundle{} + for rows.Next() { var ( - replaces sql.NullString - skips sql.NullString + bundle sql.NullString + version sql.NullString + bundlepath sql.NullString + channels sql.NullString + replaces sql.NullString + replacedBy sql.NullString ) - if rows.Next() { - if err := rows.Scan(&replaces, &skips); err != nil { - if nerr := rows.Close(); nerr != nil { - return nil, nerr - } - return nil, err + if err := rows.Scan(&bundle, &version, &bundlepath, &channels, &replaces, &replacedBy); err != nil { + if nerr := rows.Close(); nerr != nil { + return nil, nerr } - } - if err := rows.Close(); err != nil { return nil, err } - if skips.Valid && skips.String != "" { - for _, skip := range strings.Split(skips.String, ",") { - if _, ok := visited[skip]; ok { - // We've already visited this bundle's subgraph - continue - } - visited[skip] = struct{}{} - next = append(next, skip) - } + if !bundle.Valid || len(bundle.String) == 0 { + return nil, fmt.Errorf("invalid tail bundle %v for %s", bundle, head) } - if replaces.Valid && replaces.String != "" { - r := replaces.String - if _, ok := visited[r]; ok { - // We've already visited this bundle's subgraph - continue - } - visited[r] = struct{}{} - next = append(next, r) + + if bundle.String == defaultChannelHead.String { + // A nil error indicates that next is the default channel head + return nil, registry.ErrRemovingDefaultChannelDuringDeprecation + } + var channelList, replacesList, replacedList []string + if channels.Valid && len(channels.String) > 0 { + channelList = strings.Split(channels.String, ",") + } + if replaces.Valid && len(replaces.String) > 0 { + replacesList = strings.Split(replaces.String, ",") + } + if replacedBy.Valid && len(replacedBy.String) > 0 { + replacedList = strings.Split(replacedBy.String, ",") } - } - // The tail is exactly the set of bundles we visited while traversing the graph from head - var tail []string - for v := range visited { - tail = append(tail, v) + replacesChain[bundle.String] = tailBundle{ + name: bundle.String, + version: version.String, + bundlepath: bundlepath.String, + channels: channelList, + replaces: replacesList, + replacedBy: replacedList, + } } - - return tail, nil - + if err := rows.Close(); err != nil { + return nil, err + } + return replacesChain, nil } func getBundleNameAndVersionForImage(tx *sql.Tx, path string) (string, string, error) { @@ -1431,17 +1490,73 @@ func (s *sqlLoader) DeprecateBundle(path string) error { return err } - for _, bundle := range tailBundles { - if err := s.rmChannelEntry(tx, bundle); err != nil { + // track bundles that have already been added to removeOrDeprecate + removeOrDeprecate := []string{name} + seen := map[string]bool{name: true} + + headChannelsMap := map[string]struct{}{} + if _, ok := tailBundles[name]; ok { + for _, c := range tailBundles[name].channels { + headChannelsMap[c] = struct{}{} + } + } + + // Traverse replaces chain, removing bundles from all channels the initial deprecated bundle belongs to. + // If a bundle is removed from all its channels, it is truncated. +deprecate: + for ; len(removeOrDeprecate) > 0; removeOrDeprecate = removeOrDeprecate[1:] { + bundle := removeOrDeprecate[0] + if _, ok := tailBundles[bundle]; !ok { + continue + } + for _, b := range tailBundles[bundle].replaces { + if !seen[b] { + removeOrDeprecate = append(removeOrDeprecate, b) + seen[b] = true + } + } + if bundle == name { + // head bundle gets deprecated separately + continue + } + + // remove all channel_entries for bundle with same channel as the deprecated one + if err := s.rmSharedChannelEntry(tx, bundle, name); err != nil { return err } + + //rm channel entries for channels + if len(tailBundles[bundle].channels) > len(headChannelsMap) { + // bundle belongs to some channel that the initial deprecated bundle does not - we can't truncate this + continue + } + for _, c := range tailBundles[bundle].channels { + if _, ok := headChannelsMap[c]; !ok { + // bundle belongs to some channel that the initial deprecated bundle does not - we can't truncate this + continue deprecate + } + } + for _, b := range tailBundles[bundle].replacedBy { + if _, ok := tailBundles[b]; !ok { + // bundle is a replaces edge for some csv that isn't in the deprecated tail, can't be replaced safely. + continue deprecate + } + } + + // Remove bundle if err := s.rmBundle(tx, bundle); err != nil { return err } + + } + // remove links to deprecated/truncated bundles to avoid regenerating these on add/overwrite + _, err = tx.Exec(`UPDATE channel_entry SET replaces=NULL WHERE operatorbundle_name=?`, name) + if err != nil { + return err } - // Remove any channels that start with the deprecated bundle - _, err = tx.Exec(fmt.Sprintf(`DELETE FROM channel WHERE head_operatorbundle_name="%s"`, name)) + // a channel with a deprecated head is still visible on the console unless the channel_entry table has no entries for it + _, err = tx.Exec(`DELETE FROM channel WHERE head_operatorbundle_name=?`, name) if err != nil { return err } @@ -1462,6 +1577,9 @@ func (s *sqlLoader) DeprecateBundle(path string) error { return err } + if err := s.rmStrandedDeprecated(tx); err != nil { + return err + } return tx.Commit() } @@ -1478,11 +1596,73 @@ func (s *sqlLoader) RemoveStrandedBundles() error { return err } + if err := s.rmStrandedDeprecated(tx); err != nil { + return err + } return tx.Commit() } func (s *sqlLoader) rmStrandedBundles(tx *sql.Tx) error { - _, err := tx.Exec("DELETE FROM operatorbundle WHERE name NOT IN(select operatorbundle_name from channel_entry)") + // Remove everything without a channel_entry except deprecated channel heads + _, err := tx.Exec("DELETE FROM operatorbundle WHERE name NOT IN(select operatorbundle_name from channel_entry) AND name NOT IN (SELECT operatorbundle_name FROM deprecated)") + return err +} + +func (s *sqlLoader) rmStrandedDeprecated(tx *sql.Tx) error { + // Remove any deprecated channel heads which have no entries in the channel/channel_entry table to avoid being displayed on the console + rows, err := tx.Query("SELECT DISTINCT name FROM package") + if err != nil { + return err + } + defer rows.Close() + knownPackages := map[string]struct{}{} + for rows.Next() { + var pkg sql.NullString + if err := rows.Scan(&pkg); err != nil { + return err + } + if !pkg.Valid || len(pkg.String) == 0 { + return fmt.Errorf("invalid package %v", pkg) + } + knownPackages[pkg.String] = struct{}{} + } + + packagePropertiesQuery := `select distinct operatorbundle_name, value from properties where type = ?` + pRows, err := tx.Query(packagePropertiesQuery, registry.PackageType) + if err != nil { + return err + } + defer pRows.Close() + + for pRows.Next() { + var bundle, value sql.NullString + if err := pRows.Scan(&bundle, &value); err != nil { + return err + } + + if !bundle.Valid || len(bundle.String) == 0 { + return fmt.Errorf("invalid bundle %v", bundle) + } + + if !value.Valid || len(value.String) == 0 { + return fmt.Errorf("invalid package property on %v: %v", bundle, value) + } + + var prop registry.PackageProperty + if err := json.Unmarshal([]byte(value.String), &prop); err != nil { + return err + } + + if _, ok := knownPackages[prop.PackageName]; !ok { + if err := s.rmBundle(tx, bundle.String); err != nil { + return err + } + } + } + + // Clean up the deprecated table by dropping all truncated bundles + // (see pkg/sqlite/migrations/013_rm_truncated_deprecations.go for more details) + _, err = tx.Exec(`DELETE FROM deprecated WHERE deprecated.operatorbundle_name NOT IN (SELECT DISTINCT name FROM operatorbundle)`) return err } @@ -1536,3 +1716,140 @@ func (s *sqlLoader) deprecated(tx *sql.Tx, name string) (bool, error) { // Ignore any deprecated bundles return err == nil, err } + +// DeprecationAwareLoader understands how bundle deprecations are handled in SQLite and decorates +// the sqlLoader with proxy methods that handle deprecation related table housekeeping. +type DeprecationAwareLoader struct { + *sqlLoader +} + +// NewDeprecationAwareLoader returns a new DeprecationAwareLoader. +func NewDeprecationAwareLoader(db *sql.DB, opts ...DbOption) (*DeprecationAwareLoader, error) { + loader, err := newSQLLoader(db, opts...) + if err != nil { + return nil, err + } + + return &DeprecationAwareLoader{sqlLoader: loader}, nil +} + +func (d *DeprecationAwareLoader) clearLastDeprecatedInPackage(pkg string) error { + tx, err := d.db.Begin() + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + + // The last deprecated bundles for a package will still have "tombstone" records in channel_entry (among other tables). + // Use that info to relate the package to a set of rows in the deprecated table. + _, err = tx.Exec(`DELETE FROM deprecated WHERE deprecated.operatorbundle_name IN (SELECT DISTINCT deprecated.operatorbundle_name FROM (deprecated INNER JOIN channel_entry ON deprecated.operatorbundle_name = channel_entry.operatorbundle_name) WHERE channel_entry.package_name = ?)`, pkg) + if err != nil { + return err + } + + return tx.Commit() +} + +func (d *DeprecationAwareLoader) RemovePackage(pkg string) error { + if err := d.clearLastDeprecatedInPackage(pkg); err != nil { + return err + } + + return d.sqlLoader.RemovePackage(pkg) +} + +// RemoveOverwrittenChannelHead removes a bundle if it is the channel head and has nothing replacing it +func (s sqlLoader) RemoveOverwrittenChannelHead(pkg, bundle string) error { + tx, err := s.db.Begin() + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + // check if bundle has anything that replaces it + getBundlesThatReplaceHeadQuery := `SELECT DISTINCT operatorbundle.name AS replaces, channel_entry.channel_name + FROM channel_entry + LEFT OUTER JOIN channel_entry replaces + ON replaces.replaces = channel_entry.entry_id + INNER JOIN operatorbundle + ON replaces.operatorbundle_name = operatorbundle.name + WHERE channel_entry.package_name = ? + AND channel_entry.operatorbundle_name = ? + LIMIT 1` + + rows, err := tx.QueryContext(context.TODO(), getBundlesThatReplaceHeadQuery, pkg, bundle) + if err != nil { + return err + } + defer rows.Close() + if rows != nil { + for rows.Next() { + var replaces, channel sql.NullString + if err := rows.Scan(&replaces, &channel); err != nil { + return err + } + // This is not a head bundle for all channels it is a member of. Cannot remove + return fmt.Errorf("cannot overwrite bundle %s from package %s: replaced by %s on channel %s", bundle, pkg, replaces.String, channel.String) + } + } + + getReplacingBundlesQuery := ` + SELECT replaces.name as replaces, channel_entry.channel_name, min(depth) + from channel_entry + LEFT JOIN ( + SELECT entry_id, name FROM channel_entry + INNER JOIN operatorbundle + ON channel_entry.operatorbundle_name = operatorbundle.name + ) AS replaces + ON channel_entry.replaces = replaces.entry_id + WHERE channel_entry.package_name = ? + AND channel_entry.operatorbundle_name = ? + GROUP BY channel_name + ` + + pRows, err := tx.QueryContext(context.TODO(), getReplacingBundlesQuery, pkg, bundle) + if err != nil { + return err + } + defer pRows.Close() + + channelHeadUpdateQuery := `UPDATE channel SET head_operatorbundle_name = ? WHERE package_name = ? AND name = ? AND head_operatorbundle_name = ?` + for pRows.Next() { + var replaces, channel sql.NullString + var depth sql.NullInt64 + if err := pRows.Scan(&replaces, &channel, &depth); err != nil { + return err + } + + if !channel.Valid { + return fmt.Errorf("channel name column corrupt for bundle %s", bundle) + } + if replaces.Valid && len(replaces.String) != 0 { + // replace any valid entries as channel heads to avoid rmBundle from truncating the entire channel + if _, err = tx.Exec(channelHeadUpdateQuery, replaces, pkg, channel, bundle); err != nil { + return err + } + } else { + // NULL default channel before dropping to let packagemanifest detect default channel + if _, err := tx.Exec(`UPDATE channel SET head_operatorbundle_name = NULL WHERE name = ? AND package_name = ? AND name IN (SELECT default_channel FROM package WHERE name = ?)`, channel, pkg, pkg); err != nil { + return err + } + } + } + + if err := s.rmBundle(tx, bundle); err != nil { + return err + } + // remove from deprecated + if _, err = tx.Exec(`DELETE FROM deprecated WHERE deprecated.operatorbundle_name = ?`, bundle); err != nil { + return err + } + err = tx.Commit() + if err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/013_rm_truncated_deprecations.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/013_rm_truncated_deprecations.go new file mode 100644 index 00000000000..75ad3151798 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/013_rm_truncated_deprecations.go @@ -0,0 +1,31 @@ +package migrations + +import ( + "context" + "database/sql" +) + +const RmTruncatedDeprecationsMigrationKey = 13 + +// Register this migration +func init() { + registerMigration(RmTruncatedDeprecationsMigrationKey, rmTruncatedDeprecationsMigration) +} + +var rmTruncatedDeprecationsMigration = &Migration{ + Id: RmTruncatedDeprecationsMigrationKey, + Up: func(ctx context.Context, tx *sql.Tx) error { + + // Delete deprecation history for all bundles that no longer exist in the operatorbundle table + // These bundles have been truncated by more recent deprecations and would only confuse future operations on an index; + // e.g. adding a previously truncated bundle to a package removed via `opm index|registry rm` would lead to that bundle + // being deprecated + _, err := tx.ExecContext(ctx, `DELETE FROM deprecated WHERE deprecated.operatorbundle_name NOT IN (SELECT DISTINCT deprecated.operatorbundle_name FROM (deprecated INNER JOIN operatorbundle ON deprecated.operatorbundle_name = operatorbundle.name))`) + + return err + }, + Down: func(ctx context.Context, tx *sql.Tx) error { + // No-op + return nil + }, +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/206982811273848759.db-journal b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/206982811273848759.db-journal new file mode 100644 index 00000000000..f012d62c9a4 Binary files /dev/null and b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/206982811273848759.db-journal differ diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/2766156202339306673.db-journal b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/2766156202339306673.db-journal new file mode 100644 index 00000000000..2c00356f037 Binary files /dev/null and b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/2766156202339306673.db-journal differ diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go index 5b683403598..6d46d544c26 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go @@ -35,25 +35,44 @@ func (a dbQuerierAdapter) QueryContext(ctx context.Context, query string, args . type SQLQuerier struct { db Querier + querierConfig } var _ registry.Query = &SQLQuerier{} -func NewSQLLiteQuerier(dbFilename string) (*SQLQuerier, error) { +type querierConfig struct { + omitManifests bool +} + +type SQLiteQuerierOption func(*querierConfig) + +// If true, ListBundles will omit inline manifests (the object and +// csvJson fields) from response elements that contain a bundle image +// reference. +func OmitManifests(b bool) SQLiteQuerierOption { + return func(c *querierConfig) { + c.omitManifests = b + } +} + +func NewSQLLiteQuerier(dbFilename string, opts ...SQLiteQuerierOption) (*SQLQuerier, error) { db, err := OpenReadOnly(dbFilename) if err != nil { return nil, err } - - return &SQLQuerier{dbQuerierAdapter{db}}, nil + return NewSQLLiteQuerierFromDb(db, opts...), nil } -func NewSQLLiteQuerierFromDb(db *sql.DB) *SQLQuerier { - return &SQLQuerier{dbQuerierAdapter{db}} +func NewSQLLiteQuerierFromDb(db *sql.DB, opts ...SQLiteQuerierOption) *SQLQuerier { + return NewSQLLiteQuerierFromDBQuerier(dbQuerierAdapter{db}, opts...) } -func NewSQLLiteQuerierFromDBQuerier(q Querier) *SQLQuerier { - return &SQLQuerier{q} +func NewSQLLiteQuerierFromDBQuerier(q Querier, opts ...SQLiteQuerierOption) *SQLQuerier { + sq := SQLQuerier{db: q} + for _, opt := range opts { + opt(&sq.querierConfig) + } + return &sq } func (s *SQLQuerier) ListTables(ctx context.Context) ([]string, error) { @@ -268,64 +287,32 @@ func (s *SQLQuerier) GetBundle(ctx context.Context, pkgName, channelName, csvNam return out, nil } -func (s *SQLQuerier) GetBundleForChannel(ctx context.Context, pkgName string, channelName string) (*api.Bundle, error) { - query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath, operatorbundle.version, operatorbundle.skiprange FROM channel - INNER JOIN operatorbundle ON channel.head_operatorbundle_name=operatorbundle.name - INNER JOIN channel_entry ON (channel_entry.channel_name = channel.name and channel_entry.package_name=channel.package_name and channel_entry.operatorbundle_name=operatorbundle.name) - WHERE channel.package_name=? AND channel.name=? LIMIT 1` - rows, err := s.db.QueryContext(ctx, query, pkgName, channelName) +func (s *SQLQuerier) GetBundleForChannel(ctx context.Context, pkg string, channel string) (*api.Bundle, error) { + query := ` +SELECT operatorbundle.name, operatorbundle.csv FROM operatorbundle INNER JOIN channel +ON channel.head_operatorbundle_name = operatorbundle.name +WHERE channel.name = :channel AND channel.package_name = :package` + rows, err := s.db.QueryContext(ctx, query, sql.Named("channel", channel), sql.Named("package", pkg)) if err != nil { return nil, err } defer rows.Close() if !rows.Next() { - return nil, fmt.Errorf("no entry found for %s %s", pkgName, channelName) - } - var entryId sql.NullInt64 - var name sql.NullString - var bundle sql.NullString - var bundlePath sql.NullString - var version sql.NullString - var skipRange sql.NullString - if err := rows.Scan(&entryId, &name, &bundle, &bundlePath, &version, &skipRange); err != nil { - return nil, err - } - - out := &api.Bundle{} - if bundle.Valid && bundle.String != "" { - out, err = registry.BundleStringToAPIBundle(bundle.String) - if err != nil { - return nil, err - } - } - out.CsvName = name.String - out.PackageName = pkgName - out.ChannelName = channelName - out.BundlePath = bundlePath.String - out.Version = version.String - out.SkipRange = skipRange.String - - provided, required, err := s.GetApisForEntry(ctx, entryId.Int64) - if err != nil { - return nil, err - } - out.ProvidedApis = provided - out.RequiredApis = required - - dependencies, err := s.GetDependenciesForBundle(ctx, name.String, version.String, bundlePath.String) - if err != nil { - return nil, err + return nil, fmt.Errorf("no entry found for %s %s", pkg, channel) } - out.Dependencies = dependencies - - properties, err := s.GetPropertiesForBundle(ctx, name.String, version.String, bundlePath.String) - if err != nil { + var ( + name sql.NullString + csv sql.NullString + ) + if err := rows.Scan(&name, &csv); err != nil { return nil, err } - out.Properties = properties - return out, nil + return &api.Bundle{ + CsvName: name.String, + CsvJson: csv.String, + }, nil } func (s *SQLQuerier) GetChannelEntriesThatReplace(ctx context.Context, name string) (entries []*registry.ChannelEntry, err error) { @@ -970,10 +957,20 @@ tip (depth) AS ( INNER JOIN channel_entry AS skipped_entry ON skips_entry.skips = skipped_entry.entry_id GROUP BY all_entry.operatorbundle_name, all_entry.package_name, all_entry.channel_name +), +merged_properties (bundle_name, merged) AS ( + SELECT operatorbundle_name, json_group_array(json_object('type', CAST(properties.type AS TEXT), 'value', CAST(properties.value AS TEXT))) + FROM properties + GROUP BY operatorbundle_name +), +merged_dependencies (bundle_name, merged) AS ( + SELECT operatorbundle_name, json_group_array(json_object('type', CAST(dependencies.type AS TEXT), 'value', CAST(dependencies.value AS TEXT))) + FROM dependencies + GROUP BY operatorbundle_name ) SELECT replaces_bundle.entry_id, - operatorbundle.bundle, + CASE WHEN :omit_manifests AND length(coalesce(operatorbundle.bundlepath, "")) > 0 THEN NULL ELSE operatorbundle.bundle END, operatorbundle.bundlepath, operatorbundle.name, replaces_bundle.package_name, @@ -982,10 +979,8 @@ SELECT skips_bundle.skips, operatorbundle.version, operatorbundle.skiprange, - dependencies.type, - dependencies.value, - properties.type, - properties.value + merged_dependencies.merged, + merged_properties.merged FROM replaces_bundle INNER JOIN operatorbundle ON replaces_bundle.operatorbundle_name = operatorbundle.name @@ -993,20 +988,18 @@ SELECT ON replaces_bundle.operatorbundle_name = skips_bundle.operatorbundle_name AND replaces_bundle.package_name = skips_bundle.package_name AND replaces_bundle.channel_name = skips_bundle.channel_name - LEFT OUTER JOIN dependencies - ON operatorbundle.name = dependencies.operatorbundle_name - LEFT OUTER JOIN properties - ON operatorbundle.name = properties.operatorbundle_name` + LEFT OUTER JOIN merged_dependencies + ON operatorbundle.name = merged_dependencies.bundle_name + LEFT OUTER JOIN merged_properties + ON operatorbundle.name = merged_properties.bundle_name` -func (s *SQLQuerier) ListBundles(ctx context.Context) ([]*api.Bundle, error) { - rows, err := s.db.QueryContext(ctx, listBundlesQuery) +func (s *SQLQuerier) SendBundles(ctx context.Context, stream registry.BundleSender) error { + rows, err := s.db.QueryContext(ctx, listBundlesQuery, sql.Named("omit_manifests", s.omitManifests)) if err != nil { - return nil, err + return err } defer rows.Close() - var bundles []*api.Bundle - bundlesMap := map[string]*api.Bundle{} for rows.Next() { var ( entryID sql.NullInt64 @@ -1019,101 +1012,109 @@ func (s *SQLQuerier) ListBundles(ctx context.Context) ([]*api.Bundle, error) { skips sql.NullString version sql.NullString skipRange sql.NullString - depType sql.NullString - depValue sql.NullString - propType sql.NullString - propValue sql.NullString + deps sql.NullString + props sql.NullString ) - if err := rows.Scan(&entryID, &bundle, &bundlePath, &bundleName, &pkgName, &channelName, &replaces, &skips, &version, &skipRange, &depType, &depValue, &propType, &propValue); err != nil { - return nil, err + if err := rows.Scan(&entryID, &bundle, &bundlePath, &bundleName, &pkgName, &channelName, &replaces, &skips, &version, &skipRange, &deps, &props); err != nil { + return err } if !bundleName.Valid || !version.Valid || !bundlePath.Valid || !channelName.Valid { continue } - bundleKey := fmt.Sprintf("%s/%s/%s/%s", bundleName.String, version.String, bundlePath.String, channelName.String) - bundleItem, ok := bundlesMap[bundleKey] - if ok { - if depType.Valid && depValue.Valid { - bundleItem.Dependencies = append(bundleItem.Dependencies, &api.Dependency{ - Type: depType.String, - Value: depValue.String, - }) + out := &api.Bundle{} + if bundle.Valid && bundle.String != "" { + out, err = registry.BundleStringToAPIBundle(bundle.String) + if err != nil { + return err } + } + out.CsvName = bundleName.String + out.PackageName = pkgName.String + out.ChannelName = channelName.String + out.BundlePath = bundlePath.String + out.Version = version.String + out.SkipRange = skipRange.String + out.Replaces = replaces.String + + if skips.Valid { + out.Skips = strings.Split(skips.String, ",") + } - if propType.Valid && propValue.Valid { - bundleItem.Properties = append(bundleItem.Properties, &api.Property{ - Type: propType.String, - Value: propValue.String, - }) - } - } else { - // Create new bundle - out := &api.Bundle{} - if bundle.Valid && bundle.String != "" { - out, err = registry.BundleStringToAPIBundle(bundle.String) - if err != nil { - return nil, err - } + if deps.Valid { + if err := json.Unmarshal([]byte(deps.String), &out.Dependencies); err != nil { + return err } + } + buildLegacyRequiredAPIs(out.Dependencies, &out.RequiredApis) + out.Dependencies = uniqueDeps(out.Dependencies) - out.CsvName = bundleName.String - out.PackageName = pkgName.String - out.ChannelName = channelName.String - out.BundlePath = bundlePath.String - out.Version = version.String - out.SkipRange = skipRange.String - out.Replaces = replaces.String - if skips.Valid { - out.Skips = strings.Split(skips.String, ",") + if props.Valid { + if err := json.Unmarshal([]byte(props.String), &out.Properties); err != nil { + return err } + } + buildLegacyProvidedAPIs(out.Properties, &out.ProvidedApis) + out.Properties = uniqueProps(out.Properties) + if err := stream.Send(out); err != nil { + return err + } + } - provided, required, err := s.GetApisForEntry(ctx, entryID.Int64) - if err != nil { - return nil, err - } - if len(provided) > 0 { - out.ProvidedApis = provided - } - if len(required) > 0 { - out.RequiredApis = required - } + return nil +} - if depType.Valid && depValue.Valid { - out.Dependencies = []*api.Dependency{{ - Type: depType.String, - Value: depValue.String, - }} - } +func (s *SQLQuerier) ListBundles(ctx context.Context) ([]*api.Bundle, error) { + var bundleSender registry.SliceBundleSender + err := s.SendBundles(ctx, &bundleSender) + if err != nil { + return nil, err + } + return bundleSender, nil - if propType.Valid && propValue.Valid { - out.Properties = []*api.Property{{ - Type: propType.String, - Value: propValue.String, - }} - } +} - bundlesMap[bundleKey] = out +func buildLegacyRequiredAPIs(src []*api.Dependency, dst *[]*api.GroupVersionKind) error { + for _, p := range src { + if p.GetType() != registry.GVKType { + continue + } + var value registry.GVKDependency + if err := json.Unmarshal([]byte(p.GetValue()), &value); err != nil { + return err } + *dst = append(*dst, &api.GroupVersionKind{ + Group: value.Group, + Version: value.Version, + Kind: value.Kind, + }) } + return nil +} - for _, v := range bundlesMap { - if len(v.Dependencies) > 1 { - newDeps := unique(v.Dependencies) - v.Dependencies = newDeps +func buildLegacyProvidedAPIs(src []*api.Property, dst *[]*api.GroupVersionKind) error { + for _, p := range src { + if p.GetType() != registry.GVKType { + continue } - if len(v.Properties) > 1 { - newProps := uniqueProps(v.Properties) - v.Properties = newProps + var value registry.GVKProperty + if err := json.Unmarshal([]byte(p.GetValue()), &value); err != nil { + return err } - bundles = append(bundles, v) + *dst = append(*dst, &api.GroupVersionKind{ + Group: value.Group, + Version: value.Version, + Kind: value.Kind, + }) } - - return bundles, nil + return nil } -func unique(deps []*api.Dependency) []*api.Dependency { +func uniqueDeps(deps []*api.Dependency) []*api.Dependency { + if len(deps) <= 1 { + return deps + } keys := make(map[string]struct{}) var list []*api.Dependency for _, entry := range deps { @@ -1127,6 +1128,9 @@ func unique(deps []*api.Dependency) []*api.Dependency { } func uniqueProps(props []*api.Property) []*api.Property { + if len(props) <= 1 { + return props + } keys := make(map[string]struct{}) var list []*api.Property for _, entry := range props { @@ -1334,3 +1338,58 @@ func (s *SQLQuerier) listBundleChannels(ctx context.Context, bundleName string) return channels, nil } + +// PackageFromDefaultChannelHeadBundle returns the package name if the provided bundle is the head of its default channel. +func (s *SQLQuerier) PackageFromDefaultChannelHeadBundle(ctx context.Context, bundle string) (string, error) { + packageFromDefaultChannelHeadBundle := ` + SELECT package_name FROM package, channel + WHERE channel.package_name == package.name + AND package.default_channel == channel.name + AND channel.head_operatorbundle_name = (SELECT name FROM operatorbundle WHERE bundlepath=? LIMIT 1) ` + + rows, err := s.db.QueryContext(ctx, packageFromDefaultChannelHeadBundle, bundle) + if err != nil { + return "", err + } + defer rows.Close() + + var packageName sql.NullString + for rows.Next() { + if err := rows.Scan(&packageName); err != nil { + return "", err + } + + if !packageName.Valid { + return "", fmt.Errorf("package name column corrupt for bundle %s", bundle) + } + } + + return packageName.String, nil +} + +// BundlePathForChannelHead returns the bundlepath for the given package and channel +func (s *SQLQuerier) BundlePathForChannelHead(ctx context.Context, pkg string, channel string) (string, error) { + bundlePathForChannelHeadQuery := ` + SELECT bundlepath FROM operatorbundle + INNER JOIN channel ON channel.head_operatorbundle_name = operatorbundle.name + WHERE channel.package_name = ? AND channel.name = ? +` + + rows, err := s.db.QueryContext(ctx, bundlePathForChannelHeadQuery, pkg, channel) + if err != nil { + return "", err + } + defer rows.Close() + + var bundlePath sql.NullString + for rows.Next() { + if err := rows.Scan(&bundlePath); err != nil { + return "", err + } + if !bundlePath.Valid { + return "", fmt.Errorf("bundlepath column corrupt for package %s, channel %s", pkg, channel) + } + } + + return bundlePath.String, nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/test-4831389563158288344.db-journal b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/test-4831389563158288344.db-journal new file mode 100644 index 00000000000..87874f0ee2b Binary files /dev/null and b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/test-4831389563158288344.db-journal differ diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/test-6426100070888298971.db-journal b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/test-6426100070888298971.db-journal new file mode 100644 index 00000000000..0066d330817 Binary files /dev/null and b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/test-6426100070888298971.db-journal differ diff --git a/vendor/google.golang.org/grpc/MAINTAINERS.md b/vendor/google.golang.org/grpc/MAINTAINERS.md index 093c82b3afe..c6672c0a3ef 100644 --- a/vendor/google.golang.org/grpc/MAINTAINERS.md +++ b/vendor/google.golang.org/grpc/MAINTAINERS.md @@ -8,17 +8,18 @@ See [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIB for general contribution guidelines. ## Maintainers (in alphabetical order) -- [canguler](https://github.com/canguler), Google LLC + - [cesarghali](https://github.com/cesarghali), Google LLC - [dfawley](https://github.com/dfawley), Google LLC - [easwars](https://github.com/easwars), Google LLC -- [jadekler](https://github.com/jadekler), Google LLC - [menghanl](https://github.com/menghanl), Google LLC - [srini100](https://github.com/srini100), Google LLC ## Emeritus Maintainers (in alphabetical order) - [adelez](https://github.com/adelez), Google LLC +- [canguler](https://github.com/canguler), Google LLC - [iamqizhao](https://github.com/iamqizhao), Google LLC +- [jadekler](https://github.com/jadekler), Google LLC - [jtattermusch](https://github.com/jtattermusch), Google LLC - [lyuxuan](https://github.com/lyuxuan), Google LLC - [makmukhi](https://github.com/makmukhi), Google LLC diff --git a/vendor/google.golang.org/grpc/Makefile b/vendor/google.golang.org/grpc/Makefile index 1f0722f1624..1f8960922b3 100644 --- a/vendor/google.golang.org/grpc/Makefile +++ b/vendor/google.golang.org/grpc/Makefile @@ -41,8 +41,6 @@ vetdeps: clean \ proto \ test \ - testappengine \ - testappenginedeps \ testrace \ vet \ vetdeps diff --git a/vendor/google.golang.org/grpc/NOTICE.txt b/vendor/google.golang.org/grpc/NOTICE.txt new file mode 100644 index 00000000000..530197749e9 --- /dev/null +++ b/vendor/google.golang.org/grpc/NOTICE.txt @@ -0,0 +1,13 @@ +Copyright 2014 gRPC authors. + +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/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go index ab531f4c0b8..178de0898aa 100644 --- a/vendor/google.golang.org/grpc/balancer/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/balancer.go @@ -75,24 +75,26 @@ func Get(name string) Builder { return nil } -// SubConn represents a gRPC sub connection. -// Each sub connection contains a list of addresses. gRPC will -// try to connect to them (in sequence), and stop trying the -// remainder once one connection is successful. +// A SubConn represents a single connection to a gRPC backend service. // -// The reconnect backoff will be applied on the list, not a single address. -// For example, try_on_all_addresses -> backoff -> try_on_all_addresses. +// Each SubConn contains a list of addresses. // -// All SubConns start in IDLE, and will not try to connect. To trigger -// the connecting, Balancers must call Connect. -// When the connection encounters an error, it will reconnect immediately. -// When the connection becomes IDLE, it will not reconnect unless Connect is -// called. +// All SubConns start in IDLE, and will not try to connect. To trigger the +// connecting, Balancers must call Connect. If a connection re-enters IDLE, +// Balancers must call Connect again to trigger a new connection attempt. // -// This interface is to be implemented by gRPC. Users should not need a -// brand new implementation of this interface. For the situations like -// testing, the new implementation should embed this interface. This allows -// gRPC to add new methods to this interface. +// gRPC will try to connect to the addresses in sequence, and stop trying the +// remainder once the first connection is successful. If an attempt to connect +// to all addresses encounters an error, the SubConn will enter +// TRANSIENT_FAILURE for a backoff period, and then transition to IDLE. +// +// Once established, if a connection is lost, the SubConn will transition +// directly to IDLE. +// +// This interface is to be implemented by gRPC. Users should not need their own +// implementation of this interface. For situations like testing, any +// implementations should embed this interface. This allows gRPC to add new +// methods to this interface. type SubConn interface { // UpdateAddresses updates the addresses used in this SubConn. // gRPC checks if currently-connected address is still in the new list. @@ -326,6 +328,20 @@ type Balancer interface { Close() } +// ExitIdler is an optional interface for balancers to implement. If +// implemented, ExitIdle will be called when ClientConn.Connect is called, if +// the ClientConn is idle. If unimplemented, ClientConn.Connect will cause +// all SubConns to connect. +// +// Notice: it will be required for all balancers to implement this in a future +// release. +type ExitIdler interface { + // ExitIdle instructs the LB policy to reconnect to backends / exit the + // IDLE state, if appropriate and possible. Note that SubConns that enter + // the IDLE state will not reconnect until SubConn.Connect is called. + ExitIdle() +} + // SubConnState describes the state of a SubConn. type SubConnState struct { // ConnectivityState is the connectivity state of the SubConn. @@ -353,8 +369,10 @@ var ErrBadResolverState = errors.New("bad resolver state") // // It's not thread safe. type ConnectivityStateEvaluator struct { - numReady uint64 // Number of addrConns in ready state. - numConnecting uint64 // Number of addrConns in connecting state. + numReady uint64 // Number of addrConns in ready state. + numConnecting uint64 // Number of addrConns in connecting state. + numTransientFailure uint64 // Number of addrConns in transient failure state. + numIdle uint64 // Number of addrConns in idle state. } // RecordTransition records state change happening in subConn and based on that @@ -362,9 +380,11 @@ type ConnectivityStateEvaluator struct { // // - If at least one SubConn in Ready, the aggregated state is Ready; // - Else if at least one SubConn in Connecting, the aggregated state is Connecting; -// - Else the aggregated state is TransientFailure. +// - Else if at least one SubConn is TransientFailure, the aggregated state is Transient Failure; +// - Else if at least one SubConn is Idle, the aggregated state is Idle; +// - Else there are no subconns and the aggregated state is Transient Failure // -// Idle and Shutdown are not considered. +// Shutdown is not considered. func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State { // Update counters. for idx, state := range []connectivity.State{oldState, newState} { @@ -374,6 +394,10 @@ func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState conne cse.numReady += updateVal case connectivity.Connecting: cse.numConnecting += updateVal + case connectivity.TransientFailure: + cse.numTransientFailure += updateVal + case connectivity.Idle: + cse.numIdle += updateVal } } @@ -384,5 +408,11 @@ func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState conne if cse.numConnecting > 0 { return connectivity.Connecting } + if cse.numTransientFailure > 0 { + return connectivity.TransientFailure + } + if cse.numIdle > 0 { + return connectivity.Idle + } return connectivity.TransientFailure } diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go index c883efa0bbf..8dd504299fe 100644 --- a/vendor/google.golang.org/grpc/balancer/base/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go @@ -133,6 +133,7 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error { } b.subConns[aNoAttrs] = subConnInfo{subConn: sc, attrs: a.Attributes} b.scStates[sc] = connectivity.Idle + b.csEvltr.RecordTransition(connectivity.Shutdown, connectivity.Idle) sc.Connect() } else { // Always update the subconn's address in case the attributes @@ -213,10 +214,14 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su } return } - if oldS == connectivity.TransientFailure && s == connectivity.Connecting { - // Once a subconn enters TRANSIENT_FAILURE, ignore subsequent + if oldS == connectivity.TransientFailure && + (s == connectivity.Connecting || s == connectivity.Idle) { + // Once a subconn enters TRANSIENT_FAILURE, ignore subsequent IDLE or // CONNECTING transitions to prevent the aggregated state from being // always CONNECTING when many backends exist but are all down. + if s == connectivity.Idle { + sc.Connect() + } return } b.scStates[sc] = s @@ -242,7 +247,6 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su b.state == connectivity.TransientFailure { b.regeneratePicker() } - b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.picker}) } @@ -251,6 +255,11 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su func (b *baseBalancer) Close() { } +// ExitIdle is a nop because the base balancer attempts to stay connected to +// all SubConns at all times. +func (b *baseBalancer) ExitIdle() { +} + // NewErrPicker returns a Picker that always returns err on Pick(). func NewErrPicker(err error) balancer.Picker { return &errPicker{err: err} diff --git a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go index 43c2a15373a..274eb2f8580 100644 --- a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go +++ b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go @@ -47,11 +47,11 @@ func init() { type rrPickerBuilder struct{} func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker { - logger.Infof("roundrobinPicker: newPicker called with info: %v", info) + logger.Infof("roundrobinPicker: Build called with info: %v", info) if len(info.ReadySCs) == 0 { return base.NewErrPicker(balancer.ErrNoSubConnAvailable) } - var scs []balancer.SubConn + scs := make([]balancer.SubConn, 0, len(info.ReadySCs)) for sc := range info.ReadySCs { scs = append(scs, sc) } diff --git a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go index dd839796397..f4ea6174682 100644 --- a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go +++ b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go @@ -37,15 +37,20 @@ type scStateUpdate struct { err error } +// exitIdle contains no data and is just a signal sent on the updateCh in +// ccBalancerWrapper to instruct the balancer to exit idle. +type exitIdle struct{} + // ccBalancerWrapper is a wrapper on top of cc for balancers. // It implements balancer.ClientConn interface. type ccBalancerWrapper struct { - cc *ClientConn - balancerMu sync.Mutex // synchronizes calls to the balancer - balancer balancer.Balancer - updateCh *buffer.Unbounded - closed *grpcsync.Event - done *grpcsync.Event + cc *ClientConn + balancerMu sync.Mutex // synchronizes calls to the balancer + balancer balancer.Balancer + hasExitIdle bool + updateCh *buffer.Unbounded + closed *grpcsync.Event + done *grpcsync.Event mu sync.Mutex subConns map[*acBalancerWrapper]struct{} @@ -61,6 +66,7 @@ func newCCBalancerWrapper(cc *ClientConn, b balancer.Builder, bopts balancer.Bui } go ccb.watcher() ccb.balancer = b.Build(ccb, bopts) + _, ccb.hasExitIdle = ccb.balancer.(balancer.ExitIdler) return ccb } @@ -86,6 +92,17 @@ func (ccb *ccBalancerWrapper) watcher() { ccb.cc.removeAddrConn(u.getAddrConn(), errConnDrain) } ccb.mu.Unlock() + case exitIdle: + if ccb.cc.GetState() == connectivity.Idle { + if ei, ok := ccb.balancer.(balancer.ExitIdler); ok { + // We already checked that the balancer implements + // ExitIdle before pushing the event to updateCh, but + // check conditionally again as defensive programming. + ccb.balancerMu.Lock() + ei.ExitIdle() + ccb.balancerMu.Unlock() + } + } default: logger.Errorf("ccBalancerWrapper.watcher: unknown update %+v, type %T", t, t) } @@ -118,6 +135,14 @@ func (ccb *ccBalancerWrapper) close() { <-ccb.done.Done() } +func (ccb *ccBalancerWrapper) exitIdle() bool { + if !ccb.hasExitIdle { + return false + } + ccb.updateCh.Put(exitIdle{}) + return true +} + func (ccb *ccBalancerWrapper) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State, err error) { // When updating addresses for a SubConn, if the address in use is not in // the new addresses, the old ac will be tearDown() and a new ac will be @@ -144,8 +169,8 @@ func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnStat func (ccb *ccBalancerWrapper) resolverError(err error) { ccb.balancerMu.Lock() + defer ccb.balancerMu.Unlock() ccb.balancer.ResolverError(err) - ccb.balancerMu.Unlock() } func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { @@ -239,17 +264,17 @@ func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { return } - ac, err := cc.newAddrConn(addrs, opts) + newAC, err := cc.newAddrConn(addrs, opts) if err != nil { channelz.Warningf(logger, acbw.ac.channelzID, "acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", err) return } - acbw.ac = ac - ac.mu.Lock() - ac.acbw = acbw - ac.mu.Unlock() + acbw.ac = newAC + newAC.mu.Lock() + newAC.acbw = acbw + newAC.mu.Unlock() if acState != connectivity.Idle { - ac.connect() + go newAC.connect() } } } @@ -257,7 +282,7 @@ func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { func (acbw *acBalancerWrapper) Connect() { acbw.mu.Lock() defer acbw.mu.Unlock() - acbw.ac.connect() + go acbw.ac.connect() } func (acbw *acBalancerWrapper) getAddrConn() *addrConn { diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index b2bccfed136..34cc4c948db 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -322,6 +322,7 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * // A blocking dial blocks until the clientConn is ready. if cc.dopts.block { for { + cc.Connect() s := cc.GetState() if s == connectivity.Ready { break @@ -539,12 +540,31 @@ func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connec // // Experimental // -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. +// Notice: This API is EXPERIMENTAL and may be changed or removed in a later +// release. func (cc *ClientConn) GetState() connectivity.State { return cc.csMgr.getState() } +// Connect causes all subchannels in the ClientConn to attempt to connect if +// the channel is idle. Does not wait for the connection attempts to begin +// before returning. +// +// Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a later +// release. +func (cc *ClientConn) Connect() { + cc.mu.Lock() + defer cc.mu.Unlock() + if cc.balancerWrapper != nil && cc.balancerWrapper.exitIdle() { + return + } + for ac := range cc.conns { + go ac.connect() + } +} + func (cc *ClientConn) scWatcher() { for { select { @@ -845,8 +865,7 @@ func (ac *addrConn) connect() error { ac.updateConnectivityState(connectivity.Connecting, nil) ac.mu.Unlock() - // Start a goroutine connecting to the server asynchronously. - go ac.resetTransport() + ac.resetTransport() return nil } @@ -883,6 +902,10 @@ func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool { // ac.state is Ready, try to find the connected address. var curAddrFound bool for _, a := range addrs { + // a.ServerName takes precedent over ClientConn authority, if present. + if a.ServerName == "" { + a.ServerName = ac.cc.authority + } if reflect.DeepEqual(ac.curAddr, a) { curAddrFound = true break @@ -1135,112 +1158,86 @@ func (ac *addrConn) adjustParams(r transport.GoAwayReason) { } func (ac *addrConn) resetTransport() { - for i := 0; ; i++ { - if i > 0 { - ac.cc.resolveNow(resolver.ResolveNowOptions{}) - } + ac.mu.Lock() + if ac.state == connectivity.Shutdown { + ac.mu.Unlock() + return + } + + addrs := ac.addrs + backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx) + // This will be the duration that dial gets to finish. + dialDuration := minConnectTimeout + if ac.dopts.minConnectTimeout != nil { + dialDuration = ac.dopts.minConnectTimeout() + } + + if dialDuration < backoffFor { + // Give dial more time as we keep failing to connect. + dialDuration = backoffFor + } + // We can potentially spend all the time trying the first address, and + // if the server accepts the connection and then hangs, the following + // addresses will never be tried. + // + // The spec doesn't mention what should be done for multiple addresses. + // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm + connectDeadline := time.Now().Add(dialDuration) + + ac.updateConnectivityState(connectivity.Connecting, nil) + ac.mu.Unlock() + if err := ac.tryAllAddrs(addrs, connectDeadline); err != nil { + ac.cc.resolveNow(resolver.ResolveNowOptions{}) + // After exhausting all addresses, the addrConn enters + // TRANSIENT_FAILURE. ac.mu.Lock() if ac.state == connectivity.Shutdown { ac.mu.Unlock() return } + ac.updateConnectivityState(connectivity.TransientFailure, err) - addrs := ac.addrs - backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx) - // This will be the duration that dial gets to finish. - dialDuration := minConnectTimeout - if ac.dopts.minConnectTimeout != nil { - dialDuration = ac.dopts.minConnectTimeout() - } - - if dialDuration < backoffFor { - // Give dial more time as we keep failing to connect. - dialDuration = backoffFor - } - // We can potentially spend all the time trying the first address, and - // if the server accepts the connection and then hangs, the following - // addresses will never be tried. - // - // The spec doesn't mention what should be done for multiple addresses. - // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm - connectDeadline := time.Now().Add(dialDuration) - - ac.updateConnectivityState(connectivity.Connecting, nil) - ac.transport = nil + // Backoff. + b := ac.resetBackoff ac.mu.Unlock() - newTr, addr, reconnect, err := ac.tryAllAddrs(addrs, connectDeadline) - if err != nil { - // After exhausting all addresses, the addrConn enters - // TRANSIENT_FAILURE. + timer := time.NewTimer(backoffFor) + select { + case <-timer.C: ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() - return - } - ac.updateConnectivityState(connectivity.TransientFailure, err) - - // Backoff. - b := ac.resetBackoff + ac.backoffIdx++ ac.mu.Unlock() - - timer := time.NewTimer(backoffFor) - select { - case <-timer.C: - ac.mu.Lock() - ac.backoffIdx++ - ac.mu.Unlock() - case <-b: - timer.Stop() - case <-ac.ctx.Done(): - timer.Stop() - return - } - continue + case <-b: + timer.Stop() + case <-ac.ctx.Done(): + timer.Stop() + return } ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() - newTr.Close(fmt.Errorf("reached connectivity state: SHUTDOWN")) - return + if ac.state != connectivity.Shutdown { + ac.updateConnectivityState(connectivity.Idle, err) } - ac.curAddr = addr - ac.transport = newTr - ac.backoffIdx = 0 - - hctx, hcancel := context.WithCancel(ac.ctx) - ac.startHealthCheck(hctx) ac.mu.Unlock() - - // Block until the created transport is down. And when this happens, - // we restart from the top of the addr list. - <-reconnect.Done() - hcancel() - // restart connecting - the top of the loop will set state to - // CONNECTING. This is against the current connectivity semantics doc, - // however it allows for graceful behavior for RPCs not yet dispatched - // - unfortunate timing would otherwise lead to the RPC failing even - // though the TRANSIENT_FAILURE state (called for by the doc) would be - // instantaneous. - // - // Ideally we should transition to Idle here and block until there is - // RPC activity that leads to the balancer requesting a reconnect of - // the associated SubConn. + return } + // Success; reset backoff. + ac.mu.Lock() + ac.backoffIdx = 0 + ac.mu.Unlock() } -// tryAllAddrs tries to creates a connection to the addresses, and stop when at the -// first successful one. It returns the transport, the address and a Event in -// the successful case. The Event fires when the returned transport disconnects. -func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.Time) (transport.ClientTransport, resolver.Address, *grpcsync.Event, error) { +// tryAllAddrs tries to creates a connection to the addresses, and stop when at +// the first successful one. It returns an error if no address was successfully +// connected, or updates ac appropriately with the new transport. +func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.Time) error { var firstConnErr error for _, addr := range addrs { ac.mu.Lock() if ac.state == connectivity.Shutdown { ac.mu.Unlock() - return nil, resolver.Address{}, nil, errConnClosing + return errConnClosing } ac.cc.mu.RLock() @@ -1255,9 +1252,9 @@ func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.T channelz.Infof(logger, ac.channelzID, "Subchannel picks a new address %q to connect", addr.Addr) - newTr, reconnect, err := ac.createTransport(addr, copts, connectDeadline) + err := ac.createTransport(addr, copts, connectDeadline) if err == nil { - return newTr, addr, reconnect, nil + return nil } if firstConnErr == nil { firstConnErr = err @@ -1266,57 +1263,54 @@ func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.T } // Couldn't connect to any address. - return nil, resolver.Address{}, nil, firstConnErr + return firstConnErr } -// createTransport creates a connection to addr. It returns the transport and a -// Event in the successful case. The Event fires when the returned transport -// disconnects. -func (ac *addrConn) createTransport(addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) (transport.ClientTransport, *grpcsync.Event, error) { - prefaceReceived := make(chan struct{}) - onCloseCalled := make(chan struct{}) - reconnect := grpcsync.NewEvent() +// createTransport creates a connection to addr. It returns an error if the +// address was not successfully connected, or updates ac appropriately with the +// new transport. +func (ac *addrConn) createTransport(addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) error { + // TODO: Delete prefaceReceived and move the logic to wait for it into the + // transport. + prefaceReceived := grpcsync.NewEvent() + connClosed := grpcsync.NewEvent() // addr.ServerName takes precedent over ClientConn authority, if present. if addr.ServerName == "" { addr.ServerName = ac.cc.authority } - once := sync.Once{} - onGoAway := func(r transport.GoAwayReason) { - ac.mu.Lock() - ac.adjustParams(r) - once.Do(func() { - if ac.state == connectivity.Ready { - // Prevent this SubConn from being used for new RPCs by setting its - // state to Connecting. - // - // TODO: this should be Idle when grpc-go properly supports it. - ac.updateConnectivityState(connectivity.Connecting, nil) - } - }) - ac.mu.Unlock() - reconnect.Fire() - } + hctx, hcancel := context.WithCancel(ac.ctx) + hcStarted := false // protected by ac.mu onClose := func() { ac.mu.Lock() - once.Do(func() { - if ac.state == connectivity.Ready { - // Prevent this SubConn from being used for new RPCs by setting its - // state to Connecting. - // - // TODO: this should be Idle when grpc-go properly supports it. - ac.updateConnectivityState(connectivity.Connecting, nil) - } - }) - ac.mu.Unlock() - close(onCloseCalled) - reconnect.Fire() + defer ac.mu.Unlock() + defer connClosed.Fire() + if !hcStarted || hctx.Err() != nil { + // We didn't start the health check or set the state to READY, so + // no need to do anything else here. + // + // OR, we have already cancelled the health check context, meaning + // we have already called onClose once for this transport. In this + // case it would be dangerous to clear the transport and update the + // state, since there may be a new transport in this addrConn. + return + } + hcancel() + ac.transport = nil + // Refresh the name resolver + ac.cc.resolveNow(resolver.ResolveNowOptions{}) + if ac.state != connectivity.Shutdown { + ac.updateConnectivityState(connectivity.Idle, nil) + } } - onPrefaceReceipt := func() { - close(prefaceReceived) + onGoAway := func(r transport.GoAwayReason) { + ac.mu.Lock() + ac.adjustParams(r) + ac.mu.Unlock() + onClose() } connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline) @@ -1325,27 +1319,67 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne copts.ChannelzParentID = ac.channelzID } - newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, onPrefaceReceipt, onGoAway, onClose) + newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, func() { prefaceReceived.Fire() }, onGoAway, onClose) if err != nil { // newTr is either nil, or closed. - channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v. Err: %v. Reconnecting...", addr, err) - return nil, nil, err + channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v. Err: %v", addr, err) + return err } select { - case <-time.After(time.Until(connectDeadline)): + case <-connectCtx.Done(): // We didn't get the preface in time. - newTr.Close(fmt.Errorf("failed to receive server preface within timeout")) - channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v: didn't receive server preface in time. Reconnecting...", addr) - return nil, nil, errors.New("timed out waiting for server handshake") - case <-prefaceReceived: + // The error we pass to Close() is immaterial since there are no open + // streams at this point, so no trailers with error details will be sent + // out. We just need to pass a non-nil error. + newTr.Close(transport.ErrConnClosing) + if connectCtx.Err() == context.DeadlineExceeded { + err := errors.New("failed to receive server preface within timeout") + channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v: %v", addr, err) + return err + } + return nil + case <-prefaceReceived.Done(): // We got the preface - huzzah! things are good. - case <-onCloseCalled: - // The transport has already closed - noop. - return nil, nil, errors.New("connection closed") - // TODO(deklerk) this should bail on ac.ctx.Done(). Add a test and fix. + ac.mu.Lock() + defer ac.mu.Unlock() + if connClosed.HasFired() { + // onClose called first; go idle but do nothing else. + if ac.state != connectivity.Shutdown { + ac.updateConnectivityState(connectivity.Idle, nil) + } + return nil + } + if ac.state == connectivity.Shutdown { + // This can happen if the subConn was removed while in `Connecting` + // state. tearDown() would have set the state to `Shutdown`, but + // would not have closed the transport since ac.transport would not + // been set at that point. + // + // We run this in a goroutine because newTr.Close() calls onClose() + // inline, which requires locking ac.mu. + // + // The error we pass to Close() is immaterial since there are no open + // streams at this point, so no trailers with error details will be sent + // out. We just need to pass a non-nil error. + go newTr.Close(transport.ErrConnClosing) + return nil + } + ac.curAddr = addr + ac.transport = newTr + hcStarted = true + ac.startHealthCheck(hctx) // Will set state to READY if appropriate. + return nil + case <-connClosed.Done(): + // The transport has already closed. If we received the preface, too, + // this is not an error. + select { + case <-prefaceReceived.Done(): + return nil + default: + return errors.New("connection closed before server preface received") + } } - return newTr, reconnect, nil } // startHealthCheck starts the health checking stream (RPC) to watch the health diff --git a/vendor/google.golang.org/grpc/connectivity/connectivity.go b/vendor/google.golang.org/grpc/connectivity/connectivity.go index 01015626150..4a89926422b 100644 --- a/vendor/google.golang.org/grpc/connectivity/connectivity.go +++ b/vendor/google.golang.org/grpc/connectivity/connectivity.go @@ -18,7 +18,6 @@ // Package connectivity defines connectivity semantics. // For details, see https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md. -// All APIs in this package are experimental. package connectivity import ( @@ -45,7 +44,7 @@ func (s State) String() string { return "SHUTDOWN" default: logger.Errorf("unknown connectivity state: %d", s) - return "Invalid-State" + return "INVALID_STATE" } } @@ -61,3 +60,35 @@ const ( // Shutdown indicates the ClientConn has started shutting down. Shutdown ) + +// ServingMode indicates the current mode of operation of the server. +// +// Only xDS enabled gRPC servers currently report their serving mode. +type ServingMode int + +const ( + // ServingModeStarting indicates that the server is starting up. + ServingModeStarting ServingMode = iota + // ServingModeServing indicates that the server contains all required + // configuration and is serving RPCs. + ServingModeServing + // ServingModeNotServing indicates that the server is not accepting new + // connections. Existing connections will be closed gracefully, allowing + // in-progress RPCs to complete. A server enters this mode when it does not + // contain the required configuration to serve RPCs. + ServingModeNotServing +) + +func (s ServingMode) String() string { + switch s { + case ServingModeStarting: + return "STARTING" + case ServingModeServing: + return "SERVING" + case ServingModeNotServing: + return "NOT_SERVING" + default: + logger.Errorf("unknown serving mode: %d", s) + return "INVALID_MODE" + } +} diff --git a/vendor/google.golang.org/grpc/credentials/go12.go b/vendor/google.golang.org/grpc/credentials/go12.go deleted file mode 100644 index ccbf35b3312..00000000000 --- a/vendor/google.golang.org/grpc/credentials/go12.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build go1.12 - -/* - * - * Copyright 2019 gRPC authors. - * - * 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. - * - */ - -package credentials - -import "crypto/tls" - -// This init function adds cipher suite constants only defined in Go 1.12. -func init() { - cipherSuiteLookup[tls.TLS_AES_128_GCM_SHA256] = "TLS_AES_128_GCM_SHA256" - cipherSuiteLookup[tls.TLS_AES_256_GCM_SHA384] = "TLS_AES_256_GCM_SHA384" - cipherSuiteLookup[tls.TLS_CHACHA20_POLY1305_SHA256] = "TLS_CHACHA20_POLY1305_SHA256" -} diff --git a/vendor/google.golang.org/grpc/credentials/tls.go b/vendor/google.golang.org/grpc/credentials/tls.go index 8ee7124f226..784822d0560 100644 --- a/vendor/google.golang.org/grpc/credentials/tls.go +++ b/vendor/google.golang.org/grpc/credentials/tls.go @@ -230,4 +230,7 @@ var cipherSuiteLookup = map[uint16]string{ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256", + tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", + tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", } diff --git a/vendor/google.golang.org/grpc/go.mod b/vendor/google.golang.org/grpc/go.mod index 2f2cf1eb766..022cc9828fe 100644 --- a/vendor/google.golang.org/grpc/go.mod +++ b/vendor/google.golang.org/grpc/go.mod @@ -1,11 +1,11 @@ module google.golang.org/grpc -go 1.11 +go 1.14 require ( - github.com/cespare/xxhash v1.1.0 + github.com/cespare/xxhash/v2 v2.1.1 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 - github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 + github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.0 diff --git a/vendor/google.golang.org/grpc/go.sum b/vendor/google.golang.org/grpc/go.sum index 372b4ea3d20..6e7ae0db2b3 100644 --- a/vendor/google.golang.org/grpc/go.sum +++ b/vendor/google.golang.org/grpc/go.sum @@ -2,27 +2,25 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158 h1:CevA8fI91PAnP8vpnXuB8ZYAZ5wqY86nAbxfgK8tWO4= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 h1:fP+fF0up6oPY49OrjPrhIJ8yQfdIM85NXMLkMg1EXVs= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -54,11 +52,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -122,7 +119,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/google.golang.org/grpc/install_gae.sh b/vendor/google.golang.org/grpc/install_gae.sh deleted file mode 100644 index 15ff9facdd7..00000000000 --- a/vendor/google.golang.org/grpc/install_gae.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -TMP=$(mktemp -d /tmp/sdk.XXX) \ -&& curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip" \ -&& unzip -q $TMP.zip -d $TMP \ -&& export PATH="$PATH:$TMP/go_appengine" \ No newline at end of file diff --git a/vendor/google.golang.org/grpc/internal/channelz/funcs.go b/vendor/google.golang.org/grpc/internal/channelz/funcs.go index f7314139303..6d5760d9514 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/funcs.go +++ b/vendor/google.golang.org/grpc/internal/channelz/funcs.go @@ -630,7 +630,7 @@ func (c *channelMap) GetServerSockets(id int64, startID int64, maxResults int64) if count == 0 { end = true } - var s []*SocketMetric + s := make([]*SocketMetric, 0, len(sks)) for _, ns := range sks { sm := &SocketMetric{} sm.SocketData = ns.s.ChannelzMetric() diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_linux.go b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go index 692dd618177..1b1c4cce34a 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types_linux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go index 19c2fc521dc..8b06eed1ab8 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go @@ -1,4 +1,5 @@ -// +build !linux appengine +//go:build !linux +// +build !linux /* * @@ -37,6 +38,6 @@ type SocketOptionData struct { // Windows OS doesn't support Socket Option func (s *SocketOptionData) Getsockopt(fd uintptr) { once.Do(func() { - logger.Warning("Channelz: socket options are not supported on non-linux os and appengine.") + logger.Warning("Channelz: socket options are not supported on non-linux environments") }) } diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_linux.go b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go index fdf409d55de..8d194e44e1d 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/util_linux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go @@ -1,5 +1,3 @@ -// +build linux,!appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go index 8864a081116..837ddc40240 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go @@ -1,4 +1,5 @@ -// +build !linux appengine +//go:build !linux +// +build !linux /* * diff --git a/vendor/google.golang.org/grpc/internal/credentials/spiffe.go b/vendor/google.golang.org/grpc/internal/credentials/spiffe.go index be70b6cdfc3..25ade623058 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/spiffe.go +++ b/vendor/google.golang.org/grpc/internal/credentials/spiffe.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2020 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/credentials/spiffe_appengine.go b/vendor/google.golang.org/grpc/internal/credentials/spiffe_appengine.go deleted file mode 100644 index af6f5771976..00000000000 --- a/vendor/google.golang.org/grpc/internal/credentials/spiffe_appengine.go +++ /dev/null @@ -1,31 +0,0 @@ -// +build appengine - -/* - * - * Copyright 2020 gRPC authors. - * - * 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. - * - */ - -package credentials - -import ( - "crypto/tls" - "net/url" -) - -// SPIFFEIDFromState is a no-op for appengine builds. -func SPIFFEIDFromState(state tls.ConnectionState) *url.URL { - return nil -} diff --git a/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go b/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go index f499a614c20..2919632d657 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go +++ b/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/credentials/syscallconn_appengine.go b/vendor/google.golang.org/grpc/internal/credentials/syscallconn_appengine.go deleted file mode 100644 index a6144cd661c..00000000000 --- a/vendor/google.golang.org/grpc/internal/credentials/syscallconn_appengine.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build appengine - -/* - * - * Copyright 2018 gRPC authors. - * - * 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. - * - */ - -package credentials - -import ( - "net" -) - -// WrapSyscallConn returns newConn on appengine. -func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { - return newConn -} diff --git a/vendor/google.golang.org/grpc/internal/credentials/util.go b/vendor/google.golang.org/grpc/internal/credentials/util.go index 55664fa46b8..f792fd22caf 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/util.go +++ b/vendor/google.golang.org/grpc/internal/credentials/util.go @@ -18,7 +18,9 @@ package credentials -import "crypto/tls" +import ( + "crypto/tls" +) const alpnProtoStrH2 = "h2" diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 73931a94bca..e766ac04af2 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -22,6 +22,8 @@ package envconfig import ( "os" "strings" + + xdsenv "google.golang.org/grpc/internal/xds/env" ) const ( @@ -31,8 +33,8 @@ const ( ) var ( - // Retry is set if retry is explicitly enabled via "GRPC_GO_RETRY=on". - Retry = strings.EqualFold(os.Getenv(retryStr), "on") + // Retry is set if retry is explicitly enabled via "GRPC_GO_RETRY=on" or if XDS retry support is enabled. + Retry = strings.EqualFold(os.Getenv(retryStr), "on") || xdsenv.RetrySupport // TXTErrIgnore is set if TXT errors should be ignored ("GRPC_GO_IGNORE_TXT_ERRORS" is not "false"). TXTErrIgnore = !strings.EqualFold(os.Getenv(txtErrIgnoreStr), "false") ) diff --git a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go index 5e7f36703d4..be7e13d5859 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go +++ b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go @@ -117,9 +117,12 @@ type ClientInterceptor interface { NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error) } -// ServerInterceptor is unimplementable; do not use. +// ServerInterceptor is an interceptor for incoming RPC's on gRPC server side. type ServerInterceptor interface { - notDefined() + // AllowRPC checks if an incoming RPC is allowed to proceed based on + // information about connection RPC was received on, and HTTP Headers. This + // information will be piped into context. + AllowRPC(ctx context.Context) error // TODO: Make this a real interceptor for filters such as rate limiting. } type csKeyType string diff --git a/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go b/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go index 03825bbe7b5..75301c51491 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go +++ b/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go @@ -277,18 +277,13 @@ func (d *dnsResolver) lookupSRV() ([]resolver.Address, error) { return newAddrs, nil } -var filterError = func(err error) error { +func handleDNSError(err error, lookupType string) error { if dnsErr, ok := err.(*net.DNSError); ok && !dnsErr.IsTimeout && !dnsErr.IsTemporary { // Timeouts and temporary errors should be communicated to gRPC to // attempt another DNS query (with backoff). Other errors should be // suppressed (they may represent the absence of a TXT record). return nil } - return err -} - -func handleDNSError(err error, lookupType string) error { - err = filterError(err) if err != nil { err = fmt.Errorf("dns: %v record lookup error: %v", lookupType, err) logger.Info(err) @@ -323,12 +318,12 @@ func (d *dnsResolver) lookupTXT() *serviceconfig.ParseResult { } func (d *dnsResolver) lookupHost() ([]resolver.Address, error) { - var newAddrs []resolver.Address addrs, err := d.resolver.LookupHost(d.ctx, d.host) if err != nil { err = handleDNSError(err, "A") return nil, err } + newAddrs := make([]resolver.Address, 0, len(addrs)) for _, a := range addrs { ip, ok := formatIP(a) if !ok { diff --git a/vendor/google.golang.org/grpc/internal/resolver/dns/go113.go b/vendor/google.golang.org/grpc/internal/resolver/dns/go113.go deleted file mode 100644 index 8783a8cf821..00000000000 --- a/vendor/google.golang.org/grpc/internal/resolver/dns/go113.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build go1.13 - -/* - * - * Copyright 2019 gRPC authors. - * - * 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. - * - */ - -package dns - -import "net" - -func init() { - filterError = func(err error) error { - if dnsErr, ok := err.(*net.DNSError); ok && dnsErr.IsNotFound { - // The name does not exist; not an error. - return nil - } - return err - } -} diff --git a/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go b/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go index c0634d152c2..badbdbf597f 100644 --- a/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go +++ b/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go @@ -78,6 +78,7 @@ func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { return err } + var names []string for i, lbcfg := range ir { if len(lbcfg) != 1 { return fmt.Errorf("invalid loadBalancingConfig: entry %v does not contain exactly 1 policy/config pair: %q", i, lbcfg) @@ -92,6 +93,7 @@ func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { for name, jsonCfg = range lbcfg { } + names = append(names, name) builder := balancer.Get(name) if builder == nil { // If the balancer is not registered, move on to the next config. @@ -120,7 +122,7 @@ func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { // return. This means we had a loadBalancingConfig slice but did not // encounter a registered policy. The config is considered invalid in this // case. - return fmt.Errorf("invalid loadBalancingConfig: no supported policies found") + return fmt.Errorf("invalid loadBalancingConfig: no supported policies found in %v", names) } // MethodConfig defines the configuration recommended by the service providers for a diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go index 4b2964f2a1e..b3a72276dee 100644 --- a/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go index 7913ef1dbfb..999f52cd75b 100644 --- a/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go @@ -1,4 +1,5 @@ -// +build !linux appengine +//go:build !linux +// +build !linux /* * @@ -35,41 +36,41 @@ var logger = grpclog.Component("core") func log() { once.Do(func() { - logger.Info("CPU time info is unavailable on non-linux or appengine environment.") + logger.Info("CPU time info is unavailable on non-linux environments.") }) } -// GetCPUTime returns the how much CPU time has passed since the start of this process. -// It always returns 0 under non-linux or appengine environment. +// GetCPUTime returns the how much CPU time has passed since the start of this +// process. It always returns 0 under non-linux environments. func GetCPUTime() int64 { log() return 0 } -// Rusage is an empty struct under non-linux or appengine environment. +// Rusage is an empty struct under non-linux environments. type Rusage struct{} -// GetRusage is a no-op function under non-linux or appengine environment. +// GetRusage is a no-op function under non-linux environments. func GetRusage() *Rusage { log() return nil } // CPUTimeDiff returns the differences of user CPU time and system CPU time used -// between two Rusage structs. It a no-op function for non-linux or appengine environment. +// between two Rusage structs. It a no-op function for non-linux environments. func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { log() return 0, 0 } -// SetTCPUserTimeout is a no-op function under non-linux or appengine environments +// SetTCPUserTimeout is a no-op function under non-linux environments. func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { log() return nil } -// GetTCPUserTimeout is a no-op function under non-linux or appengine environments -// a negative return value indicates the operation is not supported +// GetTCPUserTimeout is a no-op function under non-linux environments. +// A negative return value indicates the operation is not supported func GetTCPUserTimeout(conn net.Conn) (int, error) { log() return -1, nil diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 0cd6da1e73f..75586307435 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -616,12 +616,22 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call return callAuthData, nil } -// NewStreamError wraps an error and reports additional information. +// NewStreamError wraps an error and reports additional information. Typically +// NewStream errors result in transparent retry, as they mean nothing went onto +// the wire. However, there are two notable exceptions: +// +// 1. If the stream headers violate the max header list size allowed by the +// server. In this case there is no reason to retry at all, as it is +// assumed the RPC would continue to fail on subsequent attempts. +// 2. If the credentials errored when requesting their headers. In this case, +// it's possible a retry can fix the problem, but indefinitely transparently +// retrying is not appropriate as it is likely the credentials, if they can +// eventually succeed, would need I/O to do so. type NewStreamError struct { Err error - DoNotRetry bool - PerformedIO bool + DoNotRetry bool + DoNotTransparentRetry bool } func (e NewStreamError) Error() string { @@ -631,24 +641,10 @@ func (e NewStreamError) Error() string { // NewStream creates a stream and registers it into the transport as "active" // streams. All non-nil errors returned will be *NewStreamError. func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) { - defer func() { - if err != nil { - nse, ok := err.(*NewStreamError) - if !ok { - nse = &NewStreamError{Err: err} - } - if len(t.perRPCCreds) > 0 || callHdr.Creds != nil { - // We may have performed I/O in the per-RPC creds callback, so do not - // allow transparent retry. - nse.PerformedIO = true - } - err = nse - } - }() ctx = peer.NewContext(ctx, t.getPeer()) headerFields, err := t.createHeaderFields(ctx, callHdr) if err != nil { - return nil, err + return nil, &NewStreamError{Err: err, DoNotTransparentRetry: true} } s := t.newStream(ctx, callHdr) cleanup := func(err error) { @@ -748,7 +744,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea return true }, hdr) if err != nil { - return nil, err + return nil, &NewStreamError{Err: err} } if success { break @@ -759,12 +755,12 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea firstTry = false select { case <-ch: - case <-s.ctx.Done(): - return nil, ContextErr(s.ctx.Err()) + case <-ctx.Done(): + return nil, &NewStreamError{Err: ContextErr(ctx.Err())} case <-t.goAway: - return nil, errStreamDrain + return nil, &NewStreamError{Err: errStreamDrain} case <-t.ctx.Done(): - return nil, ErrConnClosing + return nil, &NewStreamError{Err: ErrConnClosing} } } if t.statsHandler != nil { diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index e3799d50aa7..19c13e041d3 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -133,6 +133,22 @@ type http2Server struct { // underlying conn gets closed before the client preface could be read, it // returns a nil transport and a nil error. func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { + var authInfo credentials.AuthInfo + rawConn := conn + if config.Credentials != nil { + var err error + conn, authInfo, err = config.Credentials.ServerHandshake(rawConn) + if err != nil { + // ErrConnDispatched means that the connection was dispatched away + // from gRPC; those connections should be left open. io.EOF means + // the connection was closed before handshaking completed, which can + // happen naturally from probers. Return these errors directly. + if err == credentials.ErrConnDispatched || err == io.EOF { + return nil, err + } + return nil, connectionErrorf(false, err, "ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err) + } + } writeBufSize := config.WriteBufferSize readBufSize := config.ReadBufferSize maxHeaderListSize := defaultServerMaxHeaderListSize @@ -215,14 +231,15 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, if kep.MinTime == 0 { kep.MinTime = defaultKeepalivePolicyMinTime } + done := make(chan struct{}) t := &http2Server{ - ctx: context.Background(), + ctx: setConnection(context.Background(), rawConn), done: done, conn: conn, remoteAddr: conn.RemoteAddr(), localAddr: conn.LocalAddr(), - authInfo: config.AuthInfo, + authInfo: authInfo, framer: framer, readerDone: make(chan struct{}), writerDone: make(chan struct{}), @@ -1345,3 +1362,18 @@ func getJitter(v time.Duration) time.Duration { j := grpcrand.Int63n(2*r) - r return time.Duration(j) } + +type connectionKey struct{} + +// GetConnection gets the connection from the context. +func GetConnection(ctx context.Context) net.Conn { + conn, _ := ctx.Value(connectionKey{}).(net.Conn) + return conn +} + +// SetConnection adds the connection to the context to be able to get +// information about the destination ip and port for an incoming RPC. This also +// allows any unary or streaming interceptors to see the connection. +func setConnection(ctx context.Context, conn net.Conn) context.Context { + return context.WithValue(ctx, connectionKey{}, conn) +} diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index 14198126457..d3bf65b2bdf 100644 --- a/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -30,6 +30,7 @@ import ( "net" "sync" "sync/atomic" + "time" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -518,7 +519,8 @@ const ( // ServerConfig consists of all the configurations to establish a server transport. type ServerConfig struct { MaxStreams uint32 - AuthInfo credentials.AuthInfo + ConnectionTimeout time.Duration + Credentials credentials.TransportCredentials InTapHandle tap.ServerInHandle StatsHandler stats.Handler KeepaliveParams keepalive.ServerParameters diff --git a/vendor/google.golang.org/grpc/internal/xds/env/env.go b/vendor/google.golang.org/grpc/internal/xds/env/env.go new file mode 100644 index 00000000000..b171ac91f17 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/xds/env/env.go @@ -0,0 +1,95 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * 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. + * + */ + +// Package env acts a single source of definition for all environment variables +// related to the xDS implementation in gRPC. +package env + +import ( + "os" + "strings" +) + +const ( + // BootstrapFileNameEnv is the env variable to set bootstrap file name. + // Do not use this and read from env directly. Its value is read and kept in + // variable BootstrapFileName. + // + // When both bootstrap FileName and FileContent are set, FileName is used. + BootstrapFileNameEnv = "GRPC_XDS_BOOTSTRAP" + // BootstrapFileContentEnv is the env variable to set bootstrapp file + // content. Do not use this and read from env directly. Its value is read + // and kept in variable BootstrapFileName. + // + // When both bootstrap FileName and FileContent are set, FileName is used. + BootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG" + + ringHashSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH" + clientSideSecuritySupportEnv = "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT" + aggregateAndDNSSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER" + retrySupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_RETRY" + rbacSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_RBAC" + + c2pResolverSupportEnv = "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER" + c2pResolverTestOnlyTrafficDirectorURIEnv = "GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI" +) + +var ( + // BootstrapFileName holds the name of the file which contains xDS bootstrap + // configuration. Users can specify the location of the bootstrap file by + // setting the environment variable "GRPC_XDS_BOOTSTRAP". + // + // When both bootstrap FileName and FileContent are set, FileName is used. + BootstrapFileName = os.Getenv(BootstrapFileNameEnv) + // BootstrapFileContent holds the content of the xDS bootstrap + // configuration. Users can specify the bootstrap config by + // setting the environment variable "GRPC_XDS_BOOTSTRAP_CONFIG". + // + // When both bootstrap FileName and FileContent are set, FileName is used. + BootstrapFileContent = os.Getenv(BootstrapFileContentEnv) + // RingHashSupport indicates whether ring hash support is enabled, which can + // be disabled by setting the environment variable + // "GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH" to "false". + RingHashSupport = !strings.EqualFold(os.Getenv(ringHashSupportEnv), "false") + // ClientSideSecuritySupport is used to control processing of security + // configuration on the client-side. + // + // Note that there is no env var protection for the server-side because we + // have a brand new API on the server-side and users explicitly need to use + // the new API to get security integration on the server. + ClientSideSecuritySupport = !strings.EqualFold(os.Getenv(clientSideSecuritySupportEnv), "false") + // AggregateAndDNSSupportEnv indicates whether processing of aggregated + // cluster and DNS cluster is enabled, which can be enabled by setting the + // environment variable + // "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER" to + // "true". + AggregateAndDNSSupportEnv = strings.EqualFold(os.Getenv(aggregateAndDNSSupportEnv), "true") + + // RetrySupport indicates whether xDS retry is enabled. + RetrySupport = !strings.EqualFold(os.Getenv(retrySupportEnv), "false") + + // RBACSupport indicates whether xDS configured RBAC HTTP Filter is enabled. + RBACSupport = strings.EqualFold(os.Getenv(rbacSupportEnv), "true") + + // C2PResolverSupport indicates whether support for C2P resolver is enabled. + // This can be enabled by setting the environment variable + // "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER" to "true". + C2PResolverSupport = strings.EqualFold(os.Getenv(c2pResolverSupportEnv), "true") + // C2PResolverTestOnlyTrafficDirectorURI is the TD URI for testing. + C2PResolverTestOnlyTrafficDirectorURI = os.Getenv(c2pResolverTestOnlyTrafficDirectorURIEnv) +) diff --git a/vendor/google.golang.org/grpc/pickfirst.go b/vendor/google.golang.org/grpc/pickfirst.go index b858c2a5e63..f194d14a081 100644 --- a/vendor/google.golang.org/grpc/pickfirst.go +++ b/vendor/google.golang.org/grpc/pickfirst.go @@ -107,10 +107,12 @@ func (b *pickfirstBalancer) UpdateSubConnState(sc balancer.SubConn, s balancer.S } switch s.ConnectivityState { - case connectivity.Ready, connectivity.Idle: + case connectivity.Ready: b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &picker{result: balancer.PickResult{SubConn: sc}}}) case connectivity.Connecting: b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &picker{err: balancer.ErrNoSubConnAvailable}}) + case connectivity.Idle: + b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &idlePicker{sc: sc}}) case connectivity.TransientFailure: b.cc.UpdateState(balancer.State{ ConnectivityState: s.ConnectivityState, @@ -122,6 +124,12 @@ func (b *pickfirstBalancer) UpdateSubConnState(sc balancer.SubConn, s balancer.S func (b *pickfirstBalancer) Close() { } +func (b *pickfirstBalancer) ExitIdle() { + if b.state == connectivity.Idle { + b.sc.Connect() + } +} + type picker struct { result balancer.PickResult err error @@ -131,6 +139,17 @@ func (p *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { return p.result, p.err } +// idlePicker is used when the SubConn is IDLE and kicks the SubConn into +// CONNECTING when Pick is called. +type idlePicker struct { + sc balancer.SubConn +} + +func (i *idlePicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { + i.sc.Connect() + return balancer.PickResult{}, balancer.ErrNoSubConnAvailable +} + func init() { balancer.Register(newPickfirstBuilder()) } diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 0251f48daf1..557f29559de 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -710,13 +710,6 @@ func (s *Server) GetServiceInfo() map[string]ServiceInfo { // the server being stopped. var ErrServerStopped = errors.New("grpc: the server has been stopped") -func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { - if s.opts.creds == nil { - return rawConn, nil, nil - } - return s.opts.creds.ServerHandshake(rawConn) -} - type listenSocket struct { net.Listener channelzID int64 @@ -839,35 +832,14 @@ func (s *Server) handleRawConn(lisAddr string, rawConn net.Conn) { return } rawConn.SetDeadline(time.Now().Add(s.opts.connectionTimeout)) - conn, authInfo, err := s.useTransportAuthenticator(rawConn) - if err != nil { - // ErrConnDispatched means that the connection was dispatched away from - // gRPC; those connections should be left open. - if err != credentials.ErrConnDispatched { - // In deployments where a gRPC server runs behind a cloud load - // balancer which performs regular TCP level health checks, the - // connection is closed immediately by the latter. Skipping the - // error here will help reduce log clutter. - if err != io.EOF { - s.mu.Lock() - s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err) - s.mu.Unlock() - channelz.Warningf(logger, s.channelzID, "grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err) - } - rawConn.Close() - } - rawConn.SetDeadline(time.Time{}) - return - } // Finish handshaking (HTTP2) - st := s.newHTTP2Transport(conn, authInfo) + st := s.newHTTP2Transport(rawConn) + rawConn.SetDeadline(time.Time{}) if st == nil { - conn.Close() return } - rawConn.SetDeadline(time.Time{}) if !s.addConn(lisAddr, st) { return } @@ -888,10 +860,11 @@ func (s *Server) drainServerTransports(addr string) { // newHTTP2Transport sets up a http/2 transport (using the // gRPC http2 server transport in transport/http2_server.go). -func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) transport.ServerTransport { +func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport { config := &transport.ServerConfig{ MaxStreams: s.opts.maxConcurrentStreams, - AuthInfo: authInfo, + ConnectionTimeout: s.opts.connectionTimeout, + Credentials: s.opts.creds, InTapHandle: s.opts.inTapHandle, StatsHandler: s.opts.statsHandler, KeepaliveParams: s.opts.keepaliveParams, @@ -909,8 +882,17 @@ func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) tr s.mu.Lock() s.errorf("NewServerTransport(%q) failed: %v", c.RemoteAddr(), err) s.mu.Unlock() - c.Close() - channelz.Warning(logger, s.channelzID, "grpc: Server.Serve failed to create ServerTransport: ", err) + // ErrConnDispatched means that the connection was dispatched away from + // gRPC; those connections should be left open. + if err != credentials.ErrConnDispatched { + c.Close() + } + // Don't log on ErrConnDispatched and io.EOF to prevent log spam. + if err != credentials.ErrConnDispatched { + if err != io.EOF { + channelz.Warning(logger, s.channelzID, "grpc: Server.Serve failed to create ServerTransport: ", err) + } + } return nil } diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go index a5ebeeb6932..0285dcc6a26 100644 --- a/vendor/google.golang.org/grpc/stats/stats.go +++ b/vendor/google.golang.org/grpc/stats/stats.go @@ -36,12 +36,12 @@ type RPCStats interface { IsClient() bool } -// Begin contains stats when an RPC begins. +// Begin contains stats when an RPC attempt begins. // FailFast is only valid if this Begin is from client side. type Begin struct { // Client is true if this Begin is from client side. Client bool - // BeginTime is the time when the RPC begins. + // BeginTime is the time when the RPC attempt begins. BeginTime time.Time // FailFast indicates if this RPC is failfast. FailFast bool @@ -49,6 +49,9 @@ type Begin struct { IsClientStream bool // IsServerStream indicates whether the RPC is a server streaming RPC. IsServerStream bool + // IsTransparentRetryAttempt indicates whether this attempt was initiated + // due to transparently retrying a previous attempt. + IsTransparentRetryAttempt bool } // IsClient indicates if the stats information is from client side. diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index e224af12d21..625d47b34e5 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -274,35 +274,6 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client if c.creds != nil { callHdr.Creds = c.creds } - var trInfo *traceInfo - if EnableTracing { - trInfo = &traceInfo{ - tr: trace.New("grpc.Sent."+methodFamily(method), method), - firstLine: firstLine{ - client: true, - }, - } - if deadline, ok := ctx.Deadline(); ok { - trInfo.firstLine.deadline = time.Until(deadline) - } - trInfo.tr.LazyLog(&trInfo.firstLine, false) - ctx = trace.NewContext(ctx, trInfo.tr) - } - ctx = newContextWithRPCInfo(ctx, c.failFast, c.codec, cp, comp) - sh := cc.dopts.copts.StatsHandler - var beginTime time.Time - if sh != nil { - ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: c.failFast}) - beginTime = time.Now() - begin := &stats.Begin{ - Client: true, - BeginTime: beginTime, - FailFast: c.failFast, - IsClientStream: desc.ClientStreams, - IsServerStream: desc.ServerStreams, - } - sh.HandleRPC(ctx, begin) - } cs := &clientStream{ callHdr: callHdr, @@ -316,7 +287,6 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client cp: cp, comp: comp, cancel: cancel, - beginTime: beginTime, firstAttempt: true, onCommit: onCommit, } @@ -325,9 +295,7 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client } cs.binlog = binarylog.GetMethodLogger(method) - // Only this initial attempt has stats/tracing. - // TODO(dfawley): move to newAttempt when per-attempt stats are implemented. - if err := cs.newAttemptLocked(sh, trInfo); err != nil { + if err := cs.newAttemptLocked(false /* isTransparent */); err != nil { cs.finish(err) return nil, err } @@ -375,8 +343,43 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client // newAttemptLocked creates a new attempt with a transport. // If it succeeds, then it replaces clientStream's attempt with this new attempt. -func (cs *clientStream) newAttemptLocked(sh stats.Handler, trInfo *traceInfo) (retErr error) { +func (cs *clientStream) newAttemptLocked(isTransparent bool) (retErr error) { + ctx := newContextWithRPCInfo(cs.ctx, cs.callInfo.failFast, cs.callInfo.codec, cs.cp, cs.comp) + method := cs.callHdr.Method + sh := cs.cc.dopts.copts.StatsHandler + var beginTime time.Time + if sh != nil { + ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: cs.callInfo.failFast}) + beginTime = time.Now() + begin := &stats.Begin{ + Client: true, + BeginTime: beginTime, + FailFast: cs.callInfo.failFast, + IsClientStream: cs.desc.ClientStreams, + IsServerStream: cs.desc.ServerStreams, + IsTransparentRetryAttempt: isTransparent, + } + sh.HandleRPC(ctx, begin) + } + + var trInfo *traceInfo + if EnableTracing { + trInfo = &traceInfo{ + tr: trace.New("grpc.Sent."+methodFamily(method), method), + firstLine: firstLine{ + client: true, + }, + } + if deadline, ok := ctx.Deadline(); ok { + trInfo.firstLine.deadline = time.Until(deadline) + } + trInfo.tr.LazyLog(&trInfo.firstLine, false) + ctx = trace.NewContext(ctx, trInfo.tr) + } + newAttempt := &csAttempt{ + ctx: ctx, + beginTime: beginTime, cs: cs, dc: cs.cc.dopts.dc, statsHandler: sh, @@ -391,15 +394,14 @@ func (cs *clientStream) newAttemptLocked(sh stats.Handler, trInfo *traceInfo) (r } }() - if err := cs.ctx.Err(); err != nil { + if err := ctx.Err(); err != nil { return toRPCErr(err) } - ctx := cs.ctx if cs.cc.parsedTarget.Scheme == "xds" { // Add extra metadata (metadata that will be added by transport) to context // so the balancer can see them. - ctx = grpcutil.WithExtraMetadata(cs.ctx, metadata.Pairs( + ctx = grpcutil.WithExtraMetadata(ctx, metadata.Pairs( "content-type", grpcutil.ContentType(cs.callHdr.ContentSubtype), )) } @@ -419,7 +421,7 @@ func (cs *clientStream) newAttemptLocked(sh stats.Handler, trInfo *traceInfo) (r func (a *csAttempt) newStream() error { cs := a.cs cs.callHdr.PreviousAttempts = cs.numRetries - s, err := a.t.NewStream(cs.ctx, cs.callHdr) + s, err := a.t.NewStream(a.ctx, cs.callHdr) if err != nil { // Return without converting to an RPC error so retry code can // inspect. @@ -444,8 +446,7 @@ type clientStream struct { cancel context.CancelFunc // cancels all attempts - sentLast bool // sent an end stream - beginTime time.Time + sentLast bool // sent an end stream methodConfig *MethodConfig @@ -485,6 +486,7 @@ type clientStream struct { // csAttempt implements a single transport stream attempt within a // clientStream. type csAttempt struct { + ctx context.Context cs *clientStream t transport.ClientTransport s *transport.Stream @@ -503,6 +505,7 @@ type csAttempt struct { trInfo *traceInfo statsHandler stats.Handler + beginTime time.Time } func (cs *clientStream) commitAttemptLocked() { @@ -520,15 +523,16 @@ func (cs *clientStream) commitAttempt() { } // shouldRetry returns nil if the RPC should be retried; otherwise it returns -// the error that should be returned by the operation. -func (cs *clientStream) shouldRetry(err error) error { +// the error that should be returned by the operation. If the RPC should be +// retried, the bool indicates whether it is being retried transparently. +func (cs *clientStream) shouldRetry(err error) (bool, error) { if cs.attempt.s == nil { // Error from NewClientStream. nse, ok := err.(*transport.NewStreamError) if !ok { // Unexpected, but assume no I/O was performed and the RPC is not // fatal, so retry indefinitely. - return nil + return true, nil } // Unwrap and convert error. @@ -537,19 +541,19 @@ func (cs *clientStream) shouldRetry(err error) error { // Never retry DoNotRetry errors, which indicate the RPC should not be // retried due to max header list size violation, etc. if nse.DoNotRetry { - return err + return false, err } // In the event of a non-IO operation error from NewStream, we never // attempted to write anything to the wire, so we can retry // indefinitely. - if !nse.PerformedIO { - return nil + if !nse.DoNotTransparentRetry { + return true, nil } } if cs.finished || cs.committed { // RPC is finished or committed; cannot retry. - return err + return false, err } // Wait for the trailers. unprocessed := false @@ -559,17 +563,17 @@ func (cs *clientStream) shouldRetry(err error) error { } if cs.firstAttempt && unprocessed { // First attempt, stream unprocessed: transparently retry. - return nil + return true, nil } if cs.cc.dopts.disableRetry { - return err + return false, err } pushback := 0 hasPushback := false if cs.attempt.s != nil { if !cs.attempt.s.TrailersOnly() { - return err + return false, err } // TODO(retry): Move down if the spec changes to not check server pushback @@ -580,13 +584,13 @@ func (cs *clientStream) shouldRetry(err error) error { if pushback, e = strconv.Atoi(sps[0]); e != nil || pushback < 0 { channelz.Infof(logger, cs.cc.channelzID, "Server retry pushback specified to abort (%q).", sps[0]) cs.retryThrottler.throttle() // This counts as a failure for throttling. - return err + return false, err } hasPushback = true } else if len(sps) > 1 { channelz.Warningf(logger, cs.cc.channelzID, "Server retry pushback specified multiple values (%q); not retrying.", sps) cs.retryThrottler.throttle() // This counts as a failure for throttling. - return err + return false, err } } @@ -599,16 +603,16 @@ func (cs *clientStream) shouldRetry(err error) error { rp := cs.methodConfig.RetryPolicy if rp == nil || !rp.RetryableStatusCodes[code] { - return err + return false, err } // Note: the ordering here is important; we count this as a failure // only if the code matched a retryable code. if cs.retryThrottler.throttle() { - return err + return false, err } if cs.numRetries+1 >= rp.MaxAttempts { - return err + return false, err } var dur time.Duration @@ -631,10 +635,10 @@ func (cs *clientStream) shouldRetry(err error) error { select { case <-t.C: cs.numRetries++ - return nil + return false, nil case <-cs.ctx.Done(): t.Stop() - return status.FromContextError(cs.ctx.Err()).Err() + return false, status.FromContextError(cs.ctx.Err()).Err() } } @@ -642,12 +646,13 @@ func (cs *clientStream) shouldRetry(err error) error { func (cs *clientStream) retryLocked(lastErr error) error { for { cs.attempt.finish(toRPCErr(lastErr)) - if err := cs.shouldRetry(lastErr); err != nil { + isTransparent, err := cs.shouldRetry(lastErr) + if err != nil { cs.commitAttemptLocked() return err } cs.firstAttempt = false - if err := cs.newAttemptLocked(nil, nil); err != nil { + if err := cs.newAttemptLocked(isTransparent); err != nil { return err } if lastErr = cs.replayBufferLocked(); lastErr == nil { @@ -937,7 +942,7 @@ func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error { return io.EOF } if a.statsHandler != nil { - a.statsHandler.HandleRPC(cs.ctx, outPayload(true, m, data, payld, time.Now())) + a.statsHandler.HandleRPC(a.ctx, outPayload(true, m, data, payld, time.Now())) } if channelz.IsOn() { a.t.IncrMsgSent() @@ -985,7 +990,7 @@ func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { a.mu.Unlock() } if a.statsHandler != nil { - a.statsHandler.HandleRPC(cs.ctx, &stats.InPayload{ + a.statsHandler.HandleRPC(a.ctx, &stats.InPayload{ Client: true, RecvTime: time.Now(), Payload: m, @@ -1047,12 +1052,12 @@ func (a *csAttempt) finish(err error) { if a.statsHandler != nil { end := &stats.End{ Client: true, - BeginTime: a.cs.beginTime, + BeginTime: a.beginTime, EndTime: time.Now(), Trailer: tr, Error: err, } - a.statsHandler.HandleRPC(a.cs.ctx, end) + a.statsHandler.HandleRPC(a.ctx, end) } if a.trInfo != nil && a.trInfo.tr != nil { if err == nil { diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index e3510e10f19..48594bc246d 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.40.0" +const Version = "1.41.0" diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh index 5eaa8b05d6d..d923187a7b3 100644 --- a/vendor/google.golang.org/grpc/vet.sh +++ b/vendor/google.golang.org/grpc/vet.sh @@ -89,10 +89,6 @@ not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go" # - Ensure all xds proto imports are renamed to *pb or *grpc. git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "' -# - Check imports that are illegal in appengine (until Go 1.11). -# TODO: Remove when we drop Go 1.10 support -go list -f {{.Dir}} ./... | xargs go run test/go_vet/vet.go - misspell -error . # - Check that generated proto files are up to date. diff --git a/vendor/k8s.io/cli-runtime/pkg/genericclioptions/command_headers.go b/vendor/k8s.io/cli-runtime/pkg/genericclioptions/command_headers.go index 8f9e774752a..04889da094a 100644 --- a/vendor/k8s.io/cli-runtime/pkg/genericclioptions/command_headers.go +++ b/vendor/k8s.io/cli-runtime/pkg/genericclioptions/command_headers.go @@ -25,8 +25,8 @@ import ( ) const ( - kubectlCommandHeader = "X-Kubectl-Command" - kubectlSessionHeader = "X-Kubectl-Session" + kubectlCommandHeader = "Kubectl-Command" + kubectlSessionHeader = "Kubectl-Session" ) // CommandHeaderRoundTripper adds a layer around the standard @@ -48,8 +48,8 @@ func (c *CommandHeaderRoundTripper) RoundTrip(req *http.Request) (*http.Response return c.Delegate.RoundTrip(req) } -// ParseCommandHeaders fills in a map of X-Headers into the CommandHeaderRoundTripper. These -// headers are then filled into each request. For details on X-Headers see: +// ParseCommandHeaders fills in a map of custom headers into the CommandHeaderRoundTripper. These +// headers are then filled into each request. For details on the custom headers see: // https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/859-kubectl-headers // Each call overwrites the previously parsed command headers (not additive). // TODO(seans3): Parse/add flags removing PII from flag values. diff --git a/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go b/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go index 095a7b519e3..a5f307de56c 100644 --- a/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go +++ b/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go @@ -93,6 +93,7 @@ func (f *RecordFlags) AddFlags(cmd *cobra.Command) { if f.Record != nil { cmd.Flags().BoolVar(f.Record, "record", *f.Record, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.") + cmd.Flags().MarkDeprecated("record", "--record will be removed in the future") } } diff --git a/vendor/k8s.io/cli-runtime/pkg/printers/tableprinter.go b/vendor/k8s.io/cli-runtime/pkg/printers/tableprinter.go index 048cb66a2ba..c32e5fdf6a5 100644 --- a/vendor/k8s.io/cli-runtime/pkg/printers/tableprinter.go +++ b/vendor/k8s.io/cli-runtime/pkg/printers/tableprinter.go @@ -208,7 +208,23 @@ func printTable(table *metav1.Table, output io.Writer, options PrintOptions) err fmt.Fprint(output, "\t") } if cell != nil { - fmt.Fprint(output, cell) + switch val := cell.(type) { + case string: + print := val + truncated := false + // truncate at newlines + newline := strings.Index(print, "\n") + if newline >= 0 { + truncated = true + print = print[:newline] + } + fmt.Fprint(output, print) + if truncated { + fmt.Fprint(output, "...") + } + default: + fmt.Fprint(output, val) + } } } fmt.Fprintln(output) diff --git a/vendor/k8s.io/cli-runtime/pkg/resource/builder.go b/vendor/k8s.io/cli-runtime/pkg/resource/builder.go index a8ebf6410c8..87922680ed2 100644 --- a/vendor/k8s.io/cli-runtime/pkg/resource/builder.go +++ b/vendor/k8s.io/cli-runtime/pkg/resource/builder.go @@ -38,7 +38,7 @@ import ( "k8s.io/client-go/discovery" "k8s.io/client-go/rest" "k8s.io/client-go/restmapper" - "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/kyaml/filesys" ) var FileExtensions = []string{".json", ".yaml", ".yml"} @@ -72,9 +72,10 @@ type Builder struct { errs []error - paths []Visitor - stream bool - dir bool + paths []Visitor + stream bool + stdinInUse bool + dir bool labelSelector *string fieldSelector *string @@ -121,6 +122,8 @@ Example resource specifications include: '-f rsrc.yaml' '--filename=rsrc.json'`) +var StdinMultiUseError = errors.New("standard input cannot be used for multiple arguments") + // TODO: expand this to include other errors. func IsUsageError(err error) bool { if err == nil { @@ -362,13 +365,31 @@ func (b *Builder) URL(httpAttemptCount int, urls ...*url.URL) *Builder { // Stdin will read objects from the standard input. If ContinueOnError() is set // prior to this method being called, objects in the stream that are unrecognized -// will be ignored (but logged at V(2)). +// will be ignored (but logged at V(2)). If StdinInUse() is set prior to this method +// being called, an error will be recorded as there are multiple entities trying to use +// the single standard input stream. func (b *Builder) Stdin() *Builder { b.stream = true + if b.stdinInUse { + b.errs = append(b.errs, StdinMultiUseError) + } + b.stdinInUse = true b.paths = append(b.paths, FileVisitorForSTDIN(b.mapper, b.schema)) return b } +// StdinInUse will mark standard input as in use by this Builder, and therefore standard +// input should not be used by another entity. If Stdin() is set prior to this method +// being called, an error will be recorded as there are multiple entities trying to use +// the single standard input stream. +func (b *Builder) StdinInUse() *Builder { + if b.stdinInUse { + b.errs = append(b.errs, StdinMultiUseError) + } + b.stdinInUse = true + return b +} + // Stream will read objects from the provided reader, and if an error occurs will // include the name string in the error message. If ContinueOnError() is set // prior to this method being called, objects in the stream that are unrecognized @@ -911,9 +932,9 @@ func (b *Builder) getClient(gv schema.GroupVersion) (RESTClient, error) { case b.fakeClientFn != nil: client, err = b.fakeClientFn(gv) case b.negotiatedSerializer != nil: - client, err = b.clientConfigFn.clientForGroupVersion(gv, b.negotiatedSerializer) + client, err = b.clientConfigFn.withStdinUnavailable(b.stdinInUse).clientForGroupVersion(gv, b.negotiatedSerializer) default: - client, err = b.clientConfigFn.unstructuredClientForGroupVersion(gv) + client, err = b.clientConfigFn.withStdinUnavailable(b.stdinInUse).unstructuredClientForGroupVersion(gv) } if err != nil { diff --git a/vendor/k8s.io/cli-runtime/pkg/resource/client.go b/vendor/k8s.io/cli-runtime/pkg/resource/client.go index 46380207f3e..cd52c304313 100644 --- a/vendor/k8s.io/cli-runtime/pkg/resource/client.go +++ b/vendor/k8s.io/cli-runtime/pkg/resource/client.go @@ -56,3 +56,14 @@ func (clientConfigFn ClientConfigFunc) unstructuredClientForGroupVersion(gv sche return rest.RESTClientFor(cfg) } + +func (clientConfigFn ClientConfigFunc) withStdinUnavailable(stdinUnavailable bool) ClientConfigFunc { + return func() (*rest.Config, error) { + cfg, err := clientConfigFn() + if stdinUnavailable && cfg != nil && cfg.ExecProvider != nil { + cfg.ExecProvider.StdinUnavailable = stdinUnavailable + cfg.ExecProvider.StdinUnavailableMessage = "used by stdin resource manifest reader" + } + return cfg, err + } +} diff --git a/vendor/k8s.io/cli-runtime/pkg/resource/crd_finder.go b/vendor/k8s.io/cli-runtime/pkg/resource/crd_finder.go index 5dab3e46df2..4694f7791a1 100644 --- a/vendor/k8s.io/cli-runtime/pkg/resource/crd_finder.go +++ b/vendor/k8s.io/cli-runtime/pkg/resource/crd_finder.go @@ -35,7 +35,7 @@ func CRDFromDynamic(client dynamic.Interface) CRDGetter { return func() ([]schema.GroupKind, error) { list, err := client.Resource(schema.GroupVersionResource{ Group: "apiextensions.k8s.io", - Version: "v1beta1", + Version: "v1", Resource: "customresourcedefinitions", }).List(context.TODO(), metav1.ListOptions{}) if err != nil { diff --git a/vendor/k8s.io/cli-runtime/pkg/resource/helper.go b/vendor/k8s.io/cli-runtime/pkg/resource/helper.go index 0132759d022..684802e8857 100644 --- a/vendor/k8s.io/cli-runtime/pkg/resource/helper.go +++ b/vendor/k8s.io/cli-runtime/pkg/resource/helper.go @@ -18,9 +18,12 @@ package resource import ( "context" + "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -90,6 +93,54 @@ func (m *Helper) List(namespace, apiVersion string, options *metav1.ListOptions) return req.Do(context.TODO()).Get() } +// FollowContinue handles the continue parameter returned by the API server when using list +// chunking. To take advantage of this, the initial ListOptions provided by the consumer +// should include a non-zero Limit parameter. +func FollowContinue(initialOpts *metav1.ListOptions, + listFunc func(metav1.ListOptions) (runtime.Object, error)) error { + opts := initialOpts + for { + list, err := listFunc(*opts) + if err != nil { + return err + } + nextContinueToken, _ := metadataAccessor.Continue(list) + if len(nextContinueToken) == 0 { + return nil + } + opts.Continue = nextContinueToken + } +} + +// EnhanceListError augments errors typically returned by List operations with additional context, +// making sure to retain the StatusError type when applicable. +func EnhanceListError(err error, opts metav1.ListOptions, subj string) error { + if apierrors.IsResourceExpired(err) { + return err + } + if apierrors.IsBadRequest(err) || apierrors.IsNotFound(err) { + if se, ok := err.(*apierrors.StatusError); ok { + // modify the message without hiding this is an API error + if len(opts.LabelSelector) == 0 && len(opts.FieldSelector) == 0 { + se.ErrStatus.Message = fmt.Sprintf("Unable to list %q: %v", subj, + se.ErrStatus.Message) + } else { + se.ErrStatus.Message = fmt.Sprintf( + "Unable to find %q that match label selector %q, field selector %q: %v", subj, + opts.LabelSelector, + opts.FieldSelector, se.ErrStatus.Message) + } + return se + } + if len(opts.LabelSelector) == 0 && len(opts.FieldSelector) == 0 { + return fmt.Errorf("Unable to list %q: %v", subj, err) + } + return fmt.Errorf("Unable to find %q that match label selector %q, field selector %q: %v", + subj, opts.LabelSelector, opts.FieldSelector, err) + } + return err +} + func (m *Helper) Watch(namespace, apiVersion string, options *metav1.ListOptions) (watch.Interface, error) { options.Watch = true return m.RESTClient.Get(). diff --git a/vendor/k8s.io/cli-runtime/pkg/resource/kustomizevisitor.go b/vendor/k8s.io/cli-runtime/pkg/resource/kustomizevisitor.go index 22c9a548d4b..164891b88d7 100644 --- a/vendor/k8s.io/cli-runtime/pkg/resource/kustomizevisitor.go +++ b/vendor/k8s.io/cli-runtime/pkg/resource/kustomizevisitor.go @@ -19,8 +19,8 @@ package resource import ( "bytes" - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/krusty" + "sigs.k8s.io/kustomize/kyaml/filesys" ) // KustomizeVisitor handles kustomization.yaml files. diff --git a/vendor/k8s.io/cli-runtime/pkg/resource/selector.go b/vendor/k8s.io/cli-runtime/pkg/resource/selector.go index d29dfc46c39..2a283d4e060 100644 --- a/vendor/k8s.io/cli-runtime/pkg/resource/selector.go +++ b/vendor/k8s.io/cli-runtime/pkg/resource/selector.go @@ -17,11 +17,9 @@ limitations under the License. package resource import ( - "fmt" - - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" ) @@ -49,41 +47,23 @@ func NewSelector(client RESTClient, mapping *meta.RESTMapping, namespace, labelS // Visit implements Visitor and uses request chunking by default. func (r *Selector) Visit(fn VisitorFunc) error { - var continueToken string - for { - list, err := NewHelper(r.Client, r.Mapping).List( + helper := NewHelper(r.Client, r.Mapping) + initialOpts := metav1.ListOptions{ + LabelSelector: r.LabelSelector, + FieldSelector: r.FieldSelector, + Limit: r.LimitChunks, + } + return FollowContinue(&initialOpts, func(options metav1.ListOptions) (runtime.Object, error) { + list, err := helper.List( r.Namespace, r.ResourceMapping().GroupVersionKind.GroupVersion().String(), - &metav1.ListOptions{ - LabelSelector: r.LabelSelector, - FieldSelector: r.FieldSelector, - Limit: r.LimitChunks, - Continue: continueToken, - }, + &options, ) if err != nil { - if errors.IsResourceExpired(err) { - return err - } - if errors.IsBadRequest(err) || errors.IsNotFound(err) { - if se, ok := err.(*errors.StatusError); ok { - // modify the message without hiding this is an API error - if len(r.LabelSelector) == 0 && len(r.FieldSelector) == 0 { - se.ErrStatus.Message = fmt.Sprintf("Unable to list %q: %v", r.Mapping.Resource, se.ErrStatus.Message) - } else { - se.ErrStatus.Message = fmt.Sprintf("Unable to find %q that match label selector %q, field selector %q: %v", r.Mapping.Resource, r.LabelSelector, r.FieldSelector, se.ErrStatus.Message) - } - return se - } - if len(r.LabelSelector) == 0 && len(r.FieldSelector) == 0 { - return fmt.Errorf("Unable to list %q: %v", r.Mapping.Resource, err) - } - return fmt.Errorf("Unable to find %q that match label selector %q, field selector %q: %v", r.Mapping.Resource, r.LabelSelector, r.FieldSelector, err) - } - return err + return nil, EnhanceListError(err, options, r.Mapping.Resource.String()) } resourceVersion, _ := metadataAccessor.ResourceVersion(list) - nextContinueToken, _ := metadataAccessor.Continue(list) + info := &Info{ Client: r.Client, Mapping: r.Mapping, @@ -95,13 +75,10 @@ func (r *Selector) Visit(fn VisitorFunc) error { } if err := fn(info, nil); err != nil { - return err + return nil, err } - if len(nextContinueToken) == 0 { - return nil - } - continueToken = nextContinueToken - } + return list, nil + }) } func (r *Selector) Watch(resourceVersion string) (watch.Interface, error) { diff --git a/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go b/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go index 8f74d66b8a6..1d86235402d 100644 --- a/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go +++ b/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go @@ -50,6 +50,7 @@ import ( const ( ApplyAnnotationsFlag = "save-config" DefaultErrorExitCode = 1 + DefaultChunkSize = 500 ) type debugError interface { @@ -455,12 +456,9 @@ func AddApplyAnnotationVarFlags(cmd *cobra.Command, applyAnnotation *bool) { cmd.Flags().BoolVar(applyAnnotation, ApplyAnnotationsFlag, *applyAnnotation, "If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.") } -// AddGeneratorFlags adds flags common to resource generation commands -// TODO: need to take a pass at other generator commands to use this set of flags -func AddGeneratorFlags(cmd *cobra.Command, defaultGenerator string) { - cmd.Flags().String("generator", defaultGenerator, "The name of the API generator to use.") - cmd.Flags().MarkDeprecated("generator", "has no effect and will be removed in the future.") - AddDryRunFlag(cmd) +func AddChunkSizeFlag(cmd *cobra.Command, value *int64) { + cmd.Flags().Int64Var(value, "chunk-size", *value, + "Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may change in the future.") } type ValidateOptions struct { diff --git a/vendor/k8s.io/kubectl/pkg/util/openapi/extensions.go b/vendor/k8s.io/kubectl/pkg/util/openapi/extensions.go index f1b5cdd4f27..13f88bc8208 100644 --- a/vendor/k8s.io/kubectl/pkg/util/openapi/extensions.go +++ b/vendor/k8s.io/kubectl/pkg/util/openapi/extensions.go @@ -16,7 +16,7 @@ limitations under the License. package openapi -import "github.com/go-openapi/spec" +import "k8s.io/kube-openapi/pkg/validation/spec" // PrintColumnsKey is the key that defines which columns should be printed const PrintColumnsKey = "x-kubernetes-print-columns" diff --git a/vendor/modules.txt b/vendor/modules.txt index 8e0da1300c3..8fb30e20571 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1889,3 +1889,4 @@ sigs.k8s.io/structured-merge-diff/v4/value sigs.k8s.io/yaml # github.com/openshift/api => github.com/openshift/api v0.0.0-20211014063134-be2a7fb8aa44 # github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 + diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/AnnotationsTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/AnnotationsTransformer.go index 68d351e1816..7064fa80c07 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/AnnotationsTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/AnnotationsTransformer.go @@ -27,16 +27,10 @@ func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error { if len(p.Annotations) == 0 { return nil } - for _, r := range m.Resources() { - err := r.ApplyFilter(annotations.Filter{ - Annotations: p.Annotations, - FsSlice: p.FieldSpecs, - }) - if err != nil { - return err - } - } - return nil + return m.ApplyFilter(annotations.Filter{ + Annotations: p.Annotations, + FsSlice: p.FieldSpecs, + }) } func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin { diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/HashTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/HashTransformer.go index c7ce6f7e86b..54586beeb3c 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/HashTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/HashTransformer.go @@ -11,7 +11,7 @@ import ( ) type HashTransformerPlugin struct { - hasher ifc.KunstructuredHasher + hasher ifc.KustHasher } func (p *HashTransformerPlugin) Config( @@ -24,7 +24,7 @@ func (p *HashTransformerPlugin) Config( func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error { for _, res := range m.Resources() { if res.NeedHashSuffix() { - h, err := p.hasher.Hash(res) + h, err := res.Hash(p.hasher) if err != nil { return err } diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/HelmChartInflationGenerator.go b/vendor/sigs.k8s.io/kustomize/api/builtins/HelmChartInflationGenerator.go index e03d5abadf5..2a654ad1f82 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/HelmChartInflationGenerator.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/HelmChartInflationGenerator.go @@ -6,7 +6,6 @@ package builtins import ( "bytes" "fmt" - "io" "io/ioutil" "os" "os/exec" @@ -16,7 +15,6 @@ import ( "github.com/imdario/mergo" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/yaml" @@ -25,243 +23,291 @@ import ( // HelmChartInflationGeneratorPlugin is a plugin to generate resources // from a remote or local helm chart. type HelmChartInflationGeneratorPlugin struct { - h *resmap.PluginHelpers - types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` - runHelmCommand func([]string) ([]byte, error) - types.HelmChartArgs + h *resmap.PluginHelpers + types.HelmGlobals + types.HelmChart tmpDir string } var KustomizePlugin HelmChartInflationGeneratorPlugin +const ( + valuesMergeOptionMerge = "merge" + valuesMergeOptionOverride = "override" + valuesMergeOptionReplace = "replace" +) + +var legalMergeOptions = []string{ + valuesMergeOptionMerge, + valuesMergeOptionOverride, + valuesMergeOptionReplace, +} + // Config uses the input plugin configurations `config` to setup the generator // options -func (p *HelmChartInflationGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) error { +func (p *HelmChartInflationGeneratorPlugin) Config( + h *resmap.PluginHelpers, config []byte) (err error) { + if h.GeneralConfig() == nil { + return fmt.Errorf("unable to access general config") + } + if !h.GeneralConfig().HelmConfig.Enabled { + return fmt.Errorf("must specify --enable-helm") + } + if h.GeneralConfig().HelmConfig.Command == "" { + return fmt.Errorf("must specify --helm-command") + } p.h = h - err := yaml.Unmarshal(config, p) - if err != nil { - return err + if err = yaml.Unmarshal(config, p); err != nil { + return } - tmpDir, err := filesys.NewTmpConfirmedDir() - if err != nil { - return err + return p.validateArgs() +} + +// This uses the real file system since tmpDir may be used +// by the helm subprocess. Cannot use a chroot jail or fake +// filesystem since we allow the user to use previously +// downloaded charts. This is safe since this plugin is +// owned by kustomize. +func (p *HelmChartInflationGeneratorPlugin) establishTmpDir() (err error) { + if p.tmpDir != "" { + // already done. + return nil } - p.tmpDir = string(tmpDir) - if p.ChartName == "" { - return fmt.Errorf("chartName cannot be empty") + p.tmpDir, err = ioutil.TempDir("", "kustomize-helm-") + return err +} + +func (p *HelmChartInflationGeneratorPlugin) validateArgs() (err error) { + if p.Name == "" { + return fmt.Errorf("chart name cannot be empty") } + + // ChartHome might be consulted by the plugin (to read + // values files below it), so it must be located under + // the loader root (unless root restrictions are + // disabled, in which case this can be an absolute path). if p.ChartHome == "" { - p.ChartHome = filepath.Join(p.tmpDir, "chart") - } - if p.ChartRepoName == "" { - p.ChartRepoName = "stable" + p.ChartHome = "charts" } - if p.HelmBin == "" { - p.HelmBin = "helm" + + // The ValuesFile may be consulted by the plugin, so it must + // be under the loader root (unless root restrictions are + // disabled). + if p.ValuesFile == "" { + p.ValuesFile = filepath.Join(p.ChartHome, p.Name, "values.yaml") } - if p.HelmHome == "" { - p.HelmHome = filepath.Join(p.tmpDir, ".helm") + + if err = p.errIfIllegalValuesMerge(); err != nil { + return err } - if p.Values == "" { - p.Values = filepath.Join(p.ChartHome, p.ChartName, "values.yaml") + + // ConfigHome is not loaded by the plugin, and can be located anywhere. + if p.ConfigHome == "" { + if err = p.establishTmpDir(); err != nil { + return errors.Wrap( + err, "unable to create tmp dir for HELM_CONFIG_HOME") + } + p.ConfigHome = filepath.Join(p.tmpDir, "helm") } + return nil +} + +func (p *HelmChartInflationGeneratorPlugin) errIfIllegalValuesMerge() error { if p.ValuesMerge == "" { - p.ValuesMerge = "override" - } - // runHelmCommand will run `helm` command with args provided. Return stdout - // and error if there is any. - p.runHelmCommand = func(args []string) ([]byte, error) { - stdout := new(bytes.Buffer) - stderr := new(bytes.Buffer) - cmd := exec.Command(p.HelmBin, args...) - cmd.Stdout = stdout - cmd.Stderr = stderr - cmd.Env = append(cmd.Env, - fmt.Sprintf("HELM_CONFIG_HOME=%s", p.HelmHome), - fmt.Sprintf("HELM_CACHE_HOME=%s/.cache", p.HelmHome), - fmt.Sprintf("HELM_DATA_HOME=%s/.data", p.HelmHome), - ) - err := cmd.Run() - if err != nil { - return stdout.Bytes(), - errors.Wrap( - fmt.Errorf("failed to run command %s %s", p.HelmBin, strings.Join(args, " ")), - stderr.String(), - ) + // Use the default. + p.ValuesMerge = valuesMergeOptionOverride + return nil + } + for _, opt := range legalMergeOptions { + if p.ValuesMerge == opt { + return nil } - return stdout.Bytes(), nil } - return nil + return fmt.Errorf("valuesMerge must be one of %v", legalMergeOptions) } -// EncodeValues for writing -func (p *HelmChartInflationGeneratorPlugin) EncodeValues(w io.Writer) error { - d, err := yaml.Marshal(p.ValuesLocal) - if err != nil { - return err +func (p *HelmChartInflationGeneratorPlugin) absChartHome() string { + if filepath.IsAbs(p.ChartHome) { + return p.ChartHome } - _, err = w.Write(d) + return filepath.Join(p.h.Loader().Root(), p.ChartHome) +} + +func (p *HelmChartInflationGeneratorPlugin) runHelmCommand( + args []string) ([]byte, error) { + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + cmd := exec.Command(p.h.GeneralConfig().HelmConfig.Command, args...) + cmd.Stdout = stdout + cmd.Stderr = stderr + env := []string{ + fmt.Sprintf("HELM_CONFIG_HOME=%s", p.ConfigHome), + fmt.Sprintf("HELM_CACHE_HOME=%s/.cache", p.ConfigHome), + fmt.Sprintf("HELM_DATA_HOME=%s/.data", p.ConfigHome)} + cmd.Env = append(os.Environ(), env...) + err := cmd.Run() if err != nil { - return err + helm := p.h.GeneralConfig().HelmConfig.Command + err = errors.Wrap( + fmt.Errorf( + "unable to run: '%s %s' with env=%s (is '%s' installed?)", + helm, strings.Join(args, " "), env, helm), + stderr.String(), + ) } - return nil + return stdout.Bytes(), err } -// useValuesLocal process (merge) inflator config provided values with chart default values.yaml -func (p *HelmChartInflationGeneratorPlugin) useValuesLocal() error { - // not override, merge, none - if !(p.ValuesMerge == "none" || p.ValuesMerge == "no" || p.ValuesMerge == "false") { - var pValues []byte - var err error - - if filepath.IsAbs(p.Values) { - pValues, err = ioutil.ReadFile(p.Values) - } else { - pValues, err = p.h.Loader().Load(p.Values) - } - if err != nil { - return err +// createNewMergedValuesFile replaces/merges original values file with ValuesInline. +func (p *HelmChartInflationGeneratorPlugin) createNewMergedValuesFile() ( + path string, err error) { + if p.ValuesMerge == valuesMergeOptionMerge || + p.ValuesMerge == valuesMergeOptionOverride { + if err = p.replaceValuesInline(); err != nil { + return "", err } - chValues := make(map[string]interface{}) - err = yaml.Unmarshal(pValues, &chValues) - if err != nil { - return err - } - if p.ValuesMerge == "override" { - err = mergo.Merge(&chValues, p.ValuesLocal, mergo.WithOverride) - if err != nil { - return err - } - } - if p.ValuesMerge == "merge" { - err = mergo.Merge(&chValues, p.ValuesLocal) - if err != nil { - return err - } - } - p.ValuesLocal = chValues - } - b, err := yaml.Marshal(p.ValuesLocal) - if err != nil { - return err } - path, err := p.writeValuesBytes(b) + var b []byte + b, err = yaml.Marshal(p.ValuesInline) if err != nil { - return err + return "", err } - p.Values = path - return nil + return p.writeValuesBytes(b) } -// copyValues will copy the relative values file into the temp directory -// to avoid messing up with CWD. -func (p *HelmChartInflationGeneratorPlugin) copyValues() error { - // only copy when the values path is not absolute - if filepath.IsAbs(p.Values) { - return nil - } - // we must use use loader to read values file - b, err := p.h.Loader().Load(p.Values) +func (p *HelmChartInflationGeneratorPlugin) replaceValuesInline() error { + pValues, err := p.h.Loader().Load(p.ValuesFile) if err != nil { return err } - path, err := p.writeValuesBytes(b) - if err != nil { + chValues := make(map[string]interface{}) + if err = yaml.Unmarshal(pValues, &chValues); err != nil { return err } - p.Values = path - return nil + switch p.ValuesMerge { + case valuesMergeOptionOverride: + err = mergo.Merge( + &chValues, p.ValuesInline, mergo.WithOverride) + case valuesMergeOptionMerge: + err = mergo.Merge(&chValues, p.ValuesInline) + } + p.ValuesInline = chValues + return err } -func (p *HelmChartInflationGeneratorPlugin) writeValuesBytes(b []byte) (string, error) { - path := filepath.Join(p.ChartHome, p.ChartName, "kustomize-values.yaml") - err := ioutil.WriteFile(path, b, 0644) +// copyValuesFile to avoid branching. TODO: get rid of this. +func (p *HelmChartInflationGeneratorPlugin) copyValuesFile() (string, error) { + b, err := p.h.Loader().Load(p.ValuesFile) if err != nil { return "", err } - return path, nil + return p.writeValuesBytes(b) +} + +// Write a absolute path file in the tmp file system. +func (p *HelmChartInflationGeneratorPlugin) writeValuesBytes( + b []byte) (string, error) { + if err := p.establishTmpDir(); err != nil { + return "", fmt.Errorf("cannot create tmp dir to write helm values") + } + path := filepath.Join(p.tmpDir, p.Name+"-kustomize-values.yaml") + return path, ioutil.WriteFile(path, b, 0644) +} + +func (p *HelmChartInflationGeneratorPlugin) cleanup() { + if p.tmpDir != "" { + os.RemoveAll(p.tmpDir) + } } // Generate implements generator -func (p *HelmChartInflationGeneratorPlugin) Generate() (resmap.ResMap, error) { - // cleanup - defer os.RemoveAll(p.tmpDir) - // check helm version. we only support V3 - err := p.checkHelmVersion() - if err != nil { +func (p *HelmChartInflationGeneratorPlugin) Generate() (rm resmap.ResMap, err error) { + defer p.cleanup() + if err = p.checkHelmVersion(); err != nil { return nil, err } - // pull the chart - if !p.checkLocalChart() { - _, err := p.runHelmCommand(p.getPullCommandArgs()) - if err != nil { - return nil, err + if path, exists := p.chartExistsLocally(); !exists { + if p.Repo == "" { + return nil, fmt.Errorf( + "no repo specified for pull, no chart found at '%s'", path) } - } - - // inflator config valuesLocal - if len(p.ValuesLocal) > 0 { - err := p.useValuesLocal() - if err != nil { + if _, err := p.runHelmCommand(p.pullCommand()); err != nil { return nil, err } + } + if len(p.ValuesInline) > 0 { + p.ValuesFile, err = p.createNewMergedValuesFile() } else { - err := p.copyValues() - if err != nil { - return nil, err - } + p.ValuesFile, err = p.copyValuesFile() } - - // render the charts - stdout, err := p.runHelmCommand(p.getTemplateCommandArgs()) + if err != nil { + return nil, err + } + var stdout []byte + stdout, err = p.runHelmCommand(p.templateCommand()) if err != nil { return nil, err } - return p.h.ResmapFactory().NewResMapFromBytes(stdout) + rm, err = p.h.ResmapFactory().NewResMapFromBytes(stdout) + if err == nil { + return rm, nil + } + // try to remove the contents before first "---" because + // helm may produce messages to stdout before it + stdoutStr := string(stdout) + if idx := strings.Index(stdoutStr, "---"); idx != -1 { + return p.h.ResmapFactory().NewResMapFromBytes([]byte(stdoutStr[idx:])) + } + return nil, err } -func (p *HelmChartInflationGeneratorPlugin) getTemplateCommandArgs() []string { +func (p *HelmChartInflationGeneratorPlugin) templateCommand() []string { args := []string{"template"} if p.ReleaseName != "" { args = append(args, p.ReleaseName) } - args = append(args, filepath.Join(p.ChartHome, p.ChartName)) - if p.ReleaseNamespace != "" { - args = append(args, "--namespace", p.ReleaseNamespace) + if p.Namespace != "" { + args = append(args, "--namespace", p.Namespace) + } + args = append(args, filepath.Join(p.absChartHome(), p.Name)) + if p.ValuesFile != "" { + args = append(args, "--values", p.ValuesFile) } - if p.Values != "" { - args = append(args, "--values", p.Values) + if p.ReleaseName == "" { + // AFAICT, this doesn't work as intended due to a bug in helm. + // See https://github.com/helm/helm/issues/6019 + // I've tried placing the flag before and after the name argument. + args = append(args, "--generate-name") + } + if p.IncludeCRDs { + args = append(args, "--include-crds") } - args = append(args, p.ExtraArgs...) return args } -func (p *HelmChartInflationGeneratorPlugin) getPullCommandArgs() []string { - args := []string{"pull", "--untar", "--untardir", p.ChartHome} - chartName := fmt.Sprintf("%s/%s", p.ChartRepoName, p.ChartName) - if p.ChartVersion != "" { - args = append(args, "--version", p.ChartVersion) - } - if p.ChartRepoURL != "" { - args = append(args, "--repo", p.ChartRepoURL) - chartName = p.ChartName +func (p *HelmChartInflationGeneratorPlugin) pullCommand() []string { + args := []string{ + "pull", + "--untar", + "--untardir", p.absChartHome(), + "--repo", p.Repo, + p.Name} + if p.Version != "" { + args = append(args, "--version", p.Version) } - - args = append(args, chartName) - return args } -// checkLocalChart will return true if the chart does exist in +// chartExistsLocally will return true if the chart does exist in // local chart home. -func (p *HelmChartInflationGeneratorPlugin) checkLocalChart() bool { - path := filepath.Join(p.ChartHome, p.ChartName) +func (p *HelmChartInflationGeneratorPlugin) chartExistsLocally() (string, bool) { + path := filepath.Join(p.absChartHome(), p.Name) s, err := os.Stat(path) if err != nil { - return false + return "", false } - return s.IsDir() + return path, s.IsDir() } // checkHelmVersion will return an error if the helm version is not V3 @@ -270,11 +316,17 @@ func (p *HelmChartInflationGeneratorPlugin) checkHelmVersion() error { if err != nil { return err } - r, err := regexp.Compile(`v\d+(\.\d+)+`) + r, err := regexp.Compile(`v?\d+(\.\d+)+`) if err != nil { return err } - v := string(r.Find(stdout))[1:] + v := r.FindString(string(stdout)) + if v == "" { + return fmt.Errorf("cannot find version string in %s", string(stdout)) + } + if v[0] == 'v' { + v = v[1:] + } majorVersion := strings.Split(v, ".")[0] if majorVersion != "3" { return fmt.Errorf("this plugin requires helm V3 but got v%s", v) diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/IAMPolicyGenerator.go b/vendor/sigs.k8s.io/kustomize/api/builtins/IAMPolicyGenerator.go new file mode 100644 index 00000000000..82a2dd6033d --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/IAMPolicyGenerator.go @@ -0,0 +1,33 @@ +// Code generated by pluginator on IAMPolicyGenerator; DO NOT EDIT. +// pluginator {unknown 1970-01-01T00:00:00Z } + +package builtins + +import ( + "sigs.k8s.io/kustomize/api/filters/iampolicygenerator" + "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/yaml" +) + +type IAMPolicyGeneratorPlugin struct { + types.IAMPolicyGeneratorArgs +} + +func (p *IAMPolicyGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) { + p.IAMPolicyGeneratorArgs = types.IAMPolicyGeneratorArgs{} + err = yaml.Unmarshal(config, p) + return +} + +func (p *IAMPolicyGeneratorPlugin) Generate() (resmap.ResMap, error) { + r := resmap.New() + err := r.ApplyFilter(iampolicygenerator.Filter{ + IAMPolicyGenerator: p.IAMPolicyGeneratorArgs, + }) + return r, err +} + +func NewIAMPolicyGeneratorPlugin() resmap.GeneratorPlugin { + return &IAMPolicyGeneratorPlugin{} +} diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/ImageTagTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/ImageTagTransformer.go index a09ef163dfb..52a44d3857b 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/ImageTagTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/ImageTagTransformer.go @@ -25,24 +25,15 @@ func (p *ImageTagTransformerPlugin) Config( } func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error { - for _, r := range m.Resources() { - // traverse all fields at first - err := r.ApplyFilter(imagetag.LegacyFilter{ - ImageTag: p.ImageTag, - }) - if err != nil { - return err - } - // then use user specified field specs - err = r.ApplyFilter(imagetag.Filter{ - ImageTag: p.ImageTag, - FsSlice: p.FieldSpecs, - }) - if err != nil { - return err - } + if err := m.ApplyFilter(imagetag.LegacyFilter{ + ImageTag: p.ImageTag, + }); err != nil { + return err } - return nil + return m.ApplyFilter(imagetag.Filter{ + ImageTag: p.ImageTag, + FsSlice: p.FieldSpecs, + }) } func NewImageTagTransformerPlugin() resmap.TransformerPlugin { diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/LabelTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/LabelTransformer.go index 647e57efd06..af601da5b91 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/LabelTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/LabelTransformer.go @@ -27,16 +27,10 @@ func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error { if len(p.Labels) == 0 { return nil } - for _, r := range m.Resources() { - err := r.ApplyFilter(labels.Filter{ - Labels: p.Labels, - FsSlice: p.FieldSpecs, - }) - if err != nil { - return err - } - } - return nil + return m.ApplyFilter(labels.Filter{ + Labels: p.Labels, + FsSlice: p.FieldSpecs, + }) } func NewLabelTransformerPlugin() resmap.TransformerPlugin { diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/NamespaceTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/NamespaceTransformer.go index 0ed2796a4e0..39a514e8e5a 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/NamespaceTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/NamespaceTransformer.go @@ -30,20 +30,15 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error { return nil } for _, r := range m.Resources() { - empty, err := r.IsEmpty() - if err != nil { - return err - } - if empty { + if r.IsNilOrEmpty() { // Don't mutate empty objects? continue } r.StorePreviousId() - err = r.ApplyFilter(namespace.Filter{ + if err := r.ApplyFilter(namespace.Filter{ Namespace: p.Namespace, FsSlice: p.FieldSpecs, - }) - if err != nil { + }); err != nil { return err } matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals) diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/PatchStrategicMergeTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/PatchStrategicMergeTransformer.go index 77ebbc8aeba..f93d1266d71 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/PatchStrategicMergeTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/PatchStrategicMergeTransformer.go @@ -28,45 +28,48 @@ func (p *PatchStrategicMergeTransformerPlugin) Config( return fmt.Errorf("empty file path and empty patch content") } if len(p.Paths) != 0 { - for _, onePath := range p.Paths { - // The following oddly attempts to interpret a path string as an - // actual patch (instead of as a path to a file containing a patch). - // All tests pass if this code is commented out. This code should - // be deleted; the user should use the Patches field which - // exists for this purpose (inline patch declaration). - res, err := h.ResmapFactory().RF().SliceFromBytes([]byte(onePath)) - if err == nil { - p.loadedPatches = append(p.loadedPatches, res...) - continue - } - res, err = h.ResmapFactory().RF().SliceFromPatches( - h.Loader(), []types.PatchStrategicMerge{onePath}) - if err != nil { - return err - } - p.loadedPatches = append(p.loadedPatches, res...) + patches, err := loadFromPaths(h, p.Paths) + if err != nil { + return err } + p.loadedPatches = append(p.loadedPatches, patches...) } if p.Patches != "" { - res, err := h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches)) + patches, err := h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches)) if err != nil { return err } - p.loadedPatches = append(p.loadedPatches, res...) + p.loadedPatches = append(p.loadedPatches, patches...) } - if len(p.loadedPatches) == 0 { return fmt.Errorf( "patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches) } - // Merge the patches, looking for conflicts. - _, err = h.ResmapFactory().ConflatePatches(p.loadedPatches) - if err != nil { - return err - } return nil } +func loadFromPaths( + h *resmap.PluginHelpers, + paths []types.PatchStrategicMerge) ( + result []*resource.Resource, err error) { + var patches []*resource.Resource + for _, path := range paths { + // For legacy reasons, attempt to treat the path string as + // actual patch content. + patches, err = h.ResmapFactory().RF().SliceFromBytes([]byte(path)) + if err != nil { + // Failing that, treat it as a file path. + patches, err = h.ResmapFactory().RF().SliceFromPatches( + h.Loader(), []types.PatchStrategicMerge{path}) + if err != nil { + return + } + } + result = append(result, patches...) + } + return +} + func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error { for _, patch := range p.loadedPatches { target, err := m.GetById(patch.OrgId()) diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/PatchTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/PatchTransformer.go index 0696f3e1a69..07038af1ec2 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/PatchTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/PatchTransformer.go @@ -21,6 +21,7 @@ type PatchTransformerPlugin struct { Path string `json:"path,omitempty" yaml:"path,omitempty"` Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } func (p *PatchTransformerPlugin) Config( @@ -60,6 +61,12 @@ func (p *PatchTransformerPlugin) Config( } if errSM == nil { p.loadedPatch = patchSM + if p.Options["allowNameChange"] { + p.loadedPatch.AllowNameChange() + } + if p.Options["allowKindChange"] { + p.loadedPatch.AllowKindChange() + } } else { p.decodedPatch = patchJson } @@ -69,10 +76,9 @@ func (p *PatchTransformerPlugin) Config( func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error { if p.loadedPatch == nil { return p.transformJson6902(m, p.decodedPatch) - } else { - // The patch was a strategic merge patch - return p.transformStrategicMerge(m, p.loadedPatch) } + // The patch was a strategic merge patch + return p.transformStrategicMerge(m, p.loadedPatch) } // transformStrategicMerge applies the provided strategic merge patch diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/PrefixSuffixTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/PrefixSuffixTransformer.go index 20265d592b2..57a81a0fc0b 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/PrefixSuffixTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/PrefixSuffixTransformer.go @@ -7,9 +7,9 @@ import ( "errors" "sigs.k8s.io/kustomize/api/filters/prefixsuffix" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/yaml" ) @@ -73,12 +73,11 @@ func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error { r.StorePreviousId() } } - err := r.ApplyFilter(prefixsuffix.Filter{ + if err := r.ApplyFilter(prefixsuffix.Filter{ Prefix: p.Prefix, Suffix: p.Suffix, FieldSpec: fs, - }) - if err != nil { + }); err != nil { return err } } diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/ReplacementTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/ReplacementTransformer.go new file mode 100644 index 00000000000..21e42c81e4b --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/ReplacementTransformer.go @@ -0,0 +1,59 @@ +// Code generated by pluginator on ReplacementTransformer; DO NOT EDIT. +// pluginator {unknown 1970-01-01T00:00:00Z } + +package builtins + +import ( + "fmt" + + "sigs.k8s.io/kustomize/api/filters/replacement" + "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/yaml" +) + +// Replace values in targets with values from a source +type ReplacementTransformerPlugin struct { + ReplacementList []types.ReplacementField `json:"replacements,omitempty" yaml:"replacements,omitempty"` + Replacements []types.Replacement `json:"omitempty" yaml:"omitempty"` +} + +func (p *ReplacementTransformerPlugin) Config( + h *resmap.PluginHelpers, c []byte) (err error) { + p.ReplacementList = []types.ReplacementField{} + if err := yaml.Unmarshal(c, p); err != nil { + return err + } + + for _, r := range p.ReplacementList { + if r.Path != "" && (r.Source != nil || len(r.Targets) != 0) { + return fmt.Errorf("cannot specify both path and inline replacement") + } + if r.Path != "" { + // load the replacement from the path + content, err := h.Loader().Load(r.Path) + if err != nil { + return err + } + repl := types.Replacement{} + if err := yaml.Unmarshal(content, &repl); err != nil { + return err + } + p.Replacements = append(p.Replacements, repl) + } else { + // replacement information is already loaded + p.Replacements = append(p.Replacements, r.Replacement) + } + } + return nil +} + +func (p *ReplacementTransformerPlugin) Transform(m resmap.ResMap) (err error) { + return m.ApplyFilter(replacement.Filter{ + Replacements: p.Replacements, + }) +} + +func NewReplacementTransformerPlugin() resmap.TransformerPlugin { + return &ReplacementTransformerPlugin{} +} diff --git a/vendor/sigs.k8s.io/kustomize/api/builtins/ReplicaCountTransformer.go b/vendor/sigs.k8s.io/kustomize/api/builtins/ReplicaCountTransformer.go index 03fbf6f1e5f..120fab34006 100644 --- a/vendor/sigs.k8s.io/kustomize/api/builtins/ReplicaCountTransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/builtins/ReplicaCountTransformer.go @@ -7,9 +7,9 @@ import ( "fmt" "sigs.k8s.io/kustomize/api/filters/replicacount" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/yaml" ) diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/filesystem.go b/vendor/sigs.k8s.io/kustomize/api/filesys/filesystem.go deleted file mode 100644 index 041b4bdb398..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/filesys/filesystem.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -// Package filesys provides a file system abstraction layer. -package filesys - -import ( - "path/filepath" -) - -const ( - Separator = string(filepath.Separator) - SelfDir = "." - ParentDir = ".." -) - -// FileSystem groups basic os filesystem methods. -// It's supposed be functional subset of https://golang.org/pkg/os -type FileSystem interface { - // Create a file. - Create(path string) (File, error) - // MkDir makes a directory. - Mkdir(path string) error - // MkDirAll makes a directory path, creating intervening directories. - MkdirAll(path string) error - // RemoveAll removes path and any children it contains. - RemoveAll(path string) error - // Open opens the named file for reading. - Open(path string) (File, error) - // IsDir returns true if the path is a directory. - IsDir(path string) bool - // CleanedAbs converts the given path into a - // directory and a file name, where the directory - // is represented as a ConfirmedDir and all that implies. - // If the entire path is a directory, the file component - // is an empty string. - CleanedAbs(path string) (ConfirmedDir, string, error) - // Exists is true if the path exists in the file system. - Exists(path string) bool - // Glob returns the list of matching files, - // emulating https://golang.org/pkg/path/filepath/#Glob - Glob(pattern string) ([]string, error) - // ReadFile returns the contents of the file at the given path. - ReadFile(path string) ([]byte, error) - // WriteFile writes the data to a file at the given path, - // overwriting anything that's already there. - WriteFile(path string, data []byte) error - // Walk walks the file system with the given WalkFunc. - Walk(path string, walkFn filepath.WalkFunc) error -} diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/fieldspec.go b/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/fieldspec.go index d728e9ebcf2..8739d073336 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/fieldspec.go +++ b/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/fieldspec.go @@ -11,6 +11,7 @@ import ( "sigs.k8s.io/kustomize/api/internal/utils" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -45,12 +46,11 @@ type Filter struct { func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) { // check if the FieldSpec applies to the object - if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil { - return obj, errors.Wrap(err) + if match := isMatchGVK(fltr.FieldSpec, obj); !match { + return obj, nil } - fltr.path = utils.PathSplitter(fltr.FieldSpec.Path) - err := fltr.filter(obj) - if err != nil { + fltr.path = utils.PathSplitter(fltr.FieldSpec.Path, "/") + if err := fltr.filter(obj); err != nil { s, _ := obj.String() return nil, errors.WrapPrefixf(err, "considering field '%s' of object\n%v", fltr.FieldSpec.Path, s) @@ -158,28 +158,24 @@ func isSequenceField(name string) (string, bool) { } // isMatchGVK returns true if the fs.GVK matches the obj GVK. -func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) (bool, error) { - meta, err := obj.GetMeta() - if err != nil { - return false, err - } - if fs.Kind != "" && fs.Kind != meta.Kind { +func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) bool { + if kind := obj.GetKind(); fs.Kind != "" && fs.Kind != kind { // kind doesn't match - return false, err + return false } // parse the group and version from the apiVersion field - group, version := parseGV(meta.APIVersion) + group, version := resid.ParseGroupVersion(obj.GetApiVersion()) if fs.Group != "" && fs.Group != group { // group doesn't match - return false, nil + return false } if fs.Version != "" && fs.Version != version { // version doesn't match - return false, nil + return false } - return true, nil + return true } diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/gvk.go b/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/gvk.go deleted file mode 100644 index 42e21a80dc2..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/filters/fieldspec/gvk.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 -package fieldspec - -import ( - "strings" - - "sigs.k8s.io/kustomize/api/resid" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// Return true for 'v' followed by a 1 or 2, and don't look at rest. -// I.e. 'v1', 'v1beta1', 'v2', would return true. -func looksLikeACoreApiVersion(s string) bool { - if len(s) < 2 { - return false - } - if s[0:1] != "v" { - return false - } - return s[1:2] == "1" || s[1:2] == "2" -} - -// parseGV parses apiVersion field into group and version. -func parseGV(apiVersion string) (group, version string) { - // parse the group and version from the apiVersion field - parts := strings.SplitN(apiVersion, "/", 2) - group = parts[0] - if len(parts) > 1 { - version = parts[1] - } - // Special case the original "apiVersion" of what - // we now call the "core" (empty) group. - if version == "" && looksLikeACoreApiVersion(group) { - version = group - group = "" - } - return -} - -// GetGVK parses the metadata into a GVK -func GetGVK(meta yaml.ResourceMeta) resid.Gvk { - group, version := parseGV(meta.APIVersion) - return resid.Gvk{ - Group: group, - Version: version, - Kind: meta.Kind, - } -} diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/iampolicygenerator/doc.go b/vendor/sigs.k8s.io/kustomize/api/filters/iampolicygenerator/doc.go new file mode 100644 index 00000000000..d0ac6d91f8f --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/filters/iampolicygenerator/doc.go @@ -0,0 +1,3 @@ +// Package gkesagenerator contains a kio.Filter that that generates a +// iampolicy-related resources for a given cloud provider +package iampolicygenerator diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/iampolicygenerator/iampolicygenerator.go b/vendor/sigs.k8s.io/kustomize/api/filters/iampolicygenerator/iampolicygenerator.go new file mode 100644 index 00000000000..c1f8593fbe7 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/filters/iampolicygenerator/iampolicygenerator.go @@ -0,0 +1,55 @@ +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package iampolicygenerator + +import ( + "fmt" + + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type Filter struct { + IAMPolicyGenerator types.IAMPolicyGeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` +} + +// Filter adds a GKE service account object to nodes +func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + switch f.IAMPolicyGenerator.Cloud { + case types.GKE: + IAMPolicyResources, err := f.generateGkeIAMPolicyResources() + if err != nil { + return nil, err + } + nodes = append(nodes, IAMPolicyResources...) + default: + return nil, fmt.Errorf("cloud provider %s not supported yet", f.IAMPolicyGenerator.Cloud) + } + return nodes, nil +} + +func (f Filter) generateGkeIAMPolicyResources() ([]*yaml.RNode, error) { + var result []*yaml.RNode + input := fmt.Sprintf(` +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + iam.gke.io/gcp-service-account: %s@%s.iam.gserviceaccount.com + name: %s +`, f.IAMPolicyGenerator.ServiceAccount.Name, + f.IAMPolicyGenerator.ProjectId, + f.IAMPolicyGenerator.KubernetesService.Name) + + if f.IAMPolicyGenerator.Namespace != "" { + input = input + fmt.Sprintf("\n namespace: %s", f.IAMPolicyGenerator.Namespace) + } + + sa, err := yaml.Parse(input) + if err != nil { + return nil, err + } + + return append(result, sa), nil +} diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/imagetag/legacy.go b/vendor/sigs.k8s.io/kustomize/api/filters/imagetag/legacy.go index 5014e9c82b8..d07080b8eee 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filters/imagetag/legacy.go +++ b/vendor/sigs.k8s.io/kustomize/api/filters/imagetag/legacy.go @@ -4,6 +4,7 @@ package imagetag import ( + "sigs.k8s.io/kustomize/api/internal/utils" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -74,7 +75,7 @@ func (f findFieldsFilter) walk(node *yaml.RNode) error { return err } key := n.Key.YNode().Value - if contains(f.fields, key) { + if utils.StringSliceContains(f.fields, key) { return f.fieldCallback(n.Value) } return nil @@ -87,15 +88,6 @@ func (f findFieldsFilter) walk(node *yaml.RNode) error { return nil } -func contains(slice []string, str string) bool { - for _, s := range slice { - if s == str { - return true - } - } - return false -} - func checkImageTagsFn(imageTag types.Image) fieldCallback { return func(node *yaml.RNode) error { if node.YNode().Kind != yaml.SequenceNode { diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go b/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go index e5a3d2635a0..850059fb220 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go +++ b/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go @@ -1,18 +1,16 @@ package nameref import ( - "encoding/json" "fmt" "strings" "github.com/pkg/errors" "sigs.k8s.io/kustomize/api/filters/fieldspec" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" - "sigs.k8s.io/kustomize/kyaml/filtersutil" "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -186,11 +184,7 @@ func (f Filter) recordTheReferral(referral *resource.Resource) { // getRoleRefGvk returns a Gvk in the roleRef field. Return error // if the roleRef, roleRef/apiGroup or roleRef/kind is missing. -func getRoleRefGvk(res json.Marshaler) (*resid.Gvk, error) { - n, err := filtersutil.GetRNode(res) - if err != nil { - return nil, err - } +func getRoleRefGvk(n *resource.Resource) (*resid.Gvk, error) { roleRef, err := n.Pipe(yaml.Lookup("roleRef")) if err != nil { return nil, err @@ -263,8 +257,7 @@ func previousIdSelectedByGvk(gvk *resid.Gvk) sieveFunc { // If the we are updating a 'roleRef/name' field, the 'apiGroup' and 'kind' // fields in the same 'roleRef' map must be considered. -// If either object is cluster-scoped (!IsNamespaceableKind), there -// can be a referral. +// If either object is cluster-scoped, there can be a referral. // E.g. a RoleBinding (which exists in a namespace) can refer // to a ClusterRole (cluster-scoped) object. // https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole @@ -291,12 +284,12 @@ func prefixSuffixEquals(other resource.ResCtx) sieveFunc { func (f Filter) sameCurrentNamespaceAsReferrer() sieveFunc { referrerCurId := f.Referrer.CurId() - if !referrerCurId.IsNamespaceableKind() { + if referrerCurId.IsClusterScoped() { // If the referrer is cluster-scoped, let anything through. return acceptAll } return func(r *resource.Resource) bool { - if !r.CurId().IsNamespaceableKind() { + if r.CurId().IsClusterScoped() { // Allow cluster-scoped through. return true } diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/namespace/namespace.go b/vendor/sigs.k8s.io/kustomize/api/filters/namespace/namespace.go index 85e56c57243..e554600bc14 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filters/namespace/namespace.go +++ b/vendor/sigs.k8s.io/kustomize/api/filters/namespace/namespace.go @@ -4,11 +4,11 @@ package namespace import ( - "sigs.k8s.io/kustomize/api/filters/fieldspec" "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -54,16 +54,11 @@ func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) { // hacks applies the namespace transforms that are hardcoded rather // than specified through FieldSpecs. func (ns Filter) hacks(obj *yaml.RNode) error { - meta, err := obj.GetMeta() - if err != nil { + gvk := resid.GvkFromNode(obj) + if err := ns.metaNamespaceHack(obj, gvk); err != nil { return err } - - if err := ns.metaNamespaceHack(obj, meta); err != nil { - return err - } - - return ns.roleBindingHack(obj, meta) + return ns.roleBindingHack(obj, gvk) } // metaNamespaceHack is a hack for implementing the namespace transform @@ -74,9 +69,8 @@ func (ns Filter) hacks(obj *yaml.RNode) error { // This hack should be updated to allow individual resources to specify // if they are cluster scoped through either an annotation on the resources, // or through inlined OpenAPI on the resource as a YAML comment. -func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error { - gvk := fieldspec.GetGVK(meta) - if !gvk.IsNamespaceableKind() { +func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error { + if gvk.IsClusterScoped() { return nil } f := fsslice.Filter{ @@ -104,8 +98,8 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) erro // ... // - name: "something-else" # this will not have the namespace set // ... -func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error { - if meta.Kind != roleBindingKind && meta.Kind != clusterRoleBindingKind { +func (ns Filter) roleBindingHack(obj *yaml.RNode, gvk resid.Gvk) error { + if gvk.Kind != roleBindingKind && gvk.Kind != clusterRoleBindingKind { return nil } @@ -118,7 +112,6 @@ func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error // add the namespace to each "subject" with name: default err = obj.VisitElements(func(o *yaml.RNode) error { - // copied from kunstruct based kustomize NamespaceTransformer plugin // The only case we need to force the namespace // if for the "service account". "default" is // kind of hardcoded here for right now. diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/patchstrategicmerge/patchstrategicmerge.go b/vendor/sigs.k8s.io/kustomize/api/filters/patchstrategicmerge/patchstrategicmerge.go index 3fa532df053..1a70d19aace 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filters/patchstrategicmerge/patchstrategicmerge.go +++ b/vendor/sigs.k8s.io/kustomize/api/filters/patchstrategicmerge/patchstrategicmerge.go @@ -4,7 +4,6 @@ package patchstrategicmerge import ( - "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml/merge2" @@ -29,7 +28,7 @@ func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { if err != nil { return nil, err } - if !konfig.FlagEnableKyamlDefaultValue || r != nil { + if r != nil { result = append(result, r) } } diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/replacement/doc.go b/vendor/sigs.k8s.io/kustomize/api/filters/replacement/doc.go new file mode 100644 index 00000000000..9d9357905d4 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/filters/replacement/doc.go @@ -0,0 +1,4 @@ +// Package replacement contains a kio.Filter implementation of the kustomize +// replacement transformer (accepts sources and looks for targets to replace +// their values with values from the sources). +package replacement diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/replacement/replacement.go b/vendor/sigs.k8s.io/kustomize/api/filters/replacement/replacement.go new file mode 100644 index 00000000000..7988c322b69 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/filters/replacement/replacement.go @@ -0,0 +1,180 @@ +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package replacement + +import ( + "fmt" + "strings" + + "sigs.k8s.io/kustomize/api/internal/utils" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/resid" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type Filter struct { + Replacements []types.Replacement `json:"replacements,omitempty" yaml:"replacements,omitempty"` +} + +// Filter replaces values of targets with values from sources +func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + for _, r := range f.Replacements { + if r.Source == nil || r.Targets == nil { + return nil, fmt.Errorf("replacements must specify a source and at least one target") + } + value, err := getReplacement(nodes, &r) + if err != nil { + return nil, err + } + nodes, err = applyReplacement(nodes, value, r.Targets) + if err != nil { + return nil, err + } + } + return nodes, nil +} + +func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.TargetSelector) ([]*yaml.RNode, error) { + for _, t := range targets { + if t.Select == nil { + return nil, fmt.Errorf("target must specify resources to select") + } + if len(t.FieldPaths) == 0 { + t.FieldPaths = []string{types.DefaultReplacementFieldPath} + } + for _, n := range nodes { + ids, err := utils.MakeResIds(n) + if err != nil { + return nil, err + } + for _, id := range ids { + if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) { + err := applyToNode(n, value, t) + if err != nil { + return nil, err + } + break + } + } + } + } + return nodes, nil +} + +func rejectId(rejects []*types.Selector, id *resid.ResId) bool { + for _, r := range rejects { + if id.IsSelectedBy(r.ResId) { + return true + } + } + return false +} + +func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.TargetSelector) error { + for _, fp := range target.FieldPaths { + fieldPath := utils.SmarterPathSplitter(fp, ".") + var t *yaml.RNode + var err error + if target.Options != nil && target.Options.Create { + t, err = node.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...)) + } else { + t, err = node.Pipe(yaml.Lookup(fieldPath...)) + } + if err != nil { + return err + } + if t != nil { + if err = setTargetValue(target.Options, t, value); err != nil { + return err + } + } + } + return nil +} + +func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error { + value = value.Copy() + if options != nil && options.Delimiter != "" { + if t.YNode().Kind != yaml.ScalarNode { + return fmt.Errorf("delimiter option can only be used with scalar nodes") + } + tv := strings.Split(t.YNode().Value, options.Delimiter) + v := yaml.GetValue(value) + // TODO: Add a way to remove an element + switch { + case options.Index < 0: // prefix + tv = append([]string{v}, tv...) + case options.Index >= len(tv): // suffix + tv = append(tv, v) + default: // replace an element + tv[options.Index] = v + } + value.YNode().Value = strings.Join(tv, options.Delimiter) + } + t.SetYNode(value.YNode()) + return nil +} + +func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, error) { + source, err := selectSourceNode(nodes, r.Source) + if err != nil { + return nil, err + } + + if r.Source.FieldPath == "" { + r.Source.FieldPath = types.DefaultReplacementFieldPath + } + fieldPath := utils.SmarterPathSplitter(r.Source.FieldPath, ".") + + rn, err := source.Pipe(yaml.Lookup(fieldPath...)) + if err != nil { + return nil, err + } + if !rn.IsNilOrEmpty() { + return getRefinedValue(r.Source.Options, rn) + } + return rn, nil +} + +func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode, error) { + if options == nil || options.Delimiter == "" { + return rn, nil + } + if rn.YNode().Kind != yaml.ScalarNode { + return nil, fmt.Errorf("delimiter option can only be used with scalar nodes") + } + value := strings.Split(yaml.GetValue(rn), options.Delimiter) + if options.Index >= len(value) || options.Index < 0 { + return nil, fmt.Errorf("options.index %d is out of bounds for value %s", options.Index, yaml.GetValue(rn)) + } + n := rn.Copy() + n.YNode().Value = value[options.Index] + return n, nil +} + +// selectSourceNode finds the node that matches the selector, returning +// an error if multiple or none are found +func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yaml.RNode, error) { + var matches []*yaml.RNode + for _, n := range nodes { + ids, err := utils.MakeResIds(n) + if err != nil { + return nil, err + } + for _, id := range ids { + if id.IsSelectedBy(selector.ResId) { + if len(matches) > 0 { + return nil, fmt.Errorf( + "multiple matches for selector %s", selector) + } + matches = append(matches, n) + break + } + } + } + if len(matches) == 0 { + return nil, fmt.Errorf("nothing selected by %s", selector) + } + return matches[0], nil +} diff --git a/vendor/sigs.k8s.io/kustomize/api/filters/valueadd/valueadd.go b/vendor/sigs.k8s.io/kustomize/api/filters/valueadd/valueadd.go index 326466a45dd..f8e6b2f8261 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filters/valueadd/valueadd.go +++ b/vendor/sigs.k8s.io/kustomize/api/filters/valueadd/valueadd.go @@ -6,7 +6,7 @@ package valueadd import ( "strings" - "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/kyaml/filesys" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" ) diff --git a/vendor/sigs.k8s.io/kustomize/api/hasher/hasher.go b/vendor/sigs.k8s.io/kustomize/api/hasher/hasher.go index 36d930af69d..aef436d9192 100644 --- a/vendor/sigs.k8s.io/kustomize/api/hasher/hasher.go +++ b/vendor/sigs.k8s.io/kustomize/api/hasher/hasher.go @@ -20,12 +20,12 @@ func SortArrayAndComputeHash(s []string) (string, error) { if err != nil { return "", err } - return Encode(Hash(string(data))) + return encode(hex256(string(data))) } // Copied from https://github.com/kubernetes/kubernetes // /blob/master/pkg/kubectl/util/hash/hash.go -func Encode(hex string) (string, error) { +func encode(hex string) (string, error) { if len(hex) < 10 { return "", fmt.Errorf( "input length must be at least 10") @@ -48,23 +48,18 @@ func Encode(hex string) (string, error) { return string(enc), nil } -// Hash returns the hex form of the sha256 of the argument. -func Hash(data string) string { +// hex256 returns the hex form of the sha256 of the argument. +func hex256(data string) string { return fmt.Sprintf("%x", sha256.Sum256([]byte(data))) } -// HashRNode returns the hash value of input RNode -func HashRNode(node *yaml.RNode) (string, error) { - // get node kind - kindNode, err := node.Pipe(yaml.FieldMatcher{Name: "kind"}) - if err != nil { - return "", err - } - kind := kindNode.YNode().Value +// Hasher computes the hash of an RNode. +type Hasher struct{} - // calculate hash for different kinds - encoded := "" - switch kind { +// Hash returns a hash of the argument. +func (h *Hasher) Hash(node *yaml.RNode) (r string, err error) { + var encoded string + switch node.GetKind() { case "ConfigMap": encoded, err = encodeConfigMap(node) case "Secret": @@ -77,10 +72,11 @@ func HashRNode(node *yaml.RNode) (string, error) { if err != nil { return "", err } - return Encode(Hash(encoded)) + return encode(hex256(encoded)) } -func getNodeValues(node *yaml.RNode, paths []string) (map[string]interface{}, error) { +func getNodeValues( + node *yaml.RNode, paths []string) (map[string]interface{}, error) { values := make(map[string]interface{}) for _, p := range paths { vn, err := node.Pipe(yaml.Lookup(p)) @@ -117,8 +113,11 @@ func encodeConfigMap(node *yaml.RNode) (string, error) { if err != nil { return "", err } - m := map[string]interface{}{"kind": "ConfigMap", "name": values["metadata/name"], - "data": values["data"]} + m := map[string]interface{}{ + "kind": "ConfigMap", + "name": values["metadata/name"], + "data": values["data"], + } if _, ok := values["binaryData"].(map[string]interface{}); ok { m["binaryData"] = values["binaryData"] } diff --git a/vendor/sigs.k8s.io/kustomize/api/ifc/ifc.go b/vendor/sigs.k8s.io/kustomize/api/ifc/ifc.go index ee1ce0338be..9fd297478ad 100644 --- a/vendor/sigs.k8s.io/kustomize/api/ifc/ifc.go +++ b/vendor/sigs.k8s.io/kustomize/api/ifc/ifc.go @@ -5,8 +5,8 @@ package ifc import ( - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/yaml" ) // Validator provides functions to validate annotations and labels @@ -38,92 +38,10 @@ type Loader interface { Cleanup() error } -// Kunstructured represents a Kubernetes Resource Model object. -type Kunstructured interface { - // Several uses. - Copy() Kunstructured - - // GetAnnotations returns the k8s annotations. - GetAnnotations() map[string]string - - // GetData returns a top-level "data" field, as in a ConfigMap. - GetDataMap() map[string]string - - // GetData returns a top-level "binaryData" field, as in a ConfigMap. - GetBinaryDataMap() map[string]string - - // Used by ResAccumulator and ReplacementTransformer. - GetFieldValue(string) (interface{}, error) - - // Used by Resource.OrgId - GetGvk() resid.Gvk - - // Used by resource.Factory.SliceFromBytes - GetKind() string - - // GetLabels returns the k8s labels. - GetLabels() map[string]string - - // Used by Resource.CurId and resource factory. - GetName() string - - // Used by special case code in - // ResMap.SubsetThatCouldBeReferencedByResource - GetSlice(path string) ([]interface{}, error) - - // GetString returns the value of a string field. - // Used by Resource.GetNamespace - GetString(string) (string, error) - - // Several uses. - Map() (map[string]interface{}, error) - - // Used by Resource.AsYAML and Resource.String - MarshalJSON() ([]byte, error) - - // Used by resWrangler.Select - MatchesAnnotationSelector(selector string) (bool, error) - - // Used by resWrangler.Select - MatchesLabelSelector(selector string) (bool, error) - - // SetAnnotations replaces the k8s annotations. - SetAnnotations(map[string]string) - - // SetDataMap sets a top-level "data" field, as in a ConfigMap. - SetDataMap(map[string]string) - - // SetDataMap sets a top-level "binaryData" field, as in a ConfigMap. - SetBinaryDataMap(map[string]string) - // Used by PatchStrategicMergeTransformer. - SetGvk(resid.Gvk) - - // SetLabels replaces the k8s labels. - SetLabels(map[string]string) - - // SetName changes the name. - SetName(string) - - // SetNamespace changes the namespace. - SetNamespace(string) - - // Needed, for now, by kyaml/filtersutil.ApplyToJSON. - UnmarshalJSON([]byte) error -} - -// KunstructuredFactory makes instances of Kunstructured. -type KunstructuredFactory interface { - SliceFromBytes([]byte) ([]Kunstructured, error) - FromMap(m map[string]interface{}) Kunstructured - Hasher() KunstructuredHasher - MakeConfigMap(kvLdr KvLoader, args *types.ConfigMapArgs) (Kunstructured, error) - MakeSecret(kvLdr KvLoader, args *types.SecretArgs) (Kunstructured, error) -} - -// KunstructuredHasher returns a hash of the argument +// KustHasher returns a hash of the argument // or an error. -type KunstructuredHasher interface { - Hash(Kunstructured) (string, error) +type KustHasher interface { + Hash(*yaml.RNode) (string, error) } // See core.v1.SecretTypeOpaque diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go b/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go index a43f66d8fa7..cac47c0de68 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go @@ -7,13 +7,13 @@ import ( "encoding/json" "strings" - "github.com/go-openapi/spec" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/api/filesys" + "k8s.io/kube-openapi/pkg/validation/spec" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filesys" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/yaml" ) @@ -25,7 +25,7 @@ type OpenAPIDefinition struct { Dependencies []string } -type myProperties map[string]spec.Schema +type myProperties = map[string]spec.Schema type nameToApiMap map[string]OpenAPIDefinition // LoadConfigFromCRDs parse CRD schemas from paths into a TransformerConfig @@ -178,9 +178,12 @@ func loadCrdIntoConfig( } } if property.Ref.GetURL() != nil { - loadCrdIntoConfig( + err = loadCrdIntoConfig( theConfig, theGvk, theMap, property.Ref.String(), append(path, propName)) + if err != nil { + return + } } } return nil diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/resaccumulator.go b/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/resaccumulator.go index b49db9b1211..2723feafcf9 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/resaccumulator.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/resaccumulator.go @@ -9,9 +9,9 @@ import ( "strings" "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/resid" ) // ResAccumulator accumulates resources and the rules @@ -72,7 +72,7 @@ func (ra *ResAccumulator) MergeVars(incoming []types.Var) error { for _, v := range incoming { targetId := resid.NewResIdWithNamespace(v.ObjRef.GVK(), v.ObjRef.Name, v.ObjRef.Namespace) idMatcher := targetId.GvknEquals - if targetId.Namespace != "" || !targetId.IsNamespaceableKind() { + if targetId.Namespace != "" || targetId.IsClusterScoped() { // Preserve backward compatibility. An empty namespace means // wildcard search on the namespace hence we still use GvknEquals idMatcher = targetId.Equals @@ -107,6 +107,7 @@ func (ra *ResAccumulator) findVarValueFromResources(v types.Var) (interface{}, e for _, res := range ra.resMap.Resources() { for _, varName := range res.GetRefVarNames() { if varName == v.Name { + //nolint: staticcheck s, err := res.GetFieldValue(v.FieldRef.FieldPath) if err != nil { return "", fmt.Errorf( diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/conflict/factory.go b/vendor/sigs.k8s.io/kustomize/api/internal/conflict/factory.go deleted file mode 100644 index 3cfed193a1b..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/internal/conflict/factory.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package conflict - -import ( - "sigs.k8s.io/kustomize/api/resid" - "sigs.k8s.io/kustomize/api/resource" -) - -type cdFactory struct{} - -var _ resource.ConflictDetectorFactory = &cdFactory{} - -// NewFactory returns a new conflict detector factory. -func NewFactory() resource.ConflictDetectorFactory { - return &cdFactory{} -} - -// New returns an instance of smPatchMergeOnlyDetector. -func (c cdFactory) New(_ resid.Gvk) (resource.ConflictDetector, error) { - return &smPatchMergeOnlyDetector{}, nil -} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/conflict/smpatchmergeonlydetector.go b/vendor/sigs.k8s.io/kustomize/api/internal/conflict/smpatchmergeonlydetector.go deleted file mode 100644 index a33fdc3c38f..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/internal/conflict/smpatchmergeonlydetector.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package conflict - -import ( - "sigs.k8s.io/kustomize/api/resource" -) - -// smPatchMergeOnlyDetector ignores conflicts, -// but does real strategic merge patching. -// This is part of an effort to eliminate dependence on -// apimachinery package to allow kustomize integration -// into kubectl (#2506 and #1500) -type smPatchMergeOnlyDetector struct{} - -var _ resource.ConflictDetector = &smPatchMergeOnlyDetector{} - -func (c *smPatchMergeOnlyDetector) HasConflict( - _, _ *resource.Resource) (bool, error) { - return false, nil -} - -// There's at least one case that doesn't work. Suppose one has a -// Deployment with a volume with the bizarre "emptyDir: {}" entry. -// If you want to get rid of this entry via a patch containing -// the entry "emptyDir: null", then the following won't work, -// because null entries are eliminated. -func (c *smPatchMergeOnlyDetector) MergePatches( - r, patch *resource.Resource) (*resource.Resource, error) { - err := r.ApplySmPatch(patch) - return r, err -} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/generators/configmap.go b/vendor/sigs.k8s.io/kustomize/api/internal/generators/configmap.go index 19a0e2832e3..47498aaa587 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/generators/configmap.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/generators/configmap.go @@ -40,6 +40,13 @@ func MakeConfigMap( if err = rn.LoadMapIntoConfigMapData(m); err != nil { return nil, err } - copyLabelsAndAnnotations(rn, args.Options) + err = copyLabelsAndAnnotations(rn, args.Options) + if err != nil { + return nil, err + } + err = setImmutable(rn, args.Options) + if err != nil { + return nil, err + } return rn, nil } diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/generators/secret.go b/vendor/sigs.k8s.io/kustomize/api/internal/generators/secret.go index a46f497db28..9afaff156a8 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/generators/secret.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/generators/secret.go @@ -54,5 +54,6 @@ func MakeSecret( return nil, err } copyLabelsAndAnnotations(rn, args.Options) + setImmutable(rn, args.Options) return rn, nil } diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/generators/utils.go b/vendor/sigs.k8s.io/kustomize/api/internal/generators/utils.go index d1630fc847d..82040d42072 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/generators/utils.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/generators/utils.go @@ -76,3 +76,16 @@ func copyLabelsAndAnnotations( } return nil } + +func setImmutable( + rn *yaml.RNode, opts *types.GeneratorOptions) error { + if opts == nil { + return nil + } + if opts.Immutable { + if _, err := rn.Pipe(yaml.SetField("immutable", yaml.NewScalarRNode("true"))); err != nil { + return err + } + } + return nil +} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/git/cloner.go b/vendor/sigs.k8s.io/kustomize/api/internal/git/cloner.go index e3daccd88ae..78f4f32cbba 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/git/cloner.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/git/cloner.go @@ -4,7 +4,7 @@ package git import ( - "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/kyaml/filesys" ) // Cloner is a function that can clone a git repo. @@ -14,7 +14,7 @@ type Cloner func(repoSpec *RepoSpec) error // to say, some remote API, to obtain a local clone of // a remote repo. func ClonerUsingGitExec(repoSpec *RepoSpec) error { - r, err := newCmdRunner() + r, err := newCmdRunner(repoSpec.Timeout) if err != nil { return err } @@ -36,7 +36,10 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error { if err = r.run("checkout", "FETCH_HEAD"); err != nil { return err } - return r.run("submodule", "update", "--init", "--recursive") + if repoSpec.Submodules { + return r.run("submodule", "update", "--init", "--recursive") + } + return nil } // DoNothingCloner returns a cloner that only sets diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/git/gitrunner.go b/vendor/sigs.k8s.io/kustomize/api/internal/git/gitrunner.go index 94bb78c6005..fcc7130cdf6 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/git/gitrunner.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/git/gitrunner.go @@ -8,13 +8,10 @@ import ( "time" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/internal/utils" + "sigs.k8s.io/kustomize/kyaml/filesys" ) -// Arbitrary, but non-infinite, timeout for running commands. -const defaultDuration = 27 * time.Second - // gitRunner runs the external git binary. type gitRunner struct { gitProgram string @@ -24,7 +21,7 @@ type gitRunner struct { // newCmdRunner returns a gitRunner if it can find the binary. // It also creats a temp directory for cloning repos. -func newCmdRunner() (*gitRunner, error) { +func newCmdRunner(timeout time.Duration) (*gitRunner, error) { gitProgram, err := exec.LookPath("git") if err != nil { return nil, errors.Wrap(err, "no 'git' program on path") @@ -35,7 +32,7 @@ func newCmdRunner() (*gitRunner, error) { } return &gitRunner{ gitProgram: gitProgram, - duration: defaultDuration, + duration: timeout, dir: dir, }, nil } diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/git/repospec.go b/vendor/sigs.k8s.io/kustomize/api/internal/git/repospec.go index ad8dfc24d72..5a935f510ad 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/git/repospec.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/git/repospec.go @@ -5,11 +5,13 @@ package git import ( "fmt" + "net/url" "path/filepath" - "regexp" + "strconv" "strings" + "time" - "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/kyaml/filesys" ) // Used as a temporary non-empty occupant of the cloneDir @@ -44,6 +46,12 @@ type RepoSpec struct { // e.g. .git or empty in case of _git is present GitSuffix string + + // Submodules indicates whether or not to clone git submodules. + Submodules bool + + // Timeout is the maximum duration allowed for execing git commands. + Timeout time.Duration } // CloneSpec returns a string suitable for "git clone {spec}". @@ -70,6 +78,7 @@ func (x *RepoSpec) Cleaner(fSys filesys.FileSystem) func() error { return func() error { return fSys.RemoveAll(x.Dir.String()) } } +// NewRepoSpecFromUrl parses git-like urls. // From strings like git@github.com:someOrg/someRepo.git or // https://github.com/someOrg/someRepo?ref=someHash, extract // the parts. @@ -77,7 +86,7 @@ func NewRepoSpecFromUrl(n string) (*RepoSpec, error) { if filepath.IsAbs(n) { return nil, fmt.Errorf("uri looks like abs path: %s", n) } - host, orgRepo, path, gitRef, gitSuffix := parseGitUrl(n) + host, orgRepo, path, gitRef, gitSubmodules, suffix, gitTimeout := parseGitUrl(n) if orgRepo == "" { return nil, fmt.Errorf("url lacks orgRepo: %s", n) } @@ -86,28 +95,28 @@ func NewRepoSpecFromUrl(n string) (*RepoSpec, error) { } return &RepoSpec{ raw: n, Host: host, OrgRepo: orgRepo, - Dir: notCloned, Path: path, Ref: gitRef, GitSuffix: gitSuffix}, nil + Dir: notCloned, Path: path, Ref: gitRef, GitSuffix: suffix, + Submodules: gitSubmodules, Timeout: gitTimeout}, nil } const ( - refQuery = "?ref=" - refQueryRegex = "\\?(version|ref)=" - gitSuffix = ".git" - gitDelimiter = "_git/" + refQuery = "?ref=" + gitSuffix = ".git" + gitDelimiter = "_git/" ) // From strings like git@github.com:someOrg/someRepo.git or // https://github.com/someOrg/someRepo?ref=someHash, extract // the parts. func parseGitUrl(n string) ( - host string, orgRepo string, path string, gitRef string, gitSuff string) { + host string, orgRepo string, path string, gitRef string, gitSubmodules bool, gitSuff string, gitTimeout time.Duration) { if strings.Contains(n, gitDelimiter) { index := strings.Index(n, gitDelimiter) // Adding _git/ to host host = normalizeGitHostSpec(n[:index+len(gitDelimiter)]) orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0] - path, gitRef = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):]) + path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):]) return } host, n = parseHostSpec(n) @@ -116,35 +125,75 @@ func parseGitUrl(n string) ( index := strings.Index(n, gitSuffix) orgRepo = n[0:index] n = n[index+len(gitSuffix):] - path, gitRef = peelQuery(n) + if n[0] == '/' { + n = n[1:] + } + path, gitRef, gitTimeout, gitSubmodules = peelQuery(n) return } i := strings.Index(n, "/") if i < 1 { - return "", "", "", "", "" + path, gitRef, gitTimeout, gitSubmodules = peelQuery(n) + return } j := strings.Index(n[i+1:], "/") if j >= 0 { j += i + 1 orgRepo = n[:j] - path, gitRef = peelQuery(n[j+1:]) + path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[j+1:]) return } path = "" - orgRepo, gitRef = peelQuery(n) - return host, orgRepo, path, gitRef, gitSuff + orgRepo, gitRef, gitTimeout, gitSubmodules = peelQuery(n) + return host, orgRepo, path, gitRef, gitSubmodules, gitSuff, gitTimeout } -func peelQuery(arg string) (string, string) { +// Clone git submodules by default. +const defaultSubmodules = true - r, _ := regexp.Compile(refQueryRegex) - j := r.FindStringIndex(arg) +// Arbitrary, but non-infinite, timeout for running commands. +const defaultTimeout = 27 * time.Second - if len(j) > 0 { - return arg[:j[0]], arg[j[0]+len(r.FindString(arg)):] +func peelQuery(arg string) (string, string, time.Duration, bool) { + // Parse the given arg into a URL. In the event of a parse failure, return + // our defaults. + parsed, err := url.Parse(arg) + if err != nil { + return arg, "", defaultTimeout, defaultSubmodules } - return arg, "" + values := parsed.Query() + + // ref is the desired git ref to target. Can be specified by in a git URL + // with ?ref= or ?version=, although ref takes precedence. + ref := values.Get("version") + if queryValue := values.Get("ref"); queryValue != "" { + ref = queryValue + } + + // depth is the desired git exec timeout. Can be specified by in a git URL + // with ?timeout=. + duration := defaultTimeout + if queryValue := values.Get("timeout"); queryValue != "" { + // Attempt to first parse as a number of integer seconds (like "61"), + // and then attempt to parse as a suffixed duration (like "61s"). + if intValue, err := strconv.Atoi(queryValue); err == nil && intValue > 0 { + duration = time.Duration(intValue) * time.Second + } else if durationValue, err := time.ParseDuration(queryValue); err == nil && durationValue > 0 { + duration = durationValue + } + } + + // submodules indicates if git submodule cloning is desired. Can be + // specified by in a git URL with ?submodules=. + submodules := defaultSubmodules + if queryValue := values.Get("submodules"); queryValue != "" { + if boolValue, err := strconv.ParseBool(queryValue); err == nil { + submodules = boolValue + } + } + + return parsed.Path, ref, duration, submodules } func parseHostSpec(n string) (string, string) { diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/namebackreferences.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/namebackreferences.go index e458786c4d9..354f70e5144 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/namebackreferences.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/namebackreferences.go @@ -6,8 +6,8 @@ package builtinconfig import ( "strings" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/resid" ) // NameBackReferences is an association between a gvk.GVK (a ReferralTarget) diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtinplugintype_string.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtinplugintype_string.go index 7b775fadb43..e87fe90e4ab 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtinplugintype_string.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtinplugintype_string.go @@ -11,24 +11,26 @@ func _() { _ = x[Unknown-0] _ = x[AnnotationsTransformer-1] _ = x[ConfigMapGenerator-2] - _ = x[HashTransformer-3] - _ = x[ImageTagTransformer-4] - _ = x[LabelTransformer-5] - _ = x[LegacyOrderTransformer-6] - _ = x[NamespaceTransformer-7] - _ = x[PatchJson6902Transformer-8] - _ = x[PatchStrategicMergeTransformer-9] - _ = x[PatchTransformer-10] - _ = x[PrefixSuffixTransformer-11] - _ = x[ReplicaCountTransformer-12] - _ = x[SecretGenerator-13] - _ = x[ValueAddTransformer-14] - _ = x[HelmChartInflationGenerator-15] + _ = x[IAMPolicyGenerator-3] + _ = x[HashTransformer-4] + _ = x[ImageTagTransformer-5] + _ = x[LabelTransformer-6] + _ = x[LegacyOrderTransformer-7] + _ = x[NamespaceTransformer-8] + _ = x[PatchJson6902Transformer-9] + _ = x[PatchStrategicMergeTransformer-10] + _ = x[PatchTransformer-11] + _ = x[PrefixSuffixTransformer-12] + _ = x[ReplicaCountTransformer-13] + _ = x[SecretGenerator-14] + _ = x[ValueAddTransformer-15] + _ = x[HelmChartInflationGenerator-16] + _ = x[ReplacementTransformer-17] } -const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformerHelmChartInflationGenerator" +const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorIAMPolicyGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformerHelmChartInflationGeneratorReplacementTransformer" -var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 97, 119, 139, 163, 193, 209, 232, 255, 270, 289, 316} +var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 65, 80, 99, 115, 137, 157, 181, 211, 227, 250, 273, 288, 307, 334, 356} func (i BuiltinPluginType) String() string { if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) { diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtins.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtins.go index f53583981c7..7d5e8fce13c 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtins.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers/builtins.go @@ -15,6 +15,7 @@ const ( Unknown BuiltinPluginType = iota AnnotationsTransformer ConfigMapGenerator + IAMPolicyGenerator HashTransformer ImageTagTransformer LabelTransformer @@ -28,6 +29,7 @@ const ( SecretGenerator ValueAddTransformer HelmChartInflationGenerator + ReplacementTransformer ) var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType @@ -57,6 +59,7 @@ func GetBuiltinPluginType(n string) BuiltinPluginType { var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{ ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin, + IAMPolicyGenerator: builtins.NewIAMPolicyGeneratorPlugin, SecretGenerator: builtins.NewSecretGeneratorPlugin, HelmChartInflationGenerator: builtins.NewHelmChartInflationGeneratorPlugin, } @@ -72,6 +75,7 @@ var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin PatchStrategicMergeTransformer: builtins.NewPatchStrategicMergeTransformerPlugin, PatchTransformer: builtins.NewPatchTransformerPlugin, PrefixSuffixTransformer: builtins.NewPrefixSuffixTransformerPlugin, + ReplacementTransformer: builtins.NewReplacementTransformerPlugin, ReplicaCountTransformer: builtins.NewReplicaCountTransformerPlugin, ValueAddTransformer: builtins.NewValueAddTransformerPlugin, } diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go index a6f801ebb94..9380558cb86 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go @@ -89,7 +89,10 @@ type argsConfig struct { func (p *ExecPlugin) processOptionalArgsFields() error { var c argsConfig - yaml.Unmarshal(p.cfg, &c) + err := yaml.Unmarshal(p.cfg, &c) + if err != nil { + return err + } if c.ArgsOneLiner != "" { p.args, _ = shlex.Split(c.ArgsOneLiner) } diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go index ddd980d74a1..76be4b07606 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go @@ -78,6 +78,7 @@ func NewFnPlugin(o *types.FnPluginLoadingOptions) *FnPlugin { EnableExec: o.EnableExec, StorageMounts: toStorageMounts(o.Mounts), Env: o.Env, + AsCurrentUser: o.AsCurrentUser, }, } } diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go index aaa7c36004c..7bcce431522 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go @@ -19,21 +19,32 @@ import ( "sigs.k8s.io/kustomize/api/internal/plugins/fnplugin" "sigs.k8s.io/kustomize/api/internal/plugins/utils" "sigs.k8s.io/kustomize/api/konfig" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filesys" + "sigs.k8s.io/kustomize/kyaml/resid" ) // Loader loads plugins using a file loader (a different loader). type Loader struct { pc *types.PluginConfig rf *resmap.Factory + fs filesys.FileSystem + + // absolutePluginHome caches the location of a valid plugin root directory. + // It should only be set once the directory's existence has been confirmed. + absolutePluginHome string } func NewLoader( - pc *types.PluginConfig, rf *resmap.Factory) *Loader { - return &Loader{pc: pc, rf: rf} + pc *types.PluginConfig, rf *resmap.Factory, fs filesys.FileSystem) *Loader { + return &Loader{pc: pc, rf: rf, fs: fs} +} + +// Config provides the global (not plugin specific) PluginConfig data. +func (l *Loader) Config() *types.PluginConfig { + return l.pc } func (l *Loader) LoadGenerators( @@ -95,13 +106,47 @@ func relativePluginPath(id resid.ResId) string { strings.ToLower(id.Kind)) } -func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string { - return filepath.Join( - pc.AbsPluginHome, relativePluginPath(id), id.Kind) +func (l *Loader) AbsolutePluginPath(id resid.ResId) (string, error) { + pluginHome, err := l.absPluginHome() + if err != nil { + return "", err + } + return filepath.Join(pluginHome, relativePluginPath(id), id.Kind), nil } -func (l *Loader) absolutePluginPath(id resid.ResId) string { - return AbsolutePluginPath(l.pc, id) +// absPluginHome is the home of kustomize Exec and Go plugins. +// Kustomize plugin configuration files are k8s-style objects +// containing the fields 'apiVersion' and 'kind', e.g. +// apiVersion: apps/v1 +// kind: Deployment +// kustomize reads plugin configuration data from a file path +// specified in the 'generators:' or 'transformers:' field of a +// kustomization file. For Exec and Go plugins, kustomize +// uses this data to both locate the plugin and configure it. +// Each Exec or Go plugin (its code, its tests, its supporting data +// files, etc.) must be housed in its own directory at +// ${absPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind}) +// where +// - ${absPluginHome} is an absolute path, defined below. +// - ${pluginApiVersion} is taken from the plugin config file. +// - ${pluginKind} is taken from the plugin config file. +func (l *Loader) absPluginHome() (string, error) { + // External plugins are disabled--return the dummy plugin root. + if l.pc.PluginRestrictions != types.PluginRestrictionsNone { + return konfig.NoPluginHomeSentinal, nil + } + // We've already determined plugin home--use the cached value. + if l.absolutePluginHome != "" { + return l.absolutePluginHome, nil + } + + // Check default locations for a valid plugin root, and cache it if found. + dir, err := konfig.DefaultAbsPluginHome(l.fs) + if err != nil { + return "", err + } + l.absolutePluginHome = dir + return l.absolutePluginHome, nil } func isBuiltinPlugin(res *resource.Resource) bool { @@ -148,7 +193,7 @@ func (l *Loader) loadAndConfigurePlugin( if err != nil { return nil, errors.Wrapf(err, "marshalling yaml from res %s", res.OrgId()) } - err = c.Config(resmap.NewPluginHelpers(ldr, v, l.rf), yaml) + err = c.Config(resmap.NewPluginHelpers(ldr, v, l.rf, l.pc), yaml) if err != nil { return nil, errors.Wrapf( err, "plugin %s fails configuration", res.OrgId()) @@ -176,10 +221,13 @@ func (l *Loader) loadPlugin(res *resource.Resource) (resmap.Configurable, error) } func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, error) { + absPluginPath, err := l.AbsolutePluginPath(resId) + if err != nil { + return nil, err + } // First try to load the plugin as an executable. - p := execplugin.NewExecPlugin(l.absolutePluginPath(resId)) - err := p.ErrIfNotExecutable() - if err == nil { + p := execplugin.NewExecPlugin(absPluginPath) + if err = p.ErrIfNotExecutable(); err == nil { return p, nil } if !os.IsNotExist(err) { @@ -193,7 +241,7 @@ func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, err return nil, err } // Failing the above, try loading it as a Go plugin. - c, err := l.loadGoPlugin(resId) + c, err := l.loadGoPlugin(resId, absPluginPath+".so") if err != nil { return nil, err } @@ -208,12 +256,11 @@ func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, err // as a Loader instance variable. So make it a package variable. var registry = make(map[string]resmap.Configurable) -func (l *Loader) loadGoPlugin(id resid.ResId) (resmap.Configurable, error) { +func (l *Loader) loadGoPlugin(id resid.ResId, absPath string) (resmap.Configurable, error) { regId := relativePluginPath(id) if c, ok := registry[regId]; ok { return copyPlugin(c), nil } - absPath := l.absolutePluginPath(id) + ".so" if !utils.FileExists(absPath) { return nil, fmt.Errorf( "expected file with Go object code at: %s", absPath) diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/utils/utils.go b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/utils/utils.go index 12dd6e89f05..d1c2af76611 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/plugins/utils/utils.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/plugins/utils/utils.go @@ -12,11 +12,11 @@ import ( "strconv" "time" - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filesys" "sigs.k8s.io/yaml" ) @@ -34,7 +34,7 @@ func GoBin() string { // has her ${g}/${v}/$lower(${k})/${k}.go files. func DeterminePluginSrcRoot(fSys filesys.FileSystem) (string, error) { return konfig.FirstDirThatExistsElseError( - "source directory", fSys, []konfig.NotedFunc{ + "plugin src root", fSys, []konfig.NotedFunc{ { Note: "relative to unit test", F: func() string { @@ -137,7 +137,9 @@ func GetResMapWithIDAnnotation(rm resmap.ResMap) (resmap.ResMap, error) { } annotations := r.GetAnnotations() annotations[idAnnotation] = string(idString) - r.SetAnnotations(annotations) + if err = r.SetAnnotations(annotations); err != nil { + return nil, err + } } return inputRM, nil } @@ -158,7 +160,10 @@ func UpdateResMapValues(pluginName string, h *resmap.PluginHelpers, output []byt } for _, r := range resources { - removeIDAnnotation(r) // stale--not manipulated by plugin transformers + // stale--not manipulated by plugin transformers + if err = removeIDAnnotation(r); err != nil { + return err + } // Add to the new map, checking for duplicates if err := newMap.Append(r); err != nil { @@ -175,7 +180,7 @@ func UpdateResMapValues(pluginName string, h *resmap.PluginHelpers, output []byt return err } if oldIdx != -1 { - rm.GetByIndex(oldIdx).ResetPrimaryData(r) + rm.GetByIndex(oldIdx).ResetRNode(r) } else { if err := rm.Append(r); err != nil { return err @@ -187,21 +192,20 @@ func UpdateResMapValues(pluginName string, h *resmap.PluginHelpers, output []byt for _, id := range rm.AllIds() { newIdx, _ := newMap.GetIndexOfCurrentId(id) if newIdx == -1 { - rm.Remove(id) + if err = rm.Remove(id); err != nil { + return err + } } } return nil } -func removeIDAnnotation(r *resource.Resource) { +func removeIDAnnotation(r *resource.Resource) error { // remove the annotation set by Kustomize to track the resource annotations := r.GetAnnotations() delete(annotations, idAnnotation) - if len(annotations) == 0 { - annotations = nil - } - r.SetAnnotations(annotations) + return r.SetAnnotations(annotations) } // UpdateResourceOptions updates the generator options for each resource in the @@ -224,10 +228,9 @@ func UpdateResourceOptions(rm resmap.ResMap) (resmap.ResMap, error) { } delete(annotations, HashAnnotation) delete(annotations, BehaviorAnnotation) - if len(annotations) == 0 { - annotations = nil + if err := r.SetAnnotations(annotations); err != nil { + return nil, err } - r.SetAnnotations(annotations) r.SetOptions(types.NewGenArgs( &types.GeneratorArgs{ Behavior: behavior, diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go b/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go index acc3d131631..43d3637dd8b 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go @@ -303,16 +303,18 @@ func (kt *KustTarget) runValidators(ra *accumulator.ResAccumulator) error { if err != nil { return err } - new := ra.ResMap().DeepCopy() - kt.removeValidatedByLabel(new) - if err = orignal.ErrorIfNotEqualSets(new); err != nil { + newMap := ra.ResMap().DeepCopy() + if err = kt.removeValidatedByLabel(newMap); err != nil { + return err + } + if err = orignal.ErrorIfNotEqualSets(newMap); err != nil { return fmt.Errorf("validator shouldn't modify the resource map: %v", err) } } return nil } -func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) { +func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) error { resources := rm.Resources() for _, r := range resources { labels := r.GetLabels() @@ -320,12 +322,11 @@ func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) { continue } delete(labels, konfig.ValidatedByLabelKey) - if len(labels) == 0 { - r.SetLabels(nil) - } else { - r.SetLabels(labels) + if err := r.SetLabels(labels); err != nil { + return err } } + return nil } // accumulateResources fills the given resourceAccumulator @@ -443,7 +444,10 @@ func (kt *KustTarget) configureBuiltinPlugin( err, "builtin %s marshal", bpt) } } - err = p.Config(resmap.NewPluginHelpers(kt.ldr, kt.validator, kt.rFactory), y) + err = p.Config( + resmap.NewPluginHelpers( + kt.ldr, kt.validator, kt.rFactory, kt.pLdr.Config()), + y) if err != nil { return errors.Wrapf( err, "trouble configuring builtin %s with config: `\n%s`", bpt, string(y)) diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go b/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go index 640cc742add..7bb15516e0b 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go @@ -57,6 +57,7 @@ func (kt *KustTarget) configureBuiltinTransformers( builtinhelpers.PatchJson6902Transformer, builtinhelpers.ReplicaCountTransformer, builtinhelpers.ImageTagTransformer, + builtinhelpers.ReplacementTransformer, } { r, err := transformerConfigurators[bpt]( kt, bpt, builtinhelpers.TransformerFactories[bpt], tc) @@ -112,16 +113,22 @@ var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func( return }, - builtinhelpers.HelmChartInflationGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) ( + builtinhelpers.HelmChartInflationGenerator: func( + kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) ( result []resmap.Generator, err error) { var c struct { - types.HelmChartArgs + types.HelmGlobals + types.HelmChart } - for _, args := range kt.kustomization.HelmChartInflationGenerator { - c.HelmChartArgs = args + var globals types.HelmGlobals + if kt.kustomization.HelmGlobals != nil { + globals = *kt.kustomization.HelmGlobals + } + for _, chart := range kt.kustomization.HelmCharts { + c.HelmGlobals = globals + c.HelmChart = chart p := f() - err := kt.configureBuiltinPlugin(p, c, bpt) - if err != nil { + if err = kt.configureBuiltinPlugin(p, c, bpt); err != nil { return nil, err } result = append(result, p) @@ -201,14 +208,16 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( return } var c struct { - Path string `json:"path,omitempty" yaml:"path,omitempty"` - Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` - Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` + Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` + Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } for _, pc := range kt.kustomization.Patches { c.Target = pc.Target c.Patch = pc.Patch c.Path = pc.Path + c.Options = pc.Options p := f() err = kt.configureBuiltinPlugin(p, c, bpt) if err != nil { @@ -221,6 +230,31 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( builtinhelpers.LabelTransformer: func( kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) ( result []resmap.Transformer, err error) { + for _, label := range kt.kustomization.Labels { + var c struct { + Labels map[string]string + FieldSpecs []types.FieldSpec + } + c.Labels = label.Pairs + fss := types.FsSlice(label.FieldSpecs) + // merge the custom fieldSpecs with the default + if label.IncludeSelectors { + fss, err = fss.MergeAll(tc.CommonLabels) + } else { + // only add to metadata by default + fss, err = fss.MergeOne(types.FieldSpec{Path: "metadata/labels", CreateIfNotPresent: true}) + } + if err != nil { + return nil, err + } + c.FieldSpecs = fss + p := f() + err = kt.configureBuiltinPlugin(p, c, bpt) + if err != nil { + return nil, err + } + result = append(result, p) + } var c struct { Labels map[string]string FieldSpecs []types.FieldSpec @@ -290,6 +324,21 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( } return }, + builtinhelpers.ReplacementTransformer: func( + kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) ( + result []resmap.Transformer, err error) { + var c struct { + Replacements []types.ReplacementField + } + c.Replacements = kt.kustomization.Replacements + p := f() + err = kt.configureBuiltinPlugin(p, c, bpt) + if err != nil { + return nil, err + } + result = append(result, p) + return result, nil + }, builtinhelpers.ReplicaCountTransformer: func( kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) ( result []resmap.Transformer, err error) { diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/target/multitransformer.go b/vendor/sigs.k8s.io/kustomize/api/internal/target/multitransformer.go index 1896bdf0474..caf1bd2de49 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/target/multitransformer.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/target/multitransformer.go @@ -4,15 +4,12 @@ package target import ( - "fmt" - "sigs.k8s.io/kustomize/api/resmap" ) // multiTransformer contains a list of transformers. type multiTransformer struct { - transformers []resmap.Transformer - checkConflictEnabled bool + transformers []resmap.Transformer } var _ resmap.Transformer = &multiTransformer{} @@ -20,8 +17,8 @@ var _ resmap.Transformer = &multiTransformer{} // newMultiTransformer constructs a multiTransformer. func newMultiTransformer(t []resmap.Transformer) resmap.Transformer { r := &multiTransformer{ - transformers: make([]resmap.Transformer, len(t)), - checkConflictEnabled: false} + transformers: make([]resmap.Transformer, len(t)), + } copy(r.transformers, t) return r } @@ -29,57 +26,11 @@ func newMultiTransformer(t []resmap.Transformer) resmap.Transformer { // Transform applies the member transformers in order to the resources, // optionally detecting and erroring on commutation conflict. func (o *multiTransformer) Transform(m resmap.ResMap) error { - if o.checkConflictEnabled { - return o.transformWithCheckConflict(m) - } - return o.transform(m) -} - -func (o *multiTransformer) transform(m resmap.ResMap) error { for _, t := range o.transformers { - err := t.Transform(m) - if err != nil { + if err := t.Transform(m); err != nil { return err } - } - for _, r := range m.Resources() { - empty, err := r.IsEmpty() - if err != nil { - return err - } - if empty { - err := m.Remove(r.CurId()) - if err != nil { - return err - } - } + m.DropEmpties() } return nil } - -// Of the len(o.transformers)! possible transformer orderings, compare to a reversed order. -// A spot check to perform when the transformations are supposed to be commutative. -// Fail if there's a difference in the result. -func (o *multiTransformer) transformWithCheckConflict(m resmap.ResMap) error { - mcopy := m.DeepCopy() - err := o.transform(m) - if err != nil { - return err - } - o.reverseTransformers() - err = o.transform(mcopy) - if err != nil { - return err - } - err = m.ErrorIfNotEqualSets(mcopy) - if err != nil { - return fmt.Errorf("found conflict between different patches\n%v", err) - } - return nil -} - -func (o *multiTransformer) reverseTransformers() { - for i, j := 0, len(o.transformers)-1; i < j; i, j = i+1, j-1 { - o.transformers[i], o.transformers[j] = o.transformers[j], o.transformers[i] - } -} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/utils/makeResIds.go b/vendor/sigs.k8s.io/kustomize/api/internal/utils/makeResIds.go new file mode 100644 index 00000000000..3f6b17a3f45 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/internal/utils/makeResIds.go @@ -0,0 +1,79 @@ +package utils + +import ( + "fmt" + "strings" + + "sigs.k8s.io/kustomize/api/konfig" + "sigs.k8s.io/kustomize/kyaml/resid" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +const ( + BuildAnnotationPreviousKinds = konfig.ConfigAnnoDomain + "/previousKinds" + BuildAnnotationPreviousNames = konfig.ConfigAnnoDomain + "/previousNames" + BuildAnnotationPrefixes = konfig.ConfigAnnoDomain + "/prefixes" + BuildAnnotationSuffixes = konfig.ConfigAnnoDomain + "/suffixes" + BuildAnnotationPreviousNamespaces = konfig.ConfigAnnoDomain + "/previousNamespaces" + + // the following are only for patches, to specify whether they can change names + // and kinds of their targets + BuildAnnotationAllowNameChange = konfig.ConfigAnnoDomain + "/allowNameChange" + BuildAnnotationAllowKindChange = konfig.ConfigAnnoDomain + "/allowKindChange" + Allowed = "allowed" +) + +// MakeResIds returns all of an RNode's current and previous Ids +func MakeResIds(n *yaml.RNode) ([]resid.ResId, error) { + var result []resid.ResId + apiVersion := n.Field(yaml.APIVersionField) + var group, version string + if apiVersion != nil { + group, version = resid.ParseGroupVersion(yaml.GetValue(apiVersion.Value)) + } + result = append(result, resid.NewResIdWithNamespace( + resid.Gvk{Group: group, Version: version, Kind: n.GetKind()}, n.GetName(), n.GetNamespace()), + ) + prevIds, err := PrevIds(n) + if err != nil { + return nil, err + } + result = append(result, prevIds...) + return result, nil +} + +// PrevIds returns all of an RNode's previous Ids +func PrevIds(n *yaml.RNode) ([]resid.ResId, error) { + var ids []resid.ResId + // TODO: merge previous names and namespaces into one list of + // pairs on one annotation so there is no chance of error + annotations := n.GetAnnotations() + if _, ok := annotations[BuildAnnotationPreviousNames]; !ok { + return nil, nil + } + names := strings.Split(annotations[BuildAnnotationPreviousNames], ",") + ns := strings.Split(annotations[BuildAnnotationPreviousNamespaces], ",") + kinds := strings.Split(annotations[BuildAnnotationPreviousKinds], ",") + // This should never happen + if len(names) != len(ns) || len(names) != len(kinds) { + return nil, fmt.Errorf( + "number of previous names, " + + "number of previous namespaces, " + + "number of previous kinds not equal") + } + for i := range names { + meta, err := n.GetMeta() + if err != nil { + return nil, err + } + group, version := resid.ParseGroupVersion(meta.APIVersion) + gvk := resid.Gvk{ + Group: group, + Version: version, + Kind: kinds[i], + } + ids = append(ids, resid.NewResIdWithNamespace( + gvk, names[i], ns[i])) + } + return ids, nil +} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/utils/pathsplitter.go b/vendor/sigs.k8s.io/kustomize/api/internal/utils/pathsplitter.go index c8d2f3342ee..aa560299f7d 100644 --- a/vendor/sigs.k8s.io/kustomize/api/internal/utils/pathsplitter.go +++ b/vendor/sigs.k8s.io/kustomize/api/internal/utils/pathsplitter.go @@ -5,18 +5,60 @@ package utils import "strings" -// PathSplitter splits a slash delimited string, permitting escaped slashes. -func PathSplitter(path string) []string { - ps := strings.Split(path, "/") +// TODO: Move these to kyaml + +// PathSplitter splits a delimited string, permitting escaped delimiters. +func PathSplitter(path string, delimiter string) []string { + ps := strings.Split(path, delimiter) var res []string res = append(res, ps[0]) for i := 1; i < len(ps); i++ { last := len(res) - 1 if strings.HasSuffix(res[last], `\`) { - res[last] = strings.TrimSuffix(res[last], `\`) + "/" + ps[i] + res[last] = strings.TrimSuffix(res[last], `\`) + delimiter + ps[i] } else { res = append(res, ps[i]) } } return res } + +// SmarterPathSplitter splits a path, retaining bracketed elements. +// If the element is a list entry identifier (defined by the '='), +// it will retain the brackets. +// E.g. "[name=com.foo.someapp]" survives as one thing after splitting +// "spec.template.spec.containers.[name=com.foo.someapp].image" +// See kyaml/yaml/match.go for use of list entry identifiers. +// If the element is a mapping entry identifier, it will remove the +// brackets. +// E.g. "a.b.c" survives as one thing after splitting +// "metadata.annotations.[a.b.c] +// This function uses `PathSplitter`, so it also respects escaped delimiters. +func SmarterPathSplitter(path string, delimiter string) []string { + var result []string + split := PathSplitter(path, delimiter) + + for i := 0; i < len(split); i++ { + elem := split[i] + if strings.HasPrefix(elem, "[") && !strings.HasSuffix(elem, "]") { + // continue until we find the matching "]" + bracketed := []string{elem} + for i < len(split)-1 { + i++ + bracketed = append(bracketed, split[i]) + if strings.HasSuffix(split[i], "]") { + break + } + } + bracketedStr := strings.Join(bracketed, delimiter) + if strings.Contains(bracketedStr, "=") { + result = append(result, bracketedStr) + } else { + result = append(result, strings.Trim(bracketedStr, "[]")) + } + } else { + result = append(result, elem) + } + } + return result +} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/utils/stringslice.go b/vendor/sigs.k8s.io/kustomize/api/internal/utils/stringslice.go new file mode 100644 index 00000000000..3dc4227255f --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/internal/utils/stringslice.go @@ -0,0 +1,44 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package utils + +// StringSliceIndex returns the index of the str, else -1. +func StringSliceIndex(slice []string, str string) int { + for i := range slice { + if slice[i] == str { + return i + } + } + return -1 +} + +// StringSliceContains returns true if the slice has the string. +func StringSliceContains(slice []string, str string) bool { + for _, s := range slice { + if s == str { + return true + } + } + return false +} + +// SameEndingSubSlice returns true if the slices end the same way, e.g. +// {"a", "b", "c"}, {"b", "c"} => true +// {"a", "b", "c"}, {"a", "b"} => false +// If one slice is empty and the other is not, return false. +func SameEndingSubSlice(shortest, longest []string) bool { + if len(shortest) > len(longest) { + longest, shortest = shortest, longest + } + diff := len(longest) - len(shortest) + if len(shortest) == 0 { + return diff == 0 + } + for i := len(shortest) - 1; i >= 0; i-- { + if longest[i+diff] != shortest[i] { + return false + } + } + return true +} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/wrappy/factory.go b/vendor/sigs.k8s.io/kustomize/api/internal/wrappy/factory.go deleted file mode 100644 index b155ed3c66f..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/internal/wrappy/factory.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2020 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package wrappy - -import ( - "fmt" - - "sigs.k8s.io/kustomize/api/hasher" - "sigs.k8s.io/kustomize/api/ifc" - "sigs.k8s.io/kustomize/api/internal/generators" - "sigs.k8s.io/kustomize/api/konfig" - "sigs.k8s.io/kustomize/api/types" - "sigs.k8s.io/kustomize/kyaml/filtersutil" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// WNodeFactory makes instances of WNode. -// -// These instances in turn adapt -// sigs.k8s.io/kustomize/kyaml/yaml.RNode -// to implement ifc.Unstructured. -// This factory is meant to implement ifc.KunstructuredFactory. -// -// This implementation should be thin, as both WNode and WNodeFactory must be -// factored away (deleted) along with ifc.Kunstructured in favor of direct use -// of RNode methods upon completion of -// https://github.com/kubernetes-sigs/kustomize/issues/2506. -// -// See also api/krusty/internal/provider/depprovider.go -type WNodeFactory struct { -} - -var _ ifc.KunstructuredFactory = (*WNodeFactory)(nil) - -func (k *WNodeFactory) SliceFromBytes(bs []byte) ([]ifc.Kunstructured, error) { - yamlRNodes, err := kio.FromBytes(bs) - if err != nil { - return nil, err - } - var result []ifc.Kunstructured - for i := range yamlRNodes { - rn := yamlRNodes[i] - meta, err := rn.GetValidatedMetadata() - if err != nil { - return nil, err - } - if !shouldDropObject(meta) { - if foundNil, path := rn.HasNilEntryInList(); foundNil { - return nil, fmt.Errorf("empty item at %v in object %v", path, rn) - } - result = append(result, FromRNode(rn)) - } - } - return result, nil -} - -// shouldDropObject returns true if the resource should not be accumulated. -func shouldDropObject(m yaml.ResourceMeta) bool { - _, y := m.ObjectMeta.Annotations[konfig.IgnoredByKustomizeAnnotation] - return y -} - -func (k *WNodeFactory) FromMap(m map[string]interface{}) ifc.Kunstructured { - rn, err := FromMap(m) - if err != nil { - // TODO(#WNodeFactory): handle or bubble error" - panic(err) - } - return rn -} - -// kustHash computes a hash of an unstructured object. -type kustHash struct{} - -// Hash returns a hash of the given object -func (h *kustHash) Hash(m ifc.Kunstructured) (string, error) { - node, err := filtersutil.GetRNode(m) - if err != nil { - return "", err - } - return hasher.HashRNode(node) -} - -func (k *WNodeFactory) Hasher() ifc.KunstructuredHasher { - return &kustHash{} -} - -// MakeConfigMap makes a wrapped configmap. -func (k *WNodeFactory) MakeConfigMap( - ldr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) { - rn, err := generators.MakeConfigMap(ldr, args) - if err != nil { - return nil, err - } - return FromRNode(rn), nil -} - -// MakeSecret makes a wrapped secret. -func (k *WNodeFactory) MakeSecret( - ldr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) { - rn, err := generators.MakeSecret(ldr, args) - if err != nil { - return nil, err - } - return FromRNode(rn), nil -} diff --git a/vendor/sigs.k8s.io/kustomize/api/internal/wrappy/wnode.go b/vendor/sigs.k8s.io/kustomize/api/internal/wrappy/wnode.go deleted file mode 100644 index 81a35d1745f..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/internal/wrappy/wnode.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2020 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package wrappy - -import ( - "fmt" - "log" - "regexp" - "strconv" - "strings" - - "sigs.k8s.io/kustomize/api/ifc" - "sigs.k8s.io/kustomize/api/resid" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// WNode implements ifc.Kunstructured using yaml.RNode. -// -// It exists only to help manage a switch from -// kunstruct.UnstructAdapter to yaml.RNode as the core -// representation of KRM objects in kustomize. -// -// It's got a silly name because we don't want it around for long, -// and want its use to be obvious. -type WNode struct { - node *yaml.RNode -} - -var _ ifc.Kunstructured = (*WNode)(nil) - -func NewWNode() *WNode { - return FromRNode(yaml.NewRNode(nil)) -} - -func FromMap(m map[string]interface{}) (*WNode, error) { - n, err := yaml.FromMap(m) - if err != nil { - return nil, err - } - return FromRNode(n), nil -} - -func FromRNode(node *yaml.RNode) *WNode { - return &WNode{node: node} -} - -func (wn *WNode) AsRNode() *yaml.RNode { - return wn.node -} - -func (wn *WNode) demandMetaData(label string) yaml.ResourceMeta { - meta, err := wn.node.GetMeta() - if err != nil { - // Log and die since interface doesn't allow error. - log.Fatalf("for %s', expected valid resource: %v", label, err) - } - return meta -} - -// Copy implements ifc.Kunstructured. -func (wn *WNode) Copy() ifc.Kunstructured { - return &WNode{node: wn.node.Copy()} -} - -// GetAnnotations implements ifc.Kunstructured. -func (wn *WNode) GetAnnotations() map[string]string { - return wn.demandMetaData("GetAnnotations").Annotations -} - -// convertSliceIndex traverses the items in `fields` and find -// if there is a slice index in the item and change it to a -// valid Lookup field path. For example, 'ports[0]' will be -// converted to 'ports' and '0'. -func convertSliceIndex(fields []string) []string { - var res []string - for _, s := range fields { - if !strings.HasSuffix(s, "]") { - res = append(res, s) - continue - } - re := regexp.MustCompile(`^(.*)\[(\d+)\]$`) - groups := re.FindStringSubmatch(s) - if len(groups) == 0 { - // no match, add to result - res = append(res, s) - continue - } - if groups[1] != "" { - res = append(res, groups[1]) - } - res = append(res, groups[2]) - } - return res -} - -// GetFieldValue implements ifc.Kunstructured. -func (wn *WNode) GetFieldValue(path string) (interface{}, error) { - fields := convertSliceIndex(strings.Split(path, ".")) - rn, err := wn.node.Pipe(yaml.Lookup(fields...)) - if err != nil { - return nil, err - } - if rn == nil { - return nil, NoFieldError{path} - } - yn := rn.YNode() - - // If this is an alias node, resolve it - if yn.Kind == yaml.AliasNode { - yn = yn.Alias - } - - // Return value as map for DocumentNode and MappingNode kinds - if yn.Kind == yaml.DocumentNode || yn.Kind == yaml.MappingNode { - var result map[string]interface{} - if err := yn.Decode(&result); err != nil { - return nil, err - } - return result, err - } - - // Return value as slice for SequenceNode kind - if yn.Kind == yaml.SequenceNode { - var result []interface{} - if err := yn.Decode(&result); err != nil { - return nil, err - } - return result, nil - } - if yn.Kind != yaml.ScalarNode { - return nil, fmt.Errorf("expected ScalarNode, got Kind=%d", yn.Kind) - } - - // TODO: When doing kustomize var replacement, which is likely a - // a primary use of this function and the reason it returns interface{} - // rather than string, we do conversion from Nodes to Go types and back - // to nodes. We should figure out how to do replacement using raw nodes, - // assuming we keep the var feature in kustomize. - // The other end of this is: refvar.go:updateNodeValue. - switch yn.Tag { - case yaml.NodeTagString: - return yn.Value, nil - case yaml.NodeTagInt: - return strconv.Atoi(yn.Value) - case yaml.NodeTagFloat: - return strconv.ParseFloat(yn.Value, 64) - case yaml.NodeTagBool: - return strconv.ParseBool(yn.Value) - default: - // Possibly this should be an error or log. - return yn.Value, nil - } -} - -// GetGvk implements ifc.Kunstructured. -func (wn *WNode) GetGvk() resid.Gvk { - meta := wn.demandMetaData("GetGvk") - g, v := resid.ParseGroupVersion(meta.APIVersion) - return resid.Gvk{Group: g, Version: v, Kind: meta.Kind} -} - -// GetDataMap implements ifc.Kunstructured. -func (wn *WNode) GetDataMap() map[string]string { - return wn.node.GetDataMap() -} - -// SetDataMap implements ifc.Kunstructured. -func (wn *WNode) SetDataMap(m map[string]string) { - wn.node.SetDataMap(m) -} - -// GetBinaryDataMap implements ifc.Kunstructured. -func (wn *WNode) GetBinaryDataMap() map[string]string { - return wn.node.GetBinaryDataMap() -} - -// SetBinaryDataMap implements ifc.Kunstructured. -func (wn *WNode) SetBinaryDataMap(m map[string]string) { - wn.node.SetBinaryDataMap(m) -} - -// GetKind implements ifc.Kunstructured. -func (wn *WNode) GetKind() string { - return wn.demandMetaData("GetKind").Kind -} - -// GetLabels implements ifc.Kunstructured. -func (wn *WNode) GetLabels() map[string]string { - return wn.demandMetaData("GetLabels").Labels -} - -// GetName implements ifc.Kunstructured. -func (wn *WNode) GetName() string { - return wn.demandMetaData("GetName").Name -} - -// GetSlice implements ifc.Kunstructured. -func (wn *WNode) GetSlice(path string) ([]interface{}, error) { - value, err := wn.GetFieldValue(path) - if err != nil { - return nil, err - } - if sliceValue, ok := value.([]interface{}); ok { - return sliceValue, nil - } - return nil, fmt.Errorf("node %s is not a slice", path) -} - -// GetSlice implements ifc.Kunstructured. -func (wn *WNode) GetString(path string) (string, error) { - value, err := wn.GetFieldValue(path) - if err != nil { - return "", err - } - if v, ok := value.(string); ok { - return v, nil - } - return "", fmt.Errorf("node %s is not a string: %v", path, value) -} - -// Map implements ifc.Kunstructured. -func (wn *WNode) Map() (map[string]interface{}, error) { - return wn.node.Map() -} - -// MarshalJSON implements ifc.Kunstructured. -func (wn *WNode) MarshalJSON() ([]byte, error) { - return wn.node.MarshalJSON() -} - -// MatchesAnnotationSelector implements ifc.Kunstructured. -func (wn *WNode) MatchesAnnotationSelector(selector string) (bool, error) { - return wn.node.MatchesAnnotationSelector(selector) -} - -// MatchesLabelSelector implements ifc.Kunstructured. -func (wn *WNode) MatchesLabelSelector(selector string) (bool, error) { - return wn.node.MatchesLabelSelector(selector) -} - -// SetAnnotations implements ifc.Kunstructured. -func (wn *WNode) SetAnnotations(annotations map[string]string) { - if err := wn.node.SetAnnotations(annotations); err != nil { - log.Fatal(err) // interface doesn't allow error. - } -} - -// SetGvk implements ifc.Kunstructured. -func (wn *WNode) SetGvk(gvk resid.Gvk) { - wn.setMapField(yaml.NewScalarRNode(gvk.Kind), yaml.KindField) - wn.setMapField(yaml.NewScalarRNode(gvk.ApiVersion()), yaml.APIVersionField) -} - -// SetLabels implements ifc.Kunstructured. -func (wn *WNode) SetLabels(labels map[string]string) { - if err := wn.node.SetLabels(labels); err != nil { - log.Fatal(err) // interface doesn't allow error. - } -} - -// SetName implements ifc.Kunstructured. -func (wn *WNode) SetName(name string) { - wn.setMapField(yaml.NewScalarRNode(name), yaml.MetadataField, yaml.NameField) -} - -// SetNamespace implements ifc.Kunstructured. -func (wn *WNode) SetNamespace(ns string) { - if err := wn.node.SetNamespace(ns); err != nil { - log.Fatal(err) // interface doesn't allow error. - } -} - -func (wn *WNode) setMapField(value *yaml.RNode, path ...string) { - if err := wn.node.SetMapField(value, path...); err != nil { - // Log and die since interface doesn't allow error. - log.Fatalf("failed to set field %v: %v", path, err) - } -} - -// UnmarshalJSON implements ifc.Kunstructured. -func (wn *WNode) UnmarshalJSON(data []byte) error { - return wn.node.UnmarshalJSON(data) -} - -type NoFieldError struct { - Field string -} - -func (e NoFieldError) Error() string { - return fmt.Sprintf("no field named '%s'", e.Field) -} diff --git a/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namereference.go b/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namereference.go index a9af15706eb..26a344f4d07 100644 --- a/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namereference.go +++ b/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namereference.go @@ -3,9 +3,6 @@ package builtinpluginconsts -// TODO: rename 'fieldSpecs' to 'referrers' for clarity. -// This will, however, break anyone using a custom config. - const ( nameReferenceFieldSpecs = ` nameReference: diff --git a/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namespace.go b/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namespace.go index 2a922b25a82..a35ef9c6f7d 100644 --- a/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namespace.go +++ b/vendor/sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts/namespace.go @@ -19,5 +19,8 @@ namespace: group: apiregistration.k8s.io kind: APIService create: true +- path: spec/conversion/webhook/clientConfig/service/namespace + group: apiextensions.k8s.io + kind: CustomResourceDefinition ` ) diff --git a/vendor/sigs.k8s.io/kustomize/api/konfig/doc.go b/vendor/sigs.k8s.io/kustomize/api/konfig/doc.go index 44f659afba6..8c5f8f2cdf9 100644 --- a/vendor/sigs.k8s.io/kustomize/api/konfig/doc.go +++ b/vendor/sigs.k8s.io/kustomize/api/konfig/doc.go @@ -2,5 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 // Package konfig provides configuration methods and constants -// for the kustomize API. +// for the kustomize API, e.g. the set of file names to look for +// to identify a kustomization root. package konfig diff --git a/vendor/sigs.k8s.io/kustomize/api/konfig/general.go b/vendor/sigs.k8s.io/kustomize/api/konfig/general.go index 40167bae09b..6c86391df97 100644 --- a/vendor/sigs.k8s.io/kustomize/api/konfig/general.go +++ b/vendor/sigs.k8s.io/kustomize/api/konfig/general.go @@ -19,31 +19,7 @@ func DefaultKustomizationFileName() string { return RecognizedKustomizationFileNames()[0] } -// IfApiMachineryElseKyaml returns true if executing the apimachinery code -// path, else we're executing the kyaml code paths. -func IfApiMachineryElseKyaml(s1, s2 string) string { - if !FlagEnableKyamlDefaultValue { - return s1 - } - return s2 -} - const ( - // FlagEnableKyamlDefaultValue is the default value for the --enable_kyaml - // flag. This value is also used in unit tests. See provider.DepProvider. - // - // TODO(#3588): Delete this constant. - // - // All tests should pass for either true or false values - // of this constant, without having to check its value. - // In the cases where there's a different outcome, either decide - // that the difference is acceptable, or make the difference go away. - // - // Historically, tests passed for enable_kyaml == false, i.e. using - // apimachinery libs. This doesn't mean the code was better, it just - // means regression tests preserved those outcomes. - FlagEnableKyamlDefaultValue = true - // An environment variable to consult for kustomization // configuration data. See: // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html diff --git a/vendor/sigs.k8s.io/kustomize/api/konfig/plugins.go b/vendor/sigs.k8s.io/kustomize/api/konfig/plugins.go index a42e5e296af..30bd3b6e386 100644 --- a/vendor/sigs.k8s.io/kustomize/api/konfig/plugins.go +++ b/vendor/sigs.k8s.io/kustomize/api/konfig/plugins.go @@ -8,8 +8,8 @@ import ( "path/filepath" "runtime" - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filesys" ) const ( @@ -41,32 +41,6 @@ const ( NoPluginHomeSentinal = "/No/non-builtin/plugins!" ) -func EnabledPluginConfig(b types.BuiltinPluginLoadingOptions) (*types.PluginConfig, error) { - dir, err := DefaultAbsPluginHome(filesys.MakeFsOnDisk()) - if err != nil { - return nil, err - } - return MakePluginConfig(types.PluginRestrictionsNone, b, dir), nil -} - -func DisabledPluginConfig() *types.PluginConfig { - return MakePluginConfig( - types.PluginRestrictionsBuiltinsOnly, - types.BploUseStaticallyLinked, - NoPluginHomeSentinal) -} - -func MakePluginConfig( - pr types.PluginRestrictions, - b types.BuiltinPluginLoadingOptions, - home string) *types.PluginConfig { - return &types.PluginConfig{ - PluginRestrictions: pr, - AbsPluginHome: home, - BpLoadingOptions: b, - } -} - type NotedFunc struct { Note string F func() string @@ -77,7 +51,7 @@ type NotedFunc struct { // the home of kustomize plugins. func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) { return FirstDirThatExistsElseError( - "plugin home directory", fSys, []NotedFunc{ + "plugin root", fSys, []NotedFunc{ { Note: "homed in $" + KustomizePluginHomeEnv, F: func() string { @@ -87,9 +61,11 @@ func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) { { Note: "homed in $" + XdgConfigHomeEnv, F: func() string { - return filepath.Join( - os.Getenv(XdgConfigHomeEnv), - ProgramName, RelPluginHome) + if root := os.Getenv(XdgConfigHomeEnv); root != "" { + return filepath.Join(root, ProgramName, RelPluginHome) + } + // do not look in "kustomize/plugin" if XdgConfigHomeEnv is unset + return "" }, }, { @@ -118,11 +94,14 @@ func FirstDirThatExistsElseError( pathFuncs []NotedFunc) (string, error) { var nope []types.Pair for _, dt := range pathFuncs { - dir := dt.F() - if fSys.Exists(dir) { - return dir, nil + if dir := dt.F(); dir != "" { + if fSys.Exists(dir) { + return dir, nil + } + nope = append(nope, types.Pair{Key: dt.Note, Value: dir}) + } else { + nope = append(nope, types.Pair{Key: dt.Note, Value: ""}) } - nope = append(nope, types.Pair{Key: dt.Note, Value: dir}) } return "", types.NewErrUnableToFind(what, nope) } diff --git a/vendor/sigs.k8s.io/kustomize/api/krusty/kustomizer.go b/vendor/sigs.k8s.io/kustomize/api/krusty/kustomizer.go index 8120f9351f6..b06a8221ccd 100644 --- a/vendor/sigs.k8s.io/kustomize/api/krusty/kustomizer.go +++ b/vendor/sigs.k8s.io/kustomize/api/krusty/kustomizer.go @@ -8,7 +8,6 @@ import ( "path/filepath" "sigs.k8s.io/kustomize/api/builtins" - "sigs.k8s.io/kustomize/api/filesys" pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader" "sigs.k8s.io/kustomize/api/internal/target" "sigs.k8s.io/kustomize/api/konfig" @@ -17,6 +16,7 @@ import ( "sigs.k8s.io/kustomize/api/provider" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filesys" "sigs.k8s.io/kustomize/kyaml/openapi" ) @@ -36,7 +36,7 @@ type Kustomizer struct { func MakeKustomizer(o *Options) *Kustomizer { return &Kustomizer{ options: o, - depProvider: provider.NewDepProvider(o.UseKyaml), + depProvider: provider.NewDepProvider(), } } @@ -52,9 +52,7 @@ func MakeKustomizer(o *Options) *Kustomizer { // and Run can be called on each of them). func (b *Kustomizer) Run( fSys filesys.FileSystem, path string) (resmap.ResMap, error) { - resmapFactory := resmap.NewFactory( - b.depProvider.GetResourceFactory(), - b.depProvider.GetConflictDetectorFactory()) + resmapFactory := resmap.NewFactory(b.depProvider.GetResourceFactory()) lr := fLdr.RestrictionNone if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly { lr = fLdr.RestrictionRootOnly @@ -68,7 +66,8 @@ func (b *Kustomizer) Run( ldr, b.depProvider.GetFieldValidator(), resmapFactory, - pLdr.NewLoader(b.options.PluginConfig, resmapFactory), + // The plugin configs are always located on disk, regardless of the fSys passed in + pLdr.NewLoader(b.options.PluginConfig, resmapFactory, filesys.MakeFsOnDisk()), ) err = kt.Load() if err != nil { @@ -91,19 +90,25 @@ func (b *Kustomizer) Run( return nil, err } if b.options.DoLegacyResourceSort { - builtins.NewLegacyOrderTransformerPlugin().Transform(m) + err = builtins.NewLegacyOrderTransformerPlugin().Transform(m) + if err != nil { + return nil, err + } } if b.options.AddManagedbyLabel { t := builtins.LabelTransformerPlugin{ Labels: map[string]string{ - konfig.ManagedbyLabelKey: fmt.Sprintf( - "kustomize-%s", provenance.GetProvenance().Semver())}, + konfig.ManagedbyLabelKey: fmt.Sprintf("kustomize-%s", provenance.GetProvenance().Semver()), + }, FieldSpecs: []types.FieldSpec{{ Path: "metadata/labels", CreateIfNotPresent: true, }}, } - t.Transform(m) + err = t.Transform(m) + if err != nil { + return nil, err + } } m.RemoveBuildAnnotations() return m, nil diff --git a/vendor/sigs.k8s.io/kustomize/api/krusty/options.go b/vendor/sigs.k8s.io/kustomize/api/krusty/options.go index 91d7fac053f..438f6c10290 100644 --- a/vendor/sigs.k8s.io/kustomize/api/krusty/options.go +++ b/vendor/sigs.k8s.io/kustomize/api/krusty/options.go @@ -5,7 +5,6 @@ package krusty import ( "sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers" - "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/types" ) @@ -33,35 +32,17 @@ type Options struct { // Options related to kustomize plugins. PluginConfig *types.PluginConfig - - // TODO(#3588): Delete this field (it's always true). - // When true, use kyaml/ packages to manipulate KRM yaml. - // When false, use k8sdeps/ instead (uses k8s.io/api* packages). - UseKyaml bool - - // When true, allow name and kind changing via a patch - // When false, patch name/kind don't overwrite target name/kind - AllowResourceIdChanges bool } // MakeDefaultOptions returns a default instance of Options. func MakeDefaultOptions() *Options { return &Options{ - DoLegacyResourceSort: false, - AddManagedbyLabel: false, - LoadRestrictions: types.LoadRestrictionsRootOnly, - DoPrune: false, - PluginConfig: konfig.DisabledPluginConfig(), - UseKyaml: konfig.FlagEnableKyamlDefaultValue, - AllowResourceIdChanges: false, - } -} - -func (o Options) IfApiMachineryElseKyaml(s1, s2 string) string { - if !o.UseKyaml { - return s1 + DoLegacyResourceSort: false, + AddManagedbyLabel: false, + LoadRestrictions: types.LoadRestrictionsRootOnly, + DoPrune: false, + PluginConfig: types.DisabledPluginConfig(), } - return s2 } // GetBuiltinPluginNames returns a list of builtin plugin names diff --git a/vendor/sigs.k8s.io/kustomize/api/loader/fileloader.go b/vendor/sigs.k8s.io/kustomize/api/loader/fileloader.go index 9e8412de4c7..92bfc3f6998 100644 --- a/vendor/sigs.k8s.io/kustomize/api/loader/fileloader.go +++ b/vendor/sigs.k8s.io/kustomize/api/loader/fileloader.go @@ -12,9 +12,9 @@ import ( "path/filepath" "strings" - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/git" + "sigs.k8s.io/kustomize/kyaml/filesys" ) // fileLoader is a kustomization's interface to files. @@ -319,7 +319,6 @@ func (fl *fileLoader) Load(path string) ([]byte, error) { } return body, nil } - if !filepath.IsAbs(path) { path = fl.root.Join(path) } diff --git a/vendor/sigs.k8s.io/kustomize/api/loader/loader.go b/vendor/sigs.k8s.io/kustomize/api/loader/loader.go index c72a9596541..7a2b75f20ae 100644 --- a/vendor/sigs.k8s.io/kustomize/api/loader/loader.go +++ b/vendor/sigs.k8s.io/kustomize/api/loader/loader.go @@ -5,9 +5,9 @@ package loader import ( - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/git" + "sigs.k8s.io/kustomize/kyaml/filesys" ) // NewLoader returns a Loader pointed at the given target. diff --git a/vendor/sigs.k8s.io/kustomize/api/loader/loadrestrictions.go b/vendor/sigs.k8s.io/kustomize/api/loader/loadrestrictions.go index 99b5562fbf9..a016a962544 100644 --- a/vendor/sigs.k8s.io/kustomize/api/loader/loadrestrictions.go +++ b/vendor/sigs.k8s.io/kustomize/api/loader/loadrestrictions.go @@ -6,7 +6,7 @@ package loader import ( "fmt" - "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/kyaml/filesys" ) type LoadRestrictorFunc func( diff --git a/vendor/sigs.k8s.io/kustomize/api/provider/depprovider.go b/vendor/sigs.k8s.io/kustomize/api/provider/depprovider.go index 4bd567f3ee1..0102c89ce01 100644 --- a/vendor/sigs.k8s.io/kustomize/api/provider/depprovider.go +++ b/vendor/sigs.k8s.io/kustomize/api/provider/depprovider.go @@ -4,198 +4,39 @@ package provider import ( - "log" - + "sigs.k8s.io/kustomize/api/hasher" "sigs.k8s.io/kustomize/api/ifc" - "sigs.k8s.io/kustomize/api/internal/conflict" "sigs.k8s.io/kustomize/api/internal/validate" - "sigs.k8s.io/kustomize/api/internal/wrappy" - "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/resource" ) -// DepProvider is a dependency provider. -// -// The instances it returns are either -// - old implementations backed by k8sdeps code, -// - new implementations backed by kyaml code. -// -// History: -// -// kubectl depends on k8s.io code, and at the time of writing, so -// does kustomize. Code that imports k8s.io/api* cannot be imported -// back into k8s.io/*, yet kustomize appears inside k8s.io/kubectl. -// -// To allow kustomize to appear inside kubectl, yet still be developed -// outside kubectl, the kustomize code was divided into the following -// packages -// -// api/ -// k8sdeps/ (and internal/ks8deps/) -// ifc/ -// krusty/ -// everythingElse/ -// -// with the following rules: -// -// - Only k8sdeps/ may import k8s.io/api*. -// -// - Only krusty/ (and its internals) may import k8sdeps/. -// I.e., ifc/ and everythingElse/ must not -// import k8sdeps/ or k8s.io/api*. -// -// - Code in krusty/ may use code in k8sdeps/ to create -// objects then inject said objects into -// everythingElse/ behind dependency neutral interfaces. -// -// The idea was to periodically copy, not import, the large k8sdeps/ -// tree (plus a snippet from krusty/kustomizer.go) into the kubectl -// codebase via a large PR, and have kubectl depend on the rest via -// normal importing. -// -// Over 2019, however, kubectl underwent large changes including -// a switch to Go modules, and a concerted attempt to extract kubectl -// from the k8s repo. This made large kustomize integration PRs too -// intrusive to review. -// -// In 2020, kubectl is based on Go modules, and almost entirely -// extracted from the k8s.io repositories, and further the kyaml -// library has a appeared as a viable replacement to k8s.io/api* -// KRM manipulation code. -// -// The new plan is to eliminate k8sdeps/ entirely, along with its -// k8s.io/api* dependence, allowing kustomize code to be imported -// into kubectl via normal Go module imports. Then the kustomize API -// code can then move into the github.com/kubernetes-sigs/cli-utils -// repo. The kustomize CLI in github.com/kubernetes-sigs/kustomize -// and the kubectl CLI can then both depend on the kustomize API. -// -// So, all code that depends on k8sdeps must go behind interfaces, -// and kustomize must be factored to choose the implementation. -// -// That problem has been reduced to three interfaces, each having -// two implementations. (1) is k8sdeps-based, (2) is kyaml-based. -// -// - ifc.Kunstructured -// -// 1) api/k8sdeps/kunstruct.UnstructAdapter -// -// This adapts structs in -// k8s.io/apimachinery/pkg/apis/meta/v1/unstructured -// to ifc.Kunstructured. -// -// 2) api/wrappy.WNode -// -// This adapts sigs.k8s.io/kustomize/kyaml/yaml.RNode -// to ifc.Unstructured. -// -// At time of writing, implementation started. -// Further reducing the size of ifc.Kunstructed -// would really reduce the work -// (e.g. drop Vars, drop ReplacementTranformer). -// -// - resource.ConflictDetector -// -// 1) api/internal/k8sdeps/conflict.conflictDetectorJson -// api/internal/k8sdeps/conflict.conflictDetectorSm -// -// Uses k8s.io/apimachinery/pkg/util/strategicpatch, -// apimachinery/pkg/util/mergepatch, etc. to merge -// resource.Resource instances. -// -// 2) api/internal/conflict.smPatchMergeOnlyDetector -// -// At time of writing, this doesn't report conflicts, -// but it does know how to merge patches. Conflict -// reporting isn't vital to kustomize function. It's -// rare that a person would configure one transformer -// with many patches, much less so many that it became -// hard to spot conflicts. In the case of an undetected -// conflict, the last patch applied wins, likely what -// the user wants anyway. Regardless, the effect of this -// is plainly visible and usable in the output, even if -// a conflict happened but wasn't reported as an error. -// -// - ifc.Validator -// -// 1) api/k8sdeps/validator.KustValidator -// -// Uses k8s.io/apimachinery/pkg/api/validation and -// friends to validate strings. -// -// 2) api/internal/validate.FieldValidator -// -// See TODO inside the validator for status. -// At time of writing, this is a do-nothing -// validator as it's not critical to kustomize function. -// -// Proposed plan: -// [x] Ship kustomize with the ability to switch from 1 to 2 via -// an --enable_kyaml flag. -// [x] Make --enable_kyaml true by default. -// [x] When 2 is not noticeably more buggy than 1, delete 1. -// I.e. delete k8sdeps/, transitively deleting all k8s.io/api* deps. -// This DepProvider should be left in place to retain these -// comments, but it will have only one choice. -// [x] The way is now clear to reintegrate into kubectl. -// This should be done ASAP; the last step is cleanup. -// [ ] Cleanup. With only one impl of Kunstructure remaining, -// that interface and WNode can be deleted, along with this -// DepProvider. The other two interfaces could be dropped too. -// -// When the above is done, kustomize will use yaml.RNode and/or -// KRM Config Functions directly and exclusively. -// If you're reading this, plan not done. -// +// DepProvider is a dependency provider, injecting different +// implementations depending on the context. type DepProvider struct { - kFactory ifc.KunstructuredFactory - resourceFactory *resource.Factory - conflictDectectorFactory resource.ConflictDetectorFactory - fieldValidator ifc.Validator -} - -// The dependencies this method needs have been deleted - -// see comments above. This method will be deleted -// along with DepProvider in the final step. -func makeK8sdepBasedInstances() *DepProvider { - log.Fatal("This binary cannot use k8s.io code; it must use kyaml.") - return nil + resourceFactory *resource.Factory + // implemented by api/internal/validate.FieldValidator + // See TODO inside the validator for status. + // At time of writing, this is a do-nothing + // validator as it's not critical to kustomize function. + fieldValidator ifc.Validator } -func makeKyamlBasedInstances() *DepProvider { - kf := &wrappy.WNodeFactory{} - rf := resource.NewFactory(kf) +func NewDepProvider() *DepProvider { + rf := resource.NewFactory(&hasher.Hasher{}) return &DepProvider{ - kFactory: kf, - resourceFactory: rf, - conflictDectectorFactory: conflict.NewFactory(), - fieldValidator: validate.NewFieldValidator(), - } -} - -func NewDepProvider(useKyaml bool) *DepProvider { - if useKyaml { - return makeKyamlBasedInstances() + resourceFactory: rf, + fieldValidator: validate.NewFieldValidator(), } - return makeK8sdepBasedInstances() } func NewDefaultDepProvider() *DepProvider { - return NewDepProvider(konfig.FlagEnableKyamlDefaultValue) -} - -func (dp *DepProvider) GetKunstructuredFactory() ifc.KunstructuredFactory { - return dp.kFactory + return NewDepProvider() } func (dp *DepProvider) GetResourceFactory() *resource.Factory { return dp.resourceFactory } -func (dp *DepProvider) GetConflictDetectorFactory() resource.ConflictDetectorFactory { - return dp.conflictDectectorFactory -} - func (dp *DepProvider) GetFieldValidator() ifc.Validator { return dp.fieldValidator } diff --git a/vendor/sigs.k8s.io/kustomize/api/resmap/factory.go b/vendor/sigs.k8s.io/kustomize/api/resmap/factory.go index a93b0ad6c62..9ec0fe39678 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resmap/factory.go +++ b/vendor/sigs.k8s.io/kustomize/api/resmap/factory.go @@ -16,14 +16,11 @@ import ( type Factory struct { // Makes resources. resF *resource.Factory - // Makes ConflictDetectors. - cdf resource.ConflictDetectorFactory } // NewFactory returns a new resmap.Factory. -func NewFactory( - rf *resource.Factory, cdf resource.ConflictDetectorFactory) *Factory { - return &Factory{resF: rf, cdf: cdf} +func NewFactory(rf *resource.Factory) *Factory { + return &Factory{resF: rf} } // RF returns a resource.Factory. @@ -126,13 +123,6 @@ func (rmF *Factory) FromSecretArgs( return rmF.FromResource(res), nil } -// ConflatePatches creates a new ResMap containing a merger of the -// incoming patches. -// Error if conflict found. -func (rmF *Factory) ConflatePatches(patches []*resource.Resource) (ResMap, error) { - return (&merginator{cdf: rmF.cdf}).ConflatePatches(patches) -} - func newResMapFromResourceSlice( resources []*resource.Resource) (ResMap, error) { result := New() @@ -146,18 +136,10 @@ func newResMapFromResourceSlice( } // NewResMapFromRNodeSlice returns a ResMap from a slice of RNodes -func (rmF *Factory) NewResMapFromRNodeSlice(rnodes []*yaml.RNode) (ResMap, error) { - var resources []*resource.Resource - for _, rnode := range rnodes { - s, err := rnode.String() - if err != nil { - return nil, err - } - r, err := rmF.resF.SliceFromBytes([]byte(s)) - if err != nil { - return nil, err - } - resources = append(resources, r...) +func (rmF *Factory) NewResMapFromRNodeSlice(s []*yaml.RNode) (ResMap, error) { + rs, err := rmF.resF.ResourcesFromRNodes(s) + if err != nil { + return nil, err } - return newResMapFromResourceSlice(resources) + return newResMapFromResourceSlice(rs) } diff --git a/vendor/sigs.k8s.io/kustomize/api/resmap/idslice.go b/vendor/sigs.k8s.io/kustomize/api/resmap/idslice.go index f2e46d44069..a13d9d3c943 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resmap/idslice.go +++ b/vendor/sigs.k8s.io/kustomize/api/resmap/idslice.go @@ -19,7 +19,7 @@ package resmap import ( "sort" - "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/kyaml/resid" ) // IdSlice implements the sort interface. diff --git a/vendor/sigs.k8s.io/kustomize/api/resmap/merginator.go b/vendor/sigs.k8s.io/kustomize/api/resmap/merginator.go deleted file mode 100644 index c09b5aacb2d..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/resmap/merginator.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2020 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package resmap - -import ( - "fmt" - - "sigs.k8s.io/kustomize/api/resource" -) - -// merginator coordinates merging the resources in incoming to the result. -type merginator struct { - incoming []*resource.Resource - cdf resource.ConflictDetectorFactory - result ResMap -} - -func (m *merginator) ConflatePatches(in []*resource.Resource) (ResMap, error) { - m.result = New() - m.incoming = in - for index := range m.incoming { - alreadyInResult, err := m.appendIfNoMatch(index) - if err != nil { - return nil, err - } - if alreadyInResult != nil { - // The resource at index has the same resId as a previously - // considered resource. - // - // If they conflict with each other (e.g. they both want to change - // the image name in a Deployment, but to different values), - // return an error. - // - // If they don't conflict, then merge them into a single resource, - // since they both target the same item, and we want cumulative - // behavior. E.g. say both patches modify a map. Without a merge, - // the last patch wins, replacing the entire map. - err = m.mergeWithExisting(index, alreadyInResult) - if err != nil { - return nil, err - } - } - } - return m.result, nil -} - -func (m *merginator) appendIfNoMatch(index int) (*resource.Resource, error) { - candidate := m.incoming[index] - matchedResources := m.result.GetMatchingResourcesByAnyId( - candidate.OrgId().Equals) - if len(matchedResources) == 0 { - m.result.Append(candidate) - return nil, nil - } - if len(matchedResources) > 1 { - return nil, fmt.Errorf("multiple resources targeted by patch") - } - return matchedResources[0], nil -} - -func (m *merginator) mergeWithExisting( - index int, alreadyInResult *resource.Resource) error { - candidate := m.incoming[index] - cd, err := m.cdf.New(candidate.OrgId().Gvk) - if err != nil { - return err - } - hasConflict, err := cd.HasConflict(candidate, alreadyInResult) - if err != nil { - return err - } - if hasConflict { - return m.makeError(cd, index) - } - merged, err := cd.MergePatches(alreadyInResult, candidate) - if err != nil { - return err - } - _, err = m.result.Replace(merged) - return err -} - -// Make an error message describing the conflict. -func (m *merginator) makeError(cd resource.ConflictDetector, index int) error { - conflict, err := m.findConflict(cd, index) - if err != nil { - return err - } - if conflict == nil { - return fmt.Errorf("expected conflict for %s", m.incoming[index].OrgId()) - } - conflictMap, _ := conflict.Map() - incomingIndexMap, _ := m.incoming[index].Map() - return fmt.Errorf( - "conflict between %#v at index %d and %#v", - incomingIndexMap, - index, - conflictMap, - ) -} - -// findConflict looks for a conflict in a resource slice. -// It returns the first conflict between the resource at index -// and some other resource. Two resources can only conflict if -// they have the same original ResId. -func (m *merginator) findConflict( - cd resource.ConflictDetector, index int) (*resource.Resource, error) { - targetId := m.incoming[index].OrgId() - for i, p := range m.incoming { - if i == index || !targetId.Equals(p.OrgId()) { - continue - } - conflict, err := cd.HasConflict(p, m.incoming[index]) - if err != nil { - return nil, err - } - if conflict { - return p, nil - } - } - return nil, nil -} diff --git a/vendor/sigs.k8s.io/kustomize/api/resmap/resmap.go b/vendor/sigs.k8s.io/kustomize/api/resmap/resmap.go index b803453e128..704276cf1fa 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resmap/resmap.go +++ b/vendor/sigs.k8s.io/kustomize/api/resmap/resmap.go @@ -7,9 +7,10 @@ package resmap import ( "sigs.k8s.io/kustomize/api/ifc" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -33,8 +34,10 @@ type Configurable interface { } // NewPluginHelpers makes an instance of PluginHelpers. -func NewPluginHelpers(ldr ifc.Loader, v ifc.Validator, rf *Factory) *PluginHelpers { - return &PluginHelpers{ldr: ldr, v: v, rf: rf} +func NewPluginHelpers( + ldr ifc.Loader, v ifc.Validator, rf *Factory, + pc *types.PluginConfig) *PluginHelpers { + return &PluginHelpers{ldr: ldr, v: v, rf: rf, pc: pc} } // PluginHelpers holds things that any or all plugins might need. @@ -44,6 +47,11 @@ type PluginHelpers struct { ldr ifc.Loader v ifc.Validator rf *Factory + pc *types.PluginConfig +} + +func (c *PluginHelpers) GeneralConfig() *types.PluginConfig { + return c.pc } func (c *PluginHelpers) Loader() ifc.Loader { @@ -80,6 +88,9 @@ type TransformerPlugin interface { // resource to transform, try the OrgId first, and if this // fails or finds too many, it might make sense to then try // the CurrId. Depends on the situation. +// +// TODO: get rid of this interface (use bare resWrangler). +// There aren't multiple implementations any more. type ResMap interface { // Size reports the number of resources. Size() int @@ -158,21 +169,20 @@ type ResMap interface { // GroupedByCurrentNamespace returns a map of namespace // to a slice of *Resource in that namespace. - // Resources for whom IsNamespaceableKind is false are - // are not included at all (see NonNamespaceable). + // Cluster-scoped Resources are not included (see ClusterScoped). // Resources with an empty namespace are placed // in the resid.DefaultNamespace entry. GroupedByCurrentNamespace() map[string][]*resource.Resource - // GroupByOrginalNamespace performs as GroupByNamespace + // GroupedByOriginalNamespace performs as GroupByNamespace // but use the original namespace instead of the current // one to perform the grouping. GroupedByOriginalNamespace() map[string][]*resource.Resource - // NonNamespaceable returns a slice of resources that + // ClusterScoped returns a slice of resources that // cannot be placed in a namespace, e.g. // Node, ClusterRole, Namespace itself, etc. - NonNamespaceable() []*resource.Resource + ClusterScoped() []*resource.Resource // AllIds returns all CurrentIds. AllIds() []resid.ResId @@ -189,6 +199,9 @@ type ResMap interface { // Clear removes all resources and Ids. Clear() + // DropEmpties drops empty resources from the ResMap. + DropEmpties() + // SubsetThatCouldBeReferencedByResource returns a ResMap subset // of self with resources that could be referenced by the // resource argument. @@ -231,9 +244,8 @@ type ResMap interface { // are selected by a Selector Select(types.Selector) ([]*resource.Resource, error) - // ToRNodeSlice converts the resources in the resmp - // to a list of RNodes - ToRNodeSlice() ([]*yaml.RNode, error) + // ToRNodeSlice returns a copy of the resources as RNodes. + ToRNodeSlice() []*yaml.RNode // ApplySmPatch applies a strategic-merge patch to the // selected set of resources. @@ -242,4 +254,14 @@ type ResMap interface { // RemoveBuildAnnotations removes annotations created by the build process. RemoveBuildAnnotations() + + // ApplyFilter applies an RNode filter to all Resources in the ResMap. + // TODO: Send/recover ancillary Resource data to/from subprocesses. + // Assure that the ancillary data in Resource (everything not in the RNode) + // is sent to and re-captured from transformer subprocess (as the process + // might edit that information). One way to do this would be to solely use + // RNode metadata annotation reading and writing instead of using Resource + // struct data members, i.e. the Resource struct is replaced by RNode + // and use of (slow) k8s metadata annotations inside the RNode. + ApplyFilter(f kio.Filter) error } diff --git a/vendor/sigs.k8s.io/kustomize/api/resmap/reswrangler.go b/vendor/sigs.k8s.io/kustomize/api/resmap/reswrangler.go index f76276c481b..0305a553263 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resmap/reswrangler.go +++ b/vendor/sigs.k8s.io/kustomize/api/resmap/reswrangler.go @@ -6,14 +6,14 @@ package resmap import ( "bytes" "fmt" - "strings" + "reflect" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" - kyaml_yaml "sigs.k8s.io/kustomize/kyaml/yaml" - "sigs.k8s.io/yaml" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/resid" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" ) // resWrangler implements ResMap. @@ -38,6 +38,18 @@ func (m *resWrangler) Clear() { m.rList = nil } +// DropEmpties quickly drops empty resources. +// It doesn't use Append, which checks for Id collisions. +func (m *resWrangler) DropEmpties() { + var rList []*resource.Resource + for _, r := range m.rList { + if !r.IsNilOrEmpty() { + rList = append(rList, r) + } + } + m.rList = rList +} + // Size implements ResMap. func (m *resWrangler) Size() int { return len(m.rList) @@ -66,22 +78,27 @@ func (m *resWrangler) Append(res *resource.Resource) error { return fmt.Errorf( "may not add resource with an already registered id: %s", id) } - m.rList = append(m.rList, res) + m.append(res) return nil } +// append appends without performing an Id check +func (m *resWrangler) append(res *resource.Resource) { + m.rList = append(m.rList, res) +} + // Remove implements ResMap. func (m *resWrangler) Remove(adios resid.ResId) error { - tmp := newOne() + var rList []*resource.Resource for _, r := range m.rList { if r.CurId() != adios { - tmp.Append(r) + rList = append(rList, r) } } - if tmp.Size() != m.Size()-1 { + if len(rList) != m.Size()-1 { return fmt.Errorf("id %s not found in removal", adios) } - m.rList = tmp.rList + m.rList = rList return nil } @@ -118,16 +135,7 @@ func (m *resWrangler) Debug(title string) { } else { fmt.Println("---") } - fmt.Printf("# %d %s\n", i, r.OrgId()) - m, err := r.Map() - if err != nil { - panic(err) - } - blob, err := yaml.Marshal(m) - if err != nil { - panic(err) - } - fmt.Println(string(blob)) + fmt.Printf("# %d %s\n%s\n", i, r.OrgId(), r.String()) } } @@ -222,18 +230,18 @@ func demandOneMatch( if len(r) > 1 { return nil, fmt.Errorf("multiple matches for %s %s", s, id) } - return nil, fmt.Errorf("no matches for %sId %s", s, id) + return nil, fmt.Errorf("no matches for %s %s", s, id) } -// GroupedByCurrentNamespace implements ResMap.GroupByCurrentNamespace +// GroupedByCurrentNamespace implements ResMap. func (m *resWrangler) GroupedByCurrentNamespace() map[string][]*resource.Resource { items := m.groupedByCurrentNamespace() delete(items, resid.TotallyNotANamespace) return items } -// NonNamespaceable implements ResMap.NonNamespaceable -func (m *resWrangler) NonNamespaceable() []*resource.Resource { +// ClusterScoped implements ResMap. +func (m *resWrangler) ClusterScoped() []*resource.Resource { return m.groupedByCurrentNamespace()[resid.TotallyNotANamespace] } @@ -249,7 +257,7 @@ func (m *resWrangler) groupedByCurrentNamespace() map[string][]*resource.Resourc return byNamespace } -// GroupedByNamespace implements ResMap.GroupByOrginalNamespace +// GroupedByOriginalNamespace implements ResMap. func (m *resWrangler) GroupedByOriginalNamespace() map[string][]*resource.Resource { items := m.groupedByOriginalNamespace() delete(items, resid.TotallyNotANamespace) @@ -273,7 +281,7 @@ func (m *resWrangler) AsYaml() ([]byte, error) { firstObj := true var b []byte buf := bytes.NewBuffer(b) - for _, res := range m.Resources() { + for _, res := range m.rList { out, err := res.AsYAML() if err != nil { m, _ := res.Map() @@ -297,7 +305,7 @@ func (m *resWrangler) AsYaml() ([]byte, error) { func (m *resWrangler) ErrorIfNotEqualSets(other ResMap) error { m2, ok := other.(*resWrangler) if !ok { - panic("bad cast") + return fmt.Errorf("bad cast to resWrangler 1") } if m.Size() != m2.Size() { return fmt.Errorf( @@ -317,9 +325,9 @@ func (m *resWrangler) ErrorIfNotEqualSets(other ResMap) error { "id in self matches %d in other; id: %s", len(others), id) } r2 := others[0] - if !r1.KunstructEqual(r2) { + if !reflect.DeepEqual(r1.RNode, r2.RNode) { return fmt.Errorf( - "kunstruct not equal: \n -- %s,\n -- %s\n\n--\n%#v\n------\n%#v\n", + "nodes unequal: \n -- %s,\n -- %s\n\n--\n%#v\n------\n%#v\n", r1, r2, r1, r2) } seen[m2.indexOfResource(r2)] = true @@ -330,11 +338,11 @@ func (m *resWrangler) ErrorIfNotEqualSets(other ResMap) error { return nil } -// ErrorIfNotEqualList implements ResMap. +// ErrorIfNotEqualLists implements ResMap. func (m *resWrangler) ErrorIfNotEqualLists(other ResMap) error { m2, ok := other.(*resWrangler) if !ok { - panic("bad cast") + return fmt.Errorf("bad cast to resWrangler 2") } if m.Size() != m2.Size() { return fmt.Errorf( @@ -382,15 +390,15 @@ func (m *resWrangler) makeCopy(copier resCopier) ResMap { func (m *resWrangler) SubsetThatCouldBeReferencedByResource( referrer *resource.Resource) ResMap { referrerId := referrer.CurId() - if !referrerId.IsNamespaceableKind() { + if referrerId.IsClusterScoped() { // A cluster scoped resource can refer to anything. return m } result := newOne() roleBindingNamespaces := getNamespacesForRoleBinding(referrer) - for _, possibleTarget := range m.Resources() { + for _, possibleTarget := range m.rList { id := possibleTarget.CurId() - if !id.IsNamespaceableKind() { + if id.IsClusterScoped() { // A cluster-scoped resource can be referred to by anything. result.append(possibleTarget) continue @@ -403,8 +411,7 @@ func (m *resWrangler) SubsetThatCouldBeReferencedByResource( // The two objects are namespaced (not cluster-scoped), AND // are in different namespaces. // There's still a chance they can refer to each other. - ns := possibleTarget.GetNamespace() - if roleBindingNamespaces[ns] { + if roleBindingNamespaces[possibleTarget.GetNamespace()] { result.append(possibleTarget) } } @@ -418,6 +425,7 @@ func getNamespacesForRoleBinding(r *resource.Resource) map[string]bool { if r.GetKind() != "RoleBinding" { return result } + //nolint staticcheck subjects, err := r.GetSlice("subjects") if err != nil || subjects == nil { return result @@ -435,16 +443,21 @@ func getNamespacesForRoleBinding(r *resource.Resource) map[string]bool { return result } -func (m *resWrangler) append(res *resource.Resource) { - m.rList = append(m.rList, res) -} - // AppendAll implements ResMap. func (m *resWrangler) AppendAll(other ResMap) error { if other == nil { return nil } - for _, res := range other.Resources() { + m2, ok := other.(*resWrangler) + if !ok { + return fmt.Errorf("bad cast to resWrangler 3") + } + return m.appendAll(m2.rList) +} + +// appendAll appends all the resources, error on Id collision. +func (m *resWrangler) appendAll(list []*resource.Resource) error { + for _, res := range list { if err := m.Append(res); err != nil { return err } @@ -457,7 +470,11 @@ func (m *resWrangler) AbsorbAll(other ResMap) error { if other == nil { return nil } - for _, r := range other.Resources() { + m2, ok := other.(*resWrangler) + if !ok { + return fmt.Errorf("bad cast to resWrangler 4") + } + for _, r := range m2.rList { err := m.appendReplaceOrMerge(r) if err != nil { return err @@ -522,7 +539,7 @@ func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) { if err != nil { return nil, err } - for _, r := range m.Resources() { + for _, r := range m.rList { curId := r.CurId() orgId := r.OrgId() @@ -567,77 +584,79 @@ func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) { return result, nil } -// ToRNodeSlice converts the resources in the resmp -// to a list of RNodes -func (m *resWrangler) ToRNodeSlice() ([]*kyaml_yaml.RNode, error) { - var rnodes []*kyaml_yaml.RNode - for _, r := range m.Resources() { - s, err := r.AsYAML() - if err != nil { - return nil, err - } - rnode, err := kyaml_yaml.Parse(string(s)) - if err != nil { - return nil, err - } - rnodes = append(rnodes, rnode) +// ToRNodeSlice returns a copy of the resources as RNodes. +func (m *resWrangler) ToRNodeSlice() []*kyaml.RNode { + result := make([]*kyaml.RNode, len(m.rList)) + for i := range m.rList { + result[i] = m.rList[i].Copy() } - return rnodes, nil + return result } +// ApplySmPatch applies the patch, and errors on Id collisions. func (m *resWrangler) ApplySmPatch( selectedSet *resource.IdSet, patch *resource.Resource) error { - newRm := New() - for _, res := range m.Resources() { - if !selectedSet.Contains(res.CurId()) { - newRm.Append(res) - continue - } - patchCopy := patch.DeepCopy() - patchCopy.CopyMergeMetaDataFieldsFrom(patch) - patchCopy.SetGvk(res.GetGvk()) - err := res.ApplySmPatch(patchCopy) - if err != nil { - // Check for an error string from UnmarshalJSON that's indicative - // of an object that's missing basic KRM fields, and thus may have been - // entirely deleted (an acceptable outcome). This error handling should - // be deleted along with use of ResMap and apimachinery functions like - // UnmarshalJSON. - if !strings.Contains(err.Error(), "Object 'Kind' is missing") { - // Some unknown error, let it through. - return err - } - empty, err := res.IsEmpty() - if err != nil { + var list []*resource.Resource + for _, res := range m.rList { + if selectedSet.Contains(res.CurId()) { + patchCopy := patch.DeepCopy() + patchCopy.CopyMergeMetaDataFieldsFrom(patch) + patchCopy.SetGvk(res.GetGvk()) + patchCopy.SetKind(patch.GetKind()) + if err := res.ApplySmPatch(patchCopy); err != nil { return err } - if !empty { - m, _ := res.Map() - return errors.Wrapf( - err, "with unexpectedly non-empty object map of size %d", - len(m)) - } - // Fall through to handle deleted object. } - empty, err := res.IsEmpty() - if err != nil { - return err - } - if !empty { - // IsEmpty means all fields have been removed from the object. - // This can happen if a patch required deletion of the - // entire resource (not just a part of it). This means - // the overall resmap must shrink by one. - newRm.Append(res) + if !res.IsNilOrEmpty() { + list = append(list, res) } } m.Clear() - m.AppendAll(newRm) - return nil + return m.appendAll(list) } func (m *resWrangler) RemoveBuildAnnotations() { - for _, r := range m.Resources() { + for _, r := range m.rList { r.RemoveBuildAnnotations() } } + +// ApplyFilter implements ResMap. +func (m *resWrangler) ApplyFilter(f kio.Filter) error { + reverseLookup := make(map[*kyaml.RNode]*resource.Resource, len(m.rList)) + nodes := make([]*kyaml.RNode, len(m.rList)) + for i, r := range m.rList { + ptr := &(r.RNode) + nodes[i] = ptr + reverseLookup[ptr] = r + } + // The filter can modify nodes, but also delete and create them. + // The filtered list might be smaller or larger than the nodes list. + filtered, err := f.Filter(nodes) + if err != nil { + return err + } + // Rebuild the resmap from the filtered RNodes. + var nRList []*resource.Resource + for _, rn := range filtered { + if rn.IsNilOrEmpty() { + // A node might make it through the filter as an object, + // but still be empty. Drop such entries. + continue + } + res, ok := reverseLookup[rn] + if !ok { + // A node was created; make a Resource to wrap it. + res = &resource.Resource{ + RNode: *rn, + // Leave remaining fields empty. + // At at time of writing, seeking to eliminate those fields. + // Alternatively, could just return error on creation attempt + // until remaining fields eliminated. + } + } + nRList = append(nRList, res) + } + m.rList = nRList + return nil +} diff --git a/vendor/sigs.k8s.io/kustomize/api/resource/conflictdetector.go b/vendor/sigs.k8s.io/kustomize/api/resource/conflictdetector.go deleted file mode 100644 index f079cdd5abb..00000000000 --- a/vendor/sigs.k8s.io/kustomize/api/resource/conflictdetector.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package resource - -import "sigs.k8s.io/kustomize/api/resid" - -// ConflictDetector detects conflicts between resources. -type ConflictDetector interface { - // HasConflict returns true if the given resources have a conflict. - HasConflict(patch1, patch2 *Resource) (bool, error) - // Merge two resources into one. - MergePatches(patch1, patch2 *Resource) (*Resource, error) -} - -// ConflictDetectorFactory makes instances of ConflictDetector that know -// how to handle the given Group, Version, Kind tuple. -type ConflictDetectorFactory interface { - New(gvk resid.Gvk) (ConflictDetector, error) -} diff --git a/vendor/sigs.k8s.io/kustomize/api/resource/factory.go b/vendor/sigs.k8s.io/kustomize/api/resource/factory.go index df08c5dbf51..97ced84ba0c 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resource/factory.go +++ b/vendor/sigs.k8s.io/kustomize/api/resource/factory.go @@ -10,28 +10,39 @@ import ( "strings" "sigs.k8s.io/kustomize/api/ifc" + "sigs.k8s.io/kustomize/api/internal/generators" "sigs.k8s.io/kustomize/api/internal/kusterr" - "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/resid" + "sigs.k8s.io/kustomize/kyaml/yaml" ) // Factory makes instances of Resource. type Factory struct { - kf ifc.KunstructuredFactory + hasher ifc.KustHasher + + // When set to true, IncludeLocalConfigs indicates + // that Factory should include resources with the + // annotation 'config.kubernetes.io/local-config'. + // By default these resources are ignored. + IncludeLocalConfigs bool } // NewFactory makes an instance of Factory. -func NewFactory(kf ifc.KunstructuredFactory) *Factory { - return &Factory{kf: kf} +func NewFactory(h ifc.KustHasher) *Factory { + return &Factory{hasher: h} } -func (rf *Factory) Hasher() ifc.KunstructuredHasher { - return rf.kf.Hasher() +// Hasher returns an ifc.KustHasher +func (rf *Factory) Hasher() ifc.KustHasher { + return rf.hasher } // FromMap returns a new instance of Resource. func (rf *Factory) FromMap(m map[string]interface{}) *Resource { - return rf.makeOne(rf.kf.FromMap(m), nil) + return rf.FromMapAndOption(m, nil) } // FromMapWithName returns a new instance with the given "original" name. @@ -41,34 +52,30 @@ func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) *Resource // FromMapWithNamespaceAndName returns a new instance with the given "original" namespace. func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource { - return rf.makeOne(rf.kf.FromMap(m), nil).setPreviousNamespaceAndName(ns, n) + r := rf.FromMapAndOption(m, nil) + return r.setPreviousId(ns, n, r.GetKind()) } // FromMapAndOption returns a new instance of Resource with given options. func (rf *Factory) FromMapAndOption( m map[string]interface{}, args *types.GeneratorArgs) *Resource { - return rf.makeOne(rf.kf.FromMap(m), types.NewGenArgs(args)) -} - -// FromKunstructured returns a new instance of Resource. -func (rf *Factory) FromKunstructured(u ifc.Kunstructured) *Resource { - return rf.makeOne(u, nil) + n, err := yaml.FromMap(m) + if err != nil { + // TODO: return err instead of log. + log.Fatal(err) + } + return rf.makeOne(n, types.NewGenArgs(args)) } // makeOne returns a new instance of Resource. -func (rf *Factory) makeOne( - u ifc.Kunstructured, o *types.GenArgs) *Resource { - if u == nil { - log.Fatal("unstruct ifc must not be null") +func (rf *Factory) makeOne(rn *yaml.RNode, o *types.GenArgs) *Resource { + if rn == nil { + log.Fatal("RNode must not be null") } if o == nil { o = types.NewGenArgs(nil) } - r := &Resource{ - kunStr: u, - options: o, - } - return r + return &Resource{RNode: *rn, options: o} } // SliceFromPatches returns a slice of resources given a patch path @@ -105,47 +112,137 @@ func (rf *Factory) FromBytes(in []byte) (*Resource, error) { // SliceFromBytes unmarshals bytes into a Resource slice. func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) { - kunStructs, err := rf.kf.SliceFromBytes(in) + nodes, err := rf.RNodesFromBytes(in) if err != nil { return nil, err } - var result []*Resource - for len(kunStructs) > 0 { - u := kunStructs[0] - kunStructs = kunStructs[1:] - if strings.HasSuffix(u.GetKind(), "List") { - m, err := u.Map() - if err != nil { - return nil, err - } - items := m["items"] - itemsSlice, ok := items.([]interface{}) - if !ok { - if items == nil { - // an empty list - continue - } - return nil, fmt.Errorf("items in List is type %T, expected array", items) - } - for _, item := range itemsSlice { - itemJSON, err := json.Marshal(item) - if err != nil { - return nil, err - } - innerU, err := rf.kf.SliceFromBytes(itemJSON) - if err != nil { - return nil, err - } - // append innerU to kunStructs so nested Lists can be handled - kunStructs = append(kunStructs, innerU...) + return rf.resourcesFromRNodes(nodes), nil +} + +// ResourcesFromRNodes converts RNodes to Resources. +func (rf *Factory) ResourcesFromRNodes( + nodes []*yaml.RNode) (result []*Resource, err error) { + nodes, err = rf.dropBadNodes(nodes) + if err != nil { + return nil, err + } + return rf.resourcesFromRNodes(nodes), nil +} + +// resourcesFromRNode assumes all nodes are good. +func (rf *Factory) resourcesFromRNodes( + nodes []*yaml.RNode) (result []*Resource) { + for _, n := range nodes { + result = append(result, rf.makeOne(n, nil)) + } + return +} + +func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) { + nodes, err := kio.FromBytes(b) + if err != nil { + return nil, err + } + nodes, err = rf.dropBadNodes(nodes) + if err != nil { + return nil, err + } + for len(nodes) > 0 { + n0 := nodes[0] + nodes = nodes[1:] + kind := n0.GetKind() + if !strings.HasSuffix(kind, "List") { + result = append(result, n0) + continue + } + // Convert a FooList into a slice of Foo. + var m map[string]interface{} + m, err = n0.Map() + if err != nil { + return nil, err + } + items, ok := m["items"] + if !ok { + // treat as an empty list + continue + } + slice, ok := items.([]interface{}) + if !ok { + if items == nil { + // an empty list + continue } - } else { - result = append(result, rf.FromKunstructured(u)) + return nil, fmt.Errorf( + "expected array in %s/items, but found %T", kind, items) + } + innerNodes, err := rf.convertObjectSliceToNodeSlice(slice) + if err != nil { + return nil, err } + nodes = append(nodes, innerNodes...) } return result, nil } +// convertObjectSlice converts a list of objects to a list of RNode. +func (rf *Factory) convertObjectSliceToNodeSlice( + objects []interface{}) (result []*yaml.RNode, err error) { + var bytes []byte + var nodes []*yaml.RNode + for _, obj := range objects { + bytes, err = json.Marshal(obj) + if err != nil { + return + } + nodes, err = kio.FromBytes(bytes) + if err != nil { + return + } + nodes, err = rf.dropBadNodes(nodes) + if err != nil { + return + } + result = append(result, nodes...) + } + return +} + +// dropBadNodes may drop some nodes from its input argument. +func (rf *Factory) dropBadNodes(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + var result []*yaml.RNode + for _, n := range nodes { + ignore, err := rf.shouldIgnore(n) + if err != nil { + return nil, err + } + if !ignore { + result = append(result, n) + } + } + return result, nil +} + +// shouldIgnore returns true if there's some reason to ignore the node. +func (rf *Factory) shouldIgnore(n *yaml.RNode) (bool, error) { + if n.IsNilOrEmpty() { + return true, nil + } + if !rf.IncludeLocalConfigs { + md, err := n.GetValidatedMetadata() + if err != nil { + return true, err + } + _, ignore := md.ObjectMeta.Annotations[konfig.IgnoredByKustomizeAnnotation] + if ignore { + return true, nil + } + } + if foundNil, path := n.HasNilEntryInList(); foundNil { + return true, fmt.Errorf("empty item at %v in object %v", path, n) + } + return false, nil +} + // SliceFromBytesWithNames unmarshals bytes into a Resource slice with specified original // name. func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resource, error) { @@ -157,25 +254,25 @@ func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resour return nil, fmt.Errorf("number of names doesn't match number of resources") } for i, res := range result { - res.setPreviousNamespaceAndName(resid.DefaultNamespace, names[i]) + res.setPreviousId(resid.DefaultNamespace, names[i], res.GetKind()) } return result, nil } // MakeConfigMap makes an instance of Resource for ConfigMap func (rf *Factory) MakeConfigMap(kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (*Resource, error) { - u, err := rf.kf.MakeConfigMap(kvLdr, args) + rn, err := generators.MakeConfigMap(kvLdr, args) if err != nil { return nil, err } - return rf.makeOne(u, types.NewGenArgs(&args.GeneratorArgs)), nil + return rf.makeOne(rn, types.NewGenArgs(&args.GeneratorArgs)), nil } // MakeSecret makes an instance of Resource for Secret func (rf *Factory) MakeSecret(kvLdr ifc.KvLoader, args *types.SecretArgs) (*Resource, error) { - u, err := rf.kf.MakeSecret(kvLdr, args) + rn, err := generators.MakeSecret(kvLdr, args) if err != nil { return nil, err } - return rf.makeOne(u, types.NewGenArgs(&args.GeneratorArgs)), nil + return rf.makeOne(rn, types.NewGenArgs(&args.GeneratorArgs)), nil } diff --git a/vendor/sigs.k8s.io/kustomize/api/resource/idset.go b/vendor/sigs.k8s.io/kustomize/api/resource/idset.go index eaa25338164..5d6bd63edc6 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resource/idset.go +++ b/vendor/sigs.k8s.io/kustomize/api/resource/idset.go @@ -3,7 +3,7 @@ package resource -import "sigs.k8s.io/kustomize/api/resid" +import "sigs.k8s.io/kustomize/kyaml/resid" type IdSet struct { ids map[resid.ResId]bool diff --git a/vendor/sigs.k8s.io/kustomize/api/resource/resource.go b/vendor/sigs.k8s.io/kustomize/api/resource/resource.go index d9f2b107b03..c7065a38594 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resource/resource.go +++ b/vendor/sigs.k8s.io/kustomize/api/resource/resource.go @@ -4,161 +4,54 @@ package resource import ( - "errors" "fmt" "log" - "reflect" "strings" "sigs.k8s.io/kustomize/api/filters/patchstrategicmerge" "sigs.k8s.io/kustomize/api/ifc" - "sigs.k8s.io/kustomize/api/internal/wrappy" - "sigs.k8s.io/kustomize/api/konfig" - "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/api/internal/utils" "sigs.k8s.io/kustomize/api/types" - "sigs.k8s.io/kustomize/kyaml/filtersutil" "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/resid" kyaml "sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/yaml" ) -// Resource is a representation of a Kubernetes Resource Model (KRM) object +// Resource is an RNode, representing a Kubernetes Resource Model object, // paired with metadata used by kustomize. -// For more history, see sigs.k8s.io/kustomize/api/ifc.Unstructured type Resource struct { - kunStr ifc.Kunstructured + kyaml.RNode options *types.GenArgs refBy []resid.ResId refVarNames []string } -const ( - buildAnnotationPreviousNames = konfig.ConfigAnnoDomain + "/previousNames" - buildAnnotationPrefixes = konfig.ConfigAnnoDomain + "/prefixes" - buildAnnotationSuffixes = konfig.ConfigAnnoDomain + "/suffixes" - buildAnnotationPreviousNamespaces = konfig.ConfigAnnoDomain + "/previousNamespaces" -) - -var buildAnnotations = []string{ - buildAnnotationPreviousNames, - buildAnnotationPrefixes, - buildAnnotationSuffixes, - buildAnnotationPreviousNamespaces, -} - -func (r *Resource) ResetPrimaryData(incoming *Resource) { - r.kunStr = incoming.Copy() -} - -func (r *Resource) GetAnnotations() map[string]string { - annotations := r.kunStr.GetAnnotations() - if annotations == nil { - return make(map[string]string) - } - return annotations -} - -func (r *Resource) Copy() ifc.Kunstructured { - return r.kunStr.Copy() -} - -func (r *Resource) GetFieldValue(f string) (interface{}, error) { - return r.kunStr.GetFieldValue(f) -} - -func (r *Resource) GetDataMap() map[string]string { - return r.kunStr.GetDataMap() +var BuildAnnotations = []string{ + utils.BuildAnnotationPreviousKinds, + utils.BuildAnnotationPreviousNames, + utils.BuildAnnotationPrefixes, + utils.BuildAnnotationSuffixes, + utils.BuildAnnotationPreviousNamespaces, + utils.BuildAnnotationAllowNameChange, + utils.BuildAnnotationAllowKindChange, } -func (r *Resource) GetBinaryDataMap() map[string]string { - return r.kunStr.GetBinaryDataMap() +func (r *Resource) ResetRNode(incoming *Resource) { + r.RNode = *incoming.Copy() } func (r *Resource) GetGvk() resid.Gvk { - return r.kunStr.GetGvk() -} - -func (r *Resource) GetKind() string { - return r.kunStr.GetKind() -} - -func (r *Resource) GetLabels() map[string]string { - return r.kunStr.GetLabels() -} - -func (r *Resource) GetName() string { - return r.kunStr.GetName() -} - -func (r *Resource) GetSlice(p string) ([]interface{}, error) { - return r.kunStr.GetSlice(p) + return resid.GvkFromNode(&r.RNode) } -func (r *Resource) GetString(p string) (string, error) { - return r.kunStr.GetString(p) -} - -func (r *Resource) IsEmpty() (bool, error) { - m, err := r.kunStr.Map() - return len(m) == 0, err -} - -func (r *Resource) Map() (map[string]interface{}, error) { - return r.kunStr.Map() -} - -func (r *Resource) MarshalJSON() ([]byte, error) { - return r.kunStr.MarshalJSON() -} - -func (r *Resource) MatchesLabelSelector(selector string) (bool, error) { - return r.kunStr.MatchesLabelSelector(selector) -} - -func (r *Resource) MatchesAnnotationSelector(selector string) (bool, error) { - return r.kunStr.MatchesAnnotationSelector(selector) -} - -func (r *Resource) SetAnnotations(m map[string]string) { - if len(m) == 0 { - // Force field erasure. - r.kunStr.SetAnnotations(nil) - return - } - r.kunStr.SetAnnotations(m) -} - -func (r *Resource) SetDataMap(m map[string]string) { - r.kunStr.SetDataMap(m) -} - -func (r *Resource) SetBinaryDataMap(m map[string]string) { - r.kunStr.SetBinaryDataMap(m) +func (r *Resource) Hash(h ifc.KustHasher) (string, error) { + return h.Hash(&r.RNode) } func (r *Resource) SetGvk(gvk resid.Gvk) { - r.kunStr.SetGvk(gvk) -} - -func (r *Resource) SetLabels(m map[string]string) { - if len(m) == 0 { - // Force field erasure. - r.kunStr.SetLabels(nil) - return - } - r.kunStr.SetLabels(m) -} - -func (r *Resource) SetName(n string) { - r.kunStr.SetName(n) -} - -func (r *Resource) SetNamespace(n string) { - r.kunStr.SetNamespace(n) -} - -func (r *Resource) UnmarshalJSON(s []byte) error { - return r.kunStr.UnmarshalJSON(s) + r.SetKind(gvk.Kind) + r.SetApiVersion(gvk.ApiVersion()) } // ResCtx is an interface describing the contextual added @@ -178,24 +71,36 @@ type ResCtxMatcher func(ResCtx) bool // DeepCopy returns a new copy of resource func (r *Resource) DeepCopy() *Resource { rc := &Resource{ - kunStr: r.Copy(), + RNode: *r.Copy(), } - rc.copyOtherFields(r) + rc.copyKustomizeSpecificFields(r) return rc } -// CopyMergeMetaDataFields copies everything but the non-metadata in -// the ifc.Kunstructured map, merging labels and annotations. -func (r *Resource) CopyMergeMetaDataFieldsFrom(other *Resource) { - r.SetLabels(mergeStringMaps(other.GetLabels(), r.GetLabels())) - r.SetAnnotations( - mergeStringMaps(other.GetAnnotations(), r.GetAnnotations())) - r.SetName(other.GetName()) - r.SetNamespace(other.GetNamespace()) - r.copyOtherFields(other) +// CopyMergeMetaDataFieldsFrom copies everything but the non-metadata in +// the resource. +// TODO: move to RNode, use GetMeta to improve performance. +// Must remove the kustomize bit at the end. +func (r *Resource) CopyMergeMetaDataFieldsFrom(other *Resource) error { + if err := r.SetLabels( + mergeStringMaps(other.GetLabels(), r.GetLabels())); err != nil { + return fmt.Errorf("copyMerge cannot set labels - %w", err) + } + if err := r.SetAnnotations( + mergeStringMaps(other.GetAnnotations(), r.GetAnnotations())); err != nil { + return fmt.Errorf("copyMerge cannot set annotations - %w", err) + } + if err := r.SetName(other.GetName()); err != nil { + return fmt.Errorf("copyMerge cannot set name - %w", err) + } + if err := r.SetNamespace(other.GetNamespace()); err != nil { + return fmt.Errorf("copyMerge cannot set namespace - %w", err) + } + r.copyKustomizeSpecificFields(other) + return nil } -func (r *Resource) copyOtherFields(other *Resource) { +func (r *Resource) copyKustomizeSpecificFields(other *Resource) { r.options = other.options r.refBy = other.copyRefBy() r.refVarNames = copyStringSlice(other.refVarNames) @@ -251,10 +156,6 @@ func (r *Resource) ReferencesEqual(other *Resource) bool { return len(setSelf) == len(setOther) } -func (r *Resource) KunstructEqual(o *Resource) bool { - return reflect.DeepEqual(r.kunStr, o.kunStr) -} - func (r *Resource) copyRefBy() []resid.ResId { if r.refBy == nil { return nil @@ -275,12 +176,12 @@ func copyStringSlice(s []string) []string { // Implements ResCtx AddNamePrefix func (r *Resource) AddNamePrefix(p string) { - r.appendCsvAnnotation(buildAnnotationPrefixes, p) + r.appendCsvAnnotation(utils.BuildAnnotationPrefixes, p) } // Implements ResCtx AddNameSuffix func (r *Resource) AddNameSuffix(s string) { - r.appendCsvAnnotation(buildAnnotationSuffixes, s) + r.appendCsvAnnotation(utils.BuildAnnotationSuffixes, s) } func (r *Resource) appendCsvAnnotation(name, value string) { @@ -293,33 +194,19 @@ func (r *Resource) appendCsvAnnotation(name, value string) { } else { annotations[name] = value } - r.SetAnnotations(annotations) -} - -func SameEndingSubarray(shortest, longest []string) bool { - if len(shortest) > len(longest) { - longest, shortest = shortest, longest - } - diff := len(longest) - len(shortest) - if len(shortest) == 0 { - return diff == 0 + if err := r.SetAnnotations(annotations); err != nil { + panic(err) } - for i := len(shortest) - 1; i >= 0; i-- { - if longest[i+diff] != shortest[i] { - return false - } - } - return true } // Implements ResCtx GetNamePrefixes func (r *Resource) GetNamePrefixes() []string { - return r.getCsvAnnotation(buildAnnotationPrefixes) + return r.getCsvAnnotation(utils.BuildAnnotationPrefixes) } // Implements ResCtx GetNameSuffixes func (r *Resource) GetNameSuffixes() []string { - return r.getCsvAnnotation(buildAnnotationSuffixes) + return r.getCsvAnnotation(utils.BuildAnnotationSuffixes) } func (r *Resource) getCsvAnnotation(name string) []string { @@ -334,7 +221,8 @@ func (r *Resource) getCsvAnnotation(name string) []string { // as OutermostPrefixSuffix but performs a deeper comparison // of the suffix and prefix slices. func (r *Resource) PrefixesSuffixesEquals(o ResCtx) bool { - return SameEndingSubarray(r.GetNamePrefixes(), o.GetNamePrefixes()) && SameEndingSubarray(r.GetNameSuffixes(), o.GetNameSuffixes()) + return utils.SameEndingSubSlice(r.GetNamePrefixes(), o.GetNamePrefixes()) && + utils.SameEndingSubSlice(r.GetNameSuffixes(), o.GetNameSuffixes()) } // RemoveBuildAnnotations removes annotations created by the build process. @@ -345,18 +233,51 @@ func (r *Resource) RemoveBuildAnnotations() { if len(annotations) == 0 { return } - for _, a := range buildAnnotations { + for _, a := range BuildAnnotations { delete(annotations, a) } - r.SetAnnotations(annotations) + if err := r.SetAnnotations(annotations); err != nil { + panic(err) + } } -func (r *Resource) setPreviousNamespaceAndName(ns string, n string) *Resource { - r.appendCsvAnnotation(buildAnnotationPreviousNames, n) - r.appendCsvAnnotation(buildAnnotationPreviousNamespaces, ns) +func (r *Resource) setPreviousId(ns string, n string, k string) *Resource { + r.appendCsvAnnotation(utils.BuildAnnotationPreviousNames, n) + r.appendCsvAnnotation(utils.BuildAnnotationPreviousNamespaces, ns) + r.appendCsvAnnotation(utils.BuildAnnotationPreviousKinds, k) return r } +// AllowNameChange allows name changes to the resource. +func (r *Resource) AllowNameChange() { + annotations := r.GetAnnotations() + annotations[utils.BuildAnnotationAllowNameChange] = utils.Allowed + if err := r.SetAnnotations(annotations); err != nil { + panic(err) + } +} + +func (r *Resource) NameChangeAllowed() bool { + annotations := r.GetAnnotations() + v, ok := annotations[utils.BuildAnnotationAllowNameChange] + return ok && v == utils.Allowed +} + +// AllowKindChange allows kind changes to the resource. +func (r *Resource) AllowKindChange() { + annotations := r.GetAnnotations() + annotations[utils.BuildAnnotationAllowKindChange] = utils.Allowed + if err := r.SetAnnotations(annotations); err != nil { + panic(err) + } +} + +func (r *Resource) KindChangeAllowed() bool { + annotations := r.GetAnnotations() + v, ok := annotations[utils.BuildAnnotationAllowKindChange] + return ok && v == utils.Allowed +} + // String returns resource as JSON. func (r *Resource) String() string { bs, err := r.MarshalJSON() @@ -401,13 +322,6 @@ func (r *Resource) NeedHashSuffix() bool { return r.options != nil && r.options.ShouldAddHashSuffixToName() } -// GetNamespace returns the namespace the resource thinks it's in. -func (r *Resource) GetNamespace() string { - namespace, _ := r.GetString("metadata.namespace") - // if err, namespace is empty, so no need to check. - return namespace -} - // OrgId returns the original, immutable ResId for the resource. // This doesn't have to be unique in a ResMap. func (r *Resource) OrgId() resid.ResId { @@ -425,27 +339,18 @@ func (r *Resource) OrgId() resid.ResId { // The returned array does not include the resource's current // ID. If there are no previous IDs, this will return nil. func (r *Resource) PrevIds() []resid.ResId { - var ids []resid.ResId - // TODO: merge previous names and namespaces into one list of - // pairs on one annotation so there is no chance of error - names := r.getCsvAnnotation(buildAnnotationPreviousNames) - ns := r.getCsvAnnotation(buildAnnotationPreviousNamespaces) - if len(names) != len(ns) { - panic(errors.New( - "number of previous names not equal to " + - "number of previous namespaces")) - } - for i := range names { - ids = append(ids, resid.NewResIdWithNamespace( - r.GetGvk(), names[i], ns[i])) + prevIds, err := utils.PrevIds(&r.RNode) + if err != nil { + // this should never happen + panic(err) } - return ids + return prevIds } // StorePreviousId stores the resource's current ID via build annotations. func (r *Resource) StorePreviousId() { id := r.CurId() - r.setPreviousNamespaceAndName(id.EffectiveNamespace(), id.Name) + r.setPreviousId(id.EffectiveNamespace(), id.Name, id.Kind) } // CurId returns a ResId for the resource using the @@ -478,38 +383,36 @@ func (r *Resource) AppendRefVarName(variable types.Var) { // ApplySmPatch applies the provided strategic merge patch. func (r *Resource) ApplySmPatch(patch *Resource) error { - node, err := filtersutil.GetRNode(patch) - if err != nil { - return err + n, ns, k := r.GetName(), r.GetNamespace(), r.GetKind() + if patch.NameChangeAllowed() || patch.KindChangeAllowed() { + r.StorePreviousId() } - n, ns := r.GetName(), r.GetNamespace() - err = r.ApplyFilter(patchstrategicmerge.Filter{ - Patch: node, - }) - if err != nil { + if err := r.ApplyFilter(patchstrategicmerge.Filter{ + Patch: &patch.RNode, + }); err != nil { return err } - empty, err := r.IsEmpty() - if err != nil { - return err + if r.IsNilOrEmpty() { + return nil + } + if !patch.KindChangeAllowed() { + r.SetKind(k) } - if !empty { + if !patch.NameChangeAllowed() { r.SetName(n) - r.SetNamespace(ns) } - return err + r.SetNamespace(ns) + return nil } func (r *Resource) ApplyFilter(f kio.Filter) error { - if wn, ok := r.kunStr.(*wrappy.WNode); ok { - l, err := f.Filter([]*kyaml.RNode{wn.AsRNode()}) - if len(l) == 0 { - // Hack to deal with deletion. - r.kunStr = wrappy.NewWNode() - } - return err + l, err := f.Filter([]*kyaml.RNode{&r.RNode}) + if len(l) == 0 { + // The node was deleted, which means the entire resource + // must be deleted. Signal that via the following: + r.SetYNode(nil) } - return filtersutil.ApplyToJSON(f, r) + return err } func mergeStringMaps(maps ...map[string]string) map[string]string { diff --git a/vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go b/vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go index a39e9a38546..f95b8edd5a1 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go @@ -23,7 +23,7 @@ func (e *errUnableToFind) Error() string { m = append(m, "('"+p.Value+"'; "+p.Key+")") } return fmt.Sprintf( - "unable to find plugin root - tried: %s", strings.Join(m, ", ")) + "unable to find %s - tried: %s", e.what, strings.Join(m, ", ")) } func NewErrUnableToFind(w string, a []Pair) *errUnableToFind { diff --git a/vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go b/vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go index f5b711ee576..8d357954479 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go @@ -6,11 +6,10 @@ package types import ( "fmt" - "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/kyaml/resid" ) -// FieldSpec completely specifies a kustomizable field in -// an unstructured representation of a k8s API object. +// FieldSpec completely specifies a kustomizable field in a k8s API object. // It helps define the operands of transformations. // // For example, a directive to add a common label to objects diff --git a/vendor/sigs.k8s.io/kustomize/api/types/genargs.go b/vendor/sigs.k8s.io/kustomize/api/types/genargs.go index a3229c8e339..586d7f1af1d 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/genargs.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/genargs.go @@ -39,7 +39,7 @@ func (g *GenArgs) ShouldAddHashSuffixToName() bool { // Behavior returns Behavior field of GeneratorArgs func (g *GenArgs) Behavior() GenerationBehavior { - if g.args == nil { + if g == nil || g.args == nil { return BehaviorUnspecified } return NewGenerationBehavior(g.args.Behavior) diff --git a/vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go b/vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go index c30f6517d0b..683d89bfde5 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go @@ -15,6 +15,9 @@ type GeneratorOptions struct { // suffix to the names of generated resources that is a hash of the // resource contents. DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"` + + // Immutable if true add to all generated resources. + Immutable bool `json:"immutable,omitempty" yaml:"immutable,omitempty"` } // MergeGlobalOptionsIntoLocal merges two instances of GeneratorOptions. @@ -42,6 +45,9 @@ func MergeGlobalOptionsIntoLocal( if globalOpts.DisableNameSuffixHash { localOpts.DisableNameSuffixHash = true } + if globalOpts.Immutable { + localOpts.Immutable = true + } return localOpts } diff --git a/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go b/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go index 57037208378..c0fff2457e8 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go @@ -3,14 +3,85 @@ package types -// HelmChartArgs contains the metadata of how to generate a secret. +type HelmGlobals struct { + // ChartHome is a file path, relative to the kustomization root, + // to a directory containing a subdirectory for each chart to be + // included in the kustomization. + // The default value of this field is "charts". + // So, for example, kustomize looks for the minecraft chart + // at {kustomizationRoot}/{ChartHome}/minecraft. + // If the chart is there at build time, kustomize will use it as found, + // and not check version numbers or dates. + // If the chart is not there, kustomize will attempt to pull it + // using the version number specified in the kustomization file, + // and put it there. To suppress the pull attempt, simply assure + // that the chart is already there. + ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"` + + // ConfigHome defines a value that kustomize should pass to helm via + // the HELM_CONFIG_HOME environment variable. kustomize doesn't attempt + // to read or write this directory. + // If omitted, {tmpDir}/helm is used, where {tmpDir} is some temporary + // directory created by kustomize for the benefit of helm. + // Likewise, kustomize sets + // HELM_CACHE_HOME={ConfigHome}/.cache + // HELM_DATA_HOME={ConfigHome}/.data + // for the helm subprocess. + ConfigHome string `json:"configHome,omitempty" yaml:"configHome,omitempty"` +} + +type HelmChart struct { + // Name is the name of the chart, e.g. 'minecraft'. + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // Version is the version of the chart, e.g. '3.1.3' + Version string `json:"version,omitempty" yaml:"version,omitempty"` + + // Repo is a URL locating the chart on the internet. + // This is the argument to helm's `--repo` flag, e.g. + // `https://itzg.github.io/minecraft-server-charts`. + Repo string `json:"repo,omitempty" yaml:"repo,omitempty"` + + // ReleaseName replaces RELEASE-NAME in chart template output, + // making a particular inflation of a chart unique with respect to + // other inflations of the same chart in a cluster. It's the first + // argument to the helm `install` and `template` commands, i.e. + // helm install {RELEASE-NAME} {chartName} + // helm template {RELEASE-NAME} {chartName} + // If omitted, the flag --generate-name is passed to 'helm template'. + ReleaseName string `json:"releaseName,omitempty" yaml:"releaseName,omitempty"` + + // Namespace set the target namespace for a release. It is .Release.Namespace + // in the helm template + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + + // ValuesFile is local file path to a values file to use _instead of_ + // the default values that accompanied the chart. + // The default values are in '{ChartHome}/{Name}/values.yaml'. + ValuesFile string `json:"valuesFile,omitempty" yaml:"valuesFile,omitempty"` + + // ValuesInline holds value mappings specified directly, + // rather than in a separate file. + ValuesInline map[string]interface{} `json:"valuesInline,omitempty" yaml:"valuesInline,omitempty"` + + // ValuesMerge specifies how to treat ValuesInline with respect to Values. + // Legal values: 'merge', 'override', 'replace'. + // Defaults to 'override'. + ValuesMerge string `json:"valuesMerge,omitempty" yaml:"valuesMerge,omitempty"` + + // IncludeCRDs specifies if Helm should also generate CustomResourceDefinitions. + // Defaults to 'false'. + IncludeCRDs bool `json:"includeCRDs,omitempty" yaml:"includeCRDs,omitempty"` +} + +// HelmChartArgs contains arguments to helm. +// Deprecated. Use HelmGlobals and HelmChart instead. type HelmChartArgs struct { - ChartName string `json:"chartName,omitempty" yaml:"chartName,omitempty"` - ChartVersion string `json:"chartVersion,omitempty" yaml:"chartVersion,omitempty"` - ChartRepoURL string `json:"chartRepoUrl,omitempty" yaml:"chartRepoUrl,omitempty"` - ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"` - // Use chartRelease to keep compatible with old exec plugin - ChartRepoName string `json:"chartRelease,omitempty" yaml:"chartRelease,omitempty"` + ChartName string `json:"chartName,omitempty" yaml:"chartName,omitempty"` + ChartVersion string `json:"chartVersion,omitempty" yaml:"chartVersion,omitempty"` + ChartRepoURL string `json:"chartRepoUrl,omitempty" yaml:"chartRepoUrl,omitempty"` + ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"` + ChartRepoName string `json:"chartRepoName,omitempty" yaml:"chartRepoName,omitempty"` HelmBin string `json:"helmBin,omitempty" yaml:"helmBin,omitempty"` HelmHome string `json:"helmHome,omitempty" yaml:"helmHome,omitempty"` Values string `json:"values,omitempty" yaml:"values,omitempty"` @@ -20,3 +91,32 @@ type HelmChartArgs struct { ReleaseNamespace string `json:"releaseNamespace,omitempty" yaml:"releaseNamespace,omitempty"` ExtraArgs []string `json:"extraArgs,omitempty" yaml:"extraArgs,omitempty"` } + +// SplitHelmParameters splits helm parameters into +// per-chart params and global chart-independent parameters. +func SplitHelmParameters( + oldArgs []HelmChartArgs) (charts []HelmChart, globals HelmGlobals) { + for _, old := range oldArgs { + charts = append(charts, makeHelmChartFromHca(&old)) + if old.HelmHome != "" { + // last non-empty wins + globals.ConfigHome = old.HelmHome + } + if old.ChartHome != "" { + // last non-empty wins + globals.ChartHome = old.ChartHome + } + } + return charts, globals +} + +func makeHelmChartFromHca(old *HelmChartArgs) (c HelmChart) { + c.Name = old.ChartName + c.Version = old.ChartVersion + c.Repo = old.ChartRepoURL + c.ValuesFile = old.Values + c.ValuesInline = old.ValuesLocal + c.ValuesMerge = old.ValuesMerge + c.ReleaseName = old.ReleaseName + return +} diff --git a/vendor/sigs.k8s.io/kustomize/api/types/iampolicygenerator.go b/vendor/sigs.k8s.io/kustomize/api/types/iampolicygenerator.go new file mode 100644 index 00000000000..f1d27ba7b71 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/types/iampolicygenerator.go @@ -0,0 +1,36 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +type Cloud string + +const GKE Cloud = "gke" + +// IAMPolicyGeneratorArgs contains arguments to generate a GKE service account resource. +type IAMPolicyGeneratorArgs struct { + // which cloud provider to generate for (e.g. "gke") + Cloud `json:"cloud" yaml:"cloud"` + + // information about the kubernetes cluster for this object + KubernetesService `json:"kubernetesService" yaml:"kubernetesService"` + + // information about the service account and project + ServiceAccount `json:"serviceAccount" yaml:"serviceAccount"` +} + +type KubernetesService struct { + // the name used for the Kubernetes service account + Name string `json:"name" yaml:"name"` + + // the name of the Kubernetes namespace for this object + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` +} + +type ServiceAccount struct { + // the name of the new cloud provider service account + Name string `json:"name" yaml:"name"` + + // The ID of the project + ProjectId string `json:"projectId" yaml:"projectId"` +} diff --git a/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go b/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go index 30f0e4b2e57..8f4b45d1c82 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go @@ -6,6 +6,7 @@ package types import ( "bytes" "encoding/json" + "fmt" "sigs.k8s.io/yaml" ) @@ -46,6 +47,9 @@ type Kustomization struct { // CommonLabels to add to all objects and selectors. CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"` + // Labels to add to all objects but not selectors. + Labels []Label `json:"labels,omitempty" yaml:"labels,omitempty"` + // CommonAnnotations to add to all objects. CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"` @@ -70,6 +74,10 @@ type Kustomization struct { // patch, but this operator is simpler to specify. Images []Image `json:"images,omitempty" yaml:"images,omitempty"` + // Replacements is a list of replacements, which will copy nodes from a + // specified source to N specified targets. + Replacements []ReplacementField `json:"replacements,omitempty" yaml:"replacements,omitempty"` + // Replicas is a list of {resourcename, count} that allows for simpler replica // specification. This can also be done with a patch. Replicas []Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"` @@ -125,9 +133,14 @@ type Kustomization struct { // the map will have a suffix hash generated from its contents. SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"` + // HelmGlobals contains helm configuration that isn't chart specific. + HelmGlobals *HelmGlobals `json:"helmGlobals,omitempty" yaml:"helmGlobals,omitempty"` + + // HelmCharts is a list of helm chart configuration instances. + HelmCharts []HelmChart `json:"helmCharts,omitempty" yaml:"helmCharts,omitempty"` + // HelmChartInflationGenerator is a list of helm chart configurations. - // The resulting resource is a normal operand rendered from - // a remote chart by `helm template` + // Deprecated. Auto-converted to HelmGlobals and HelmCharts. HelmChartInflationGenerator []HelmChartArgs `json:"helmChartInflationGenerator,omitempty" yaml:"helmChartInflationGenerator,omitempty"` // GeneratorOptions modify behavior of all ConfigMap and Secret generators. @@ -181,15 +194,42 @@ func (k *Kustomization) FixKustomizationPostUnmarshalling() { k.SecretGenerator[i].EnvSource = "" } } + charts, globals := SplitHelmParameters(k.HelmChartInflationGenerator) + if k.HelmGlobals == nil { + if globals.ChartHome != "" || globals.ConfigHome != "" { + k.HelmGlobals = &globals + } + } + k.HelmCharts = append(k.HelmCharts, charts...) + // Wipe it for the fix command. + k.HelmChartInflationGenerator = nil } // FixKustomizationPreMarshalling fixes things // that should occur after the kustomization file // has been processed. -func (k *Kustomization) FixKustomizationPreMarshalling() { +func (k *Kustomization) FixKustomizationPreMarshalling() error { // PatchesJson6902 should be under the Patches field. k.Patches = append(k.Patches, k.PatchesJson6902...) k.PatchesJson6902 = nil + + // this fix is not in FixKustomizationPostUnmarshalling because + // it will break some commands like `create` and `add`. those + // commands depend on 'commonLabels' field + if cl := labelFromCommonLabels(k.CommonLabels); cl != nil { + // check conflicts between commonLabels and labels + for _, l := range k.Labels { + for k := range l.Pairs { + if _, exist := cl.Pairs[k]; exist { + return fmt.Errorf("label name '%s' exists in both commonLabels and labels", k) + } + } + } + k.Labels = append(k.Labels, *cl) + k.CommonLabels = nil + } + + return nil } func (k *Kustomization) EnforceFields() []string { diff --git a/vendor/sigs.k8s.io/kustomize/api/types/labels.go b/vendor/sigs.k8s.io/kustomize/api/types/labels.go new file mode 100644 index 00000000000..e2a2aee7894 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/types/labels.go @@ -0,0 +1,25 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +type Label struct { + // Pairs contains the key-value pairs for labels to add + Pairs map[string]string `json:"pairs,omitempty" yaml:"pairs,omitempty"` + // IncludeSelectors inidicates should transformer include the + // fieldSpecs for selectors. Custom fieldSpecs specified by + // FieldSpecs will be merged with builtin fieldSpecs if this + // is true. + IncludeSelectors bool `json:"includeSelectors,omitempty" yaml:"includeSelectors,omitempty"` + FieldSpecs []FieldSpec `json:"fields,omitempty" yaml:"fields,omitempty"` +} + +func labelFromCommonLabels(commonLabels map[string]string) *Label { + if len(commonLabels) == 0 { + return nil + } + return &Label{ + Pairs: commonLabels, + IncludeSelectors: true, + } +} diff --git a/vendor/sigs.k8s.io/kustomize/api/types/patch.go b/vendor/sigs.k8s.io/kustomize/api/types/patch.go index 48b521d7e87..5310a6e66db 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/patch.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/patch.go @@ -3,6 +3,8 @@ package types +import "reflect" + // Patch represent either a Strategic Merge Patch or a JSON patch // and its targets. // The content of the patch can either be from a file @@ -16,6 +18,9 @@ type Patch struct { // Target points to the resources that the patch is applied to Target *Selector `json:"target,omitempty" yaml:"target,omitempty"` + + // Options is a list of options for the patch + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } // Equals return true if p equals o. @@ -24,5 +29,6 @@ func (p *Patch) Equals(o Patch) bool { (p.Target != nil && o.Target != nil && *p.Target == *o.Target) return p.Path == o.Path && p.Patch == o.Patch && - targetEqual + targetEqual && + reflect.DeepEqual(p.Options, o.Options) } diff --git a/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go b/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go index 2756f982681..741e5debc46 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go @@ -3,27 +3,13 @@ package types +type HelmConfig struct { + Enabled bool + Command string +} + // PluginConfig holds plugin configuration. type PluginConfig struct { - // AbsPluginHome is the home of kustomize plugins. - // Kustomize plugin configuration files are k8s-style objects - // containing the fields 'apiVersion' and 'kind', e.g. - // apiVersion: apps/v1 - // kind: Deployment - // kustomize reads plugin configuration data from a file path - // specified in the 'generators:' or 'transformers:' field of a - // kustomization file. kustomize must then use this data to both - // locate the plugin and configure it. - // Every kustomize plugin (its code, its tests, its supporting data - // files, etc.) must be housed in its own directory at - // ${AbsPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind}) - // where - // - ${AbsPluginHome} is an absolute path, defined below. - // - ${pluginApiVersion} is taken from the plugin config file. - // - ${pluginKind} is taken from the plugin config file. - // The value of AbsPluginHome can be any absolute path. - AbsPluginHome string - // PluginRestrictions distinguishes plugin restrictions. PluginRestrictions PluginRestrictions @@ -32,4 +18,30 @@ type PluginConfig struct { // FnpLoadingOptions sets the way function-based plugin behaviors. FnpLoadingOptions FnPluginLoadingOptions + + // HelmConfig contains metadata needed for allowing and running helm. + HelmConfig HelmConfig +} + +func EnabledPluginConfig(b BuiltinPluginLoadingOptions) (pc *PluginConfig) { + pc = MakePluginConfig(PluginRestrictionsNone, b) + pc.FnpLoadingOptions.EnableStar = true + pc.HelmConfig.Enabled = true + // If this command is not on PATH, tests needing it should skip. + pc.HelmConfig.Command = "helmV3" + return +} + +func DisabledPluginConfig() *PluginConfig { + return MakePluginConfig( + PluginRestrictionsBuiltinsOnly, + BploUseStaticallyLinked) +} + +func MakePluginConfig(pr PluginRestrictions, + b BuiltinPluginLoadingOptions) *PluginConfig { + return &PluginConfig{ + PluginRestrictions: pr, + BpLoadingOptions: b, + } } diff --git a/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go b/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go index 6dae63a97a1..b1ab2221f69 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go @@ -42,7 +42,7 @@ const ( BploLoadFromFileSys ) -// FnPluginLoadingOptions set way functions-based pluing are restricted +// FnPluginLoadingOptions set way functions-based plugins are restricted type FnPluginLoadingOptions struct { // Allow to run executables EnableExec bool @@ -55,4 +55,6 @@ type FnPluginLoadingOptions struct { Mounts []string // list of env variables to pass to fn Env []string + // Run as uid and gid of the command executor + AsCurrentUser bool } diff --git a/vendor/sigs.k8s.io/kustomize/api/types/replacement.go b/vendor/sigs.k8s.io/kustomize/api/types/replacement.go index 57c2507ada7..1f59239d9ae 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/replacement.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/replacement.go @@ -1,27 +1,87 @@ -// Copyright 2019 The Kubernetes Authors. +// Copyright 2021 The Kubernetes Authors. // SPDX-License-Identifier: Apache-2.0 package types +import ( + "fmt" + "strings" + + "sigs.k8s.io/kustomize/kyaml/resid" +) + +const DefaultReplacementFieldPath = "metadata.name" + // Replacement defines how to perform a substitution // where it is from and where it is to. type Replacement struct { - Source *ReplSource `json:"source" yaml:"source"` - Target *ReplTarget `json:"target" yaml:"target"` + // The source of the value. + Source *SourceSelector `json:"source" yaml:"source"` + + // The N fields to write the value to. + Targets []*TargetSelector `json:"targets" yaml:"targets"` +} + +// SourceSelector is the source of the replacement transformer. +type SourceSelector struct { + // A specific object to read it from. + resid.ResId `json:",inline,omitempty" yaml:",inline,omitempty"` + + // Structured field path expected in the allowed object. + FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"` + + // Used to refine the interpretation of the field. + Options *FieldOptions `json:"options,omitempty" yaml:"options,omitempty"` +} + +func (s *SourceSelector) String() string { + if s == nil { + return "" + } + result := []string{s.ResId.String()} + if s.FieldPath != "" { + result = append(result, s.FieldPath) + } + if opts := s.Options.String(); opts != "" { + result = append(result, opts) + } + return strings.Join(result, ":") } -// ReplSource defines where a substitution is from -// It can from two different kinds of sources -// - from a field of one resource -// - from a string -type ReplSource struct { - ObjRef *Target `json:"objref,omitempty" yaml:"objref,omitempty"` - FieldRef string `json:"fieldref,omitempty" yaml:"fiedldref,omitempty"` - Value string `json:"value,omitempty" yaml:"value,omitempty"` +// TargetSelector specifies fields in one or more objects. +type TargetSelector struct { + // Include objects that match this. + Select *Selector `json:"select" yaml:"select"` + + // From the allowed set, remove objects that match this. + Reject []*Selector `json:"reject,omitempty" yaml:"reject,omitempty"` + + // Structured field paths expected in each allowed object. + FieldPaths []string `json:"fieldPaths,omitempty" yaml:"fieldPaths,omitempty"` + + // Used to refine the interpretation of the field. + Options *FieldOptions `json:"options,omitempty" yaml:"options,omitempty"` +} + +// FieldOptions refine the interpretation of FieldPaths. +type FieldOptions struct { + // Used to split/join the field. + Delimiter string `json:"delimiter,omitempty" yaml:"delimiter,omitempty"` + + // Which position in the split to consider. + Index int `json:"index,omitempty" yaml:"index,omitempty"` + + // TODO (#3492): Implement use of this option + // None, Base64, URL, Hex, etc + Encoding string `json:"encoding,omitempty" yaml:"encoding,omitempty"` + + // If field missing, add it. + Create bool `json:"create,omitempty" yaml:"create,omitempty"` } -// ReplTarget defines where a substitution is to. -type ReplTarget struct { - ObjRef *Selector `json:"objref,omitempty" yaml:"objref,omitempty"` - FieldRefs []string `json:"fieldrefs,omitempty" yaml:"fieldrefs,omitempty"` +func (fo *FieldOptions) String() string { + if fo == nil || (fo.Delimiter == "" && !fo.Create) { + return "" + } + return fmt.Sprintf("%s(%d), create=%t", fo.Delimiter, fo.Index, fo.Create) } diff --git a/vendor/sigs.k8s.io/kustomize/api/types/replacementfield.go b/vendor/sigs.k8s.io/kustomize/api/types/replacementfield.go new file mode 100644 index 00000000000..a5684f8486c --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/api/types/replacementfield.go @@ -0,0 +1,6 @@ +package types + +type ReplacementField struct { + Replacement `json:",inline,omitempty" yaml:",inline,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` +} diff --git a/vendor/sigs.k8s.io/kustomize/api/types/selector.go b/vendor/sigs.k8s.io/kustomize/api/types/selector.go index 007b508f131..2c07f0b01b8 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/selector.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/selector.go @@ -4,18 +4,18 @@ package types import ( + "fmt" "regexp" - "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/kyaml/resid" ) // Selector specifies a set of resources. // Any resource that matches intersection of all conditions // is included in this set. type Selector struct { - resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` + // ResId refers to a GVKN/Ns of a resource. + resid.ResId `json:",inline,omitempty" yaml:",inline,omitempty"` // AnnotationSelector is a string that follows the label selection expression // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api @@ -28,6 +28,15 @@ type Selector struct { LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"` } +func (s *Selector) Copy() Selector { + return *s +} + +func (s *Selector) String() string { + return fmt.Sprintf( + "%s:a=%s:l=%s", s.ResId, s.AnnotationSelector, s.LabelSelector) +} + // SelectorRegex is a Selector with regex in GVK // Any resource that matches intersection of all conditions // is included in this set. diff --git a/vendor/sigs.k8s.io/kustomize/api/types/var.go b/vendor/sigs.k8s.io/kustomize/api/types/var.go index f636d0d35bb..0ca5579c0df 100644 --- a/vendor/sigs.k8s.io/kustomize/api/types/var.go +++ b/vendor/sigs.k8s.io/kustomize/api/types/var.go @@ -9,11 +9,9 @@ import ( "sort" "strings" - "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/kyaml/resid" ) -const defaultFieldPath = "metadata.name" - // Var represents a variable whose value will be sourced // from a field in a Kubernetes object. type Var struct { @@ -71,7 +69,7 @@ type FieldSelector struct { // defaulting sets reference to field used by default. func (v *Var) Defaulting() { if v.FieldRef.FieldPath == "" { - v.FieldRef.FieldPath = defaultFieldPath + v.FieldRef.FieldPath = DefaultReplacementFieldPath } v.ObjRef.GVK() } diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/comments/comments.go b/vendor/sigs.k8s.io/kustomize/kyaml/comments/comments.go index 9d6dc22dc4a..0dfc4d8de8f 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/comments/comments.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/comments/comments.go @@ -54,7 +54,10 @@ func (c *copier) VisitList(s walk.Sources, _ *openapi.ResourceSchema, _ walk.Lis origin := originItems[i] if dest.Value == origin.Value { - copy(yaml.NewRNode(dest), yaml.NewRNode(origin)) + // We copy the comments recursively on each node in the list. + if err := CopyComments(yaml.NewRNode(dest), yaml.NewRNode(origin)); err != nil { + return nil, err + } } } diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/fieldmeta/fieldmeta.go b/vendor/sigs.k8s.io/kustomize/kyaml/fieldmeta/fieldmeta.go index 83fdff3d5b8..c537c337259 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/fieldmeta/fieldmeta.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/fieldmeta/fieldmeta.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "github.com/go-openapi/spec" + "k8s.io/kube-openapi/pkg/validation/spec" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/yaml" diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/confirmeddir.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/confirmeddir.go similarity index 100% rename from vendor/sigs.k8s.io/kustomize/api/filesys/confirmeddir.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/confirmeddir.go diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/filesys/doc.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/doc.go new file mode 100644 index 00000000000..bd39634416b --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/doc.go @@ -0,0 +1,7 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package filesys provides a file system abstraction, +// a subset of that provided by golang.org/pkg/os, +// with an on-disk and in-memory representation. +package filesys diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/file.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/file.go similarity index 100% rename from vendor/sigs.k8s.io/kustomize/api/filesys/file.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/file.go diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/fileinfo.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/fileinfo.go similarity index 100% rename from vendor/sigs.k8s.io/kustomize/api/filesys/fileinfo.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/fileinfo.go diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/fileondisk.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/fileondisk.go similarity index 100% rename from vendor/sigs.k8s.io/kustomize/api/filesys/fileondisk.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/fileondisk.go diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/filesys/filesystem.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/filesystem.go new file mode 100644 index 00000000000..53e0f1921ec --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/filesystem.go @@ -0,0 +1,120 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package filesys + +import ( + "path/filepath" +) + +const ( + Separator = string(filepath.Separator) + SelfDir = "." + ParentDir = ".." +) + +// FileSystem groups basic os filesystem methods. +// It's supposed be functional subset of https://golang.org/pkg/os +type FileSystem interface { + // Create a file. + Create(path string) (File, error) + // MkDir makes a directory. + Mkdir(path string) error + // MkDirAll makes a directory path, creating intervening directories. + MkdirAll(path string) error + // RemoveAll removes path and any children it contains. + RemoveAll(path string) error + // Open opens the named file for reading. + Open(path string) (File, error) + // IsDir returns true if the path is a directory. + IsDir(path string) bool + // ReadDir returns a list of files and directories within a directory. + ReadDir(path string) ([]string, error) + // CleanedAbs converts the given path into a + // directory and a file name, where the directory + // is represented as a ConfirmedDir and all that implies. + // If the entire path is a directory, the file component + // is an empty string. + CleanedAbs(path string) (ConfirmedDir, string, error) + // Exists is true if the path exists in the file system. + Exists(path string) bool + // Glob returns the list of matching files, + // emulating https://golang.org/pkg/path/filepath/#Glob + Glob(pattern string) ([]string, error) + // ReadFile returns the contents of the file at the given path. + ReadFile(path string) ([]byte, error) + // WriteFile writes the data to a file at the given path, + // overwriting anything that's already there. + WriteFile(path string, data []byte) error + // Walk walks the file system with the given WalkFunc. + Walk(path string, walkFn filepath.WalkFunc) error +} + +// FileSystemOrOnDisk satisfies the FileSystem interface by forwarding +// all of its method calls to the given FileSystem whenever it's not nil. +// If it's nil, the call is forwarded to the OS's underlying file system. +type FileSystemOrOnDisk struct { + FileSystem FileSystem +} + +// Set sets the given FileSystem as the target for all the FileSystem method calls. +func (fs *FileSystemOrOnDisk) Set(f FileSystem) { fs.FileSystem = f } + +func (fs FileSystemOrOnDisk) fs() FileSystem { + if fs.FileSystem != nil { + return fs.FileSystem + } + return MakeFsOnDisk() +} + +func (fs FileSystemOrOnDisk) Create(path string) (File, error) { + return fs.fs().Create(path) +} + +func (fs FileSystemOrOnDisk) Mkdir(path string) error { + return fs.fs().Mkdir(path) +} + +func (fs FileSystemOrOnDisk) MkdirAll(path string) error { + return fs.fs().MkdirAll(path) +} + +func (fs FileSystemOrOnDisk) RemoveAll(path string) error { + return fs.fs().RemoveAll(path) +} + +func (fs FileSystemOrOnDisk) Open(path string) (File, error) { + return fs.fs().Open(path) +} + +func (fs FileSystemOrOnDisk) IsDir(path string) bool { + return fs.fs().IsDir(path) +} + +func (fs FileSystemOrOnDisk) ReadDir(path string) ([]string, error) { + return fs.fs().ReadDir(path) +} + +func (fs FileSystemOrOnDisk) CleanedAbs(path string) (ConfirmedDir, string, error) { + return fs.fs().CleanedAbs(path) +} + +func (fs FileSystemOrOnDisk) Exists(path string) bool { + return fs.fs().Exists(path) +} + +func (fs FileSystemOrOnDisk) Glob(pattern string) ([]string, error) { + return fs.fs().Glob(pattern) +} + +func (fs FileSystemOrOnDisk) ReadFile(path string) ([]byte, error) { + return fs.fs().ReadFile(path) +} + +func (fs FileSystemOrOnDisk) WriteFile(path string, data []byte) error { + return fs.fs().WriteFile(path, data) +} + +func (fs FileSystemOrOnDisk) Walk(path string, walkFn filepath.WalkFunc) error { + return fs.fs().Walk(path, walkFn) +} diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/fsnode.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/fsnode.go similarity index 80% rename from vendor/sigs.k8s.io/kustomize/api/filesys/fsnode.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/fsnode.go index e81c3df7881..fbede9ed7d9 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filesys/fsnode.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/fsnode.go @@ -6,6 +6,7 @@ package filesys import ( "bytes" "fmt" + "io" "log" "os" "path/filepath" @@ -37,9 +38,9 @@ type fsNode struct { // if this node is a file, this is the content. content []byte - // if this node is a file, this tracks whether or - // not it is "open". - open bool + // if offset is not nil the file is open and it tracks + // the current file offset. + offset *int } // MakeEmptyDirInMemory returns an empty directory. @@ -119,6 +120,9 @@ func (n *fsNode) addFile(name string, c []byte) (result *fsNode, err error) { result, ok := parent.dir[fileName] if ok { // File already exists; overwrite it. + if result.offset != nil { + return nil, fmt.Errorf("cannot add already opened file '%s'", n.Path()) + } result.content = c return result, nil } @@ -133,7 +137,12 @@ func (n *fsNode) addFile(name string, c []byte) (result *fsNode, err error) { // Create implements FileSystem. // Create makes an empty file. func (n *fsNode) Create(path string) (result File, err error) { - return n.AddFile(path, []byte{}) + f, err := n.AddFile(path, nil) + if err != nil { + return f, err + } + f.offset = new(int) + return f, nil } // WriteFile implements FileSystem. @@ -154,6 +163,7 @@ func (n *fsNode) AddFile( } func (n *fsNode) addDir(path string) (result *fsNode, err error) { + parent := n dName, subDirName := mySplit(path) if dName != "" { @@ -226,7 +236,7 @@ func (n *fsNode) CleanedAbs(path string) (ConfirmedDir, string, error) { return "", "", errors.Wrap(err, "unable to clean") } if node == nil { - return "", "", fmt.Errorf("'%s' doesn't exist", path) + return "", "", notExistError(path) } if node.isNodeADir() { return ConfirmedDir(node.Path()), "", nil @@ -299,7 +309,8 @@ func (n *fsNode) RemoveAll(path string) error { return err } if result == nil { - return fmt.Errorf("cannot find '%s' to remove it", path) + // If the path doesn't exist, no need to remove anything. + return nil } return result.Remove() } @@ -339,6 +350,32 @@ func (n *fsNode) IsDir(path string) bool { return result.isNodeADir() } +// ReadDir implements FileSystem. +func (n *fsNode) ReadDir(path string) ([]string, error) { + if !n.Exists(path) { + return nil, notExistError(path) + } + if !n.IsDir(path) { + return nil, fmt.Errorf("%s is not a directory", path) + } + + dir, err := n.Find(path) + if err != nil { + return nil, err + } + if dir == nil { + return nil, fmt.Errorf("could not find directory %s", path) + } + + keys := make([]string, len(dir.dir)) + i := 0 + for k := range dir.dir { + keys[i] = k + i++ + } + return keys, nil +} + // Size returns the size of the node. func (n *fsNode) Size() int64 { if n.isNodeADir() { @@ -348,22 +385,38 @@ func (n *fsNode) Size() int64 { } // Open implements FileSystem. -// Open opens the node for reading (just marks it). +// Open opens the node in read-write mode and sets the offset its start. +// Writing right after opening the file will replace the original content +// and move the offset forward, as with a file opened with O_RDWR | O_CREATE. +// +// As an example, let's consider a file with content "content": +// - open: sets offset to start, content is "content" +// - write "@": offset increases by one, the content is now "@ontent" +// - read the rest: since offset is 1, the read operation returns "ontent" +// - write "$": offset is at EOF, so "$" is appended and content is now "@ontent$" +// - read the rest: returns 0 bytes and EOF +// - close: the content is still "@ontent$" func (n *fsNode) Open(path string) (File, error) { result, err := n.Find(path) if err != nil { return nil, err } if result == nil { - return nil, fmt.Errorf("cannot find '%s' to open it", path) + return nil, notExistError(path) + } + if result.offset != nil { + return nil, fmt.Errorf("cannot open previously opened file '%s'", path) } - result.open = true + result.offset = new(int) return result, nil } // Close marks the node closed. func (n *fsNode) Close() error { - n.open = false + if n.offset == nil { + return fmt.Errorf("cannot close already closed file '%s'", n.Path()) + } + n.offset = nil return nil } @@ -374,11 +427,14 @@ func (n *fsNode) ReadFile(path string) (c []byte, err error) { return nil, err } if result == nil { - return nil, fmt.Errorf("cannot find '%s' to read it", path) + return nil, notExistError(path) + } + if result.isNodeADir() { + return nil, fmt.Errorf("cannot read content from non-file '%s'", n.Path()) } c = make([]byte, len(result.content)) - _, err = result.Read(c) - return c, err + copy(c, result.content) + return c, nil } // Read returns the content of the file node. @@ -387,7 +443,19 @@ func (n *fsNode) Read(d []byte) (c int, err error) { return 0, fmt.Errorf( "cannot read content from non-file '%s'", n.Path()) } - return copy(d, n.content), nil + if n.offset == nil { + return 0, fmt.Errorf("cannot read from closed file '%s'", n.Path()) + } + + rest := n.content[*n.offset:] + if len(d) < len(rest) { + rest = rest[:len(d)] + } else { + err = io.EOF + } + copy(d, rest) + *n.offset += len(rest) + return len(rest), err } // Write saves the contents of the argument to the file node. @@ -396,8 +464,12 @@ func (n *fsNode) Write(p []byte) (c int, err error) { return 0, fmt.Errorf( "cannot write content to non-file '%s'", n.Path()) } - n.content = make([]byte, len(p)) - return copy(n.content, p), nil + if n.offset == nil { + return 0, fmt.Errorf("cannot write to closed file '%s'", n.Path()) + } + n.content = append(n.content[:*n.offset], p...) + *n.offset = len(n.content) + return len(p), nil } // ContentMatches returns true if v matches fake file's content. @@ -422,7 +494,7 @@ func (n *fsNode) Walk(path string, walkFn filepath.WalkFunc) error { return err } if result == nil { - return fmt.Errorf("cannot find '%s' to walk it", path) + return notExistError(path) } return result.WalkMe(walkFn) } @@ -515,7 +587,7 @@ func isLegalFileNameForCreation(n string) bool { func (n *fsNode) RegExpGlob(pattern string) ([]string, error) { var result []string var expression = regexp.MustCompile(pattern) - n.WalkMe(func(path string, info os.FileInfo, err error) error { + err := n.WalkMe(func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -526,6 +598,9 @@ func (n *fsNode) RegExpGlob(pattern string) ([]string, error) { } return nil }) + if err != nil { + return nil, err + } sort.Strings(result) return result, nil } @@ -537,7 +612,7 @@ func (n *fsNode) RegExpGlob(pattern string) ([]string, error) { // This is how /bin/ls behaves. func (n *fsNode) Glob(pattern string) ([]string, error) { var result []string - n.WalkMe(func(path string, info os.FileInfo, err error) error { + err := n.WalkMe(func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -552,6 +627,16 @@ func (n *fsNode) Glob(pattern string) ([]string, error) { } return nil }) + if err != nil { + return nil, err + } sort.Strings(result) return result, nil } + +// notExistError indicates that a file or directory does not exist. +// Unwrapping returns os.ErrNotExist so errors.Is(err, os.ErrNotExist) works correctly. +type notExistError string + +func (err notExistError) Error() string { return fmt.Sprintf("'%s' doesn't exist", string(err)) } +func (err notExistError) Unwrap() error { return os.ErrNotExist } diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/fsondisk.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/fsondisk.go similarity index 89% rename from vendor/sigs.k8s.io/kustomize/api/filesys/fsondisk.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/fsondisk.go index 6becbb6f132..d5c07f381c0 100644 --- a/vendor/sigs.k8s.io/kustomize/api/filesys/fsondisk.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/fsondisk.go @@ -57,7 +57,7 @@ func (x fsOnDisk) CleanedAbs( deLinked, err := filepath.EvalSymlinks(absRoot) if err != nil { return "", "", fmt.Errorf( - "evalsymlink failure on '%s' : %v", path, err) + "evalsymlink failure on '%s' : %w", path, err) } if x.IsDir(deLinked) { return ConfirmedDir(deLinked), "", nil @@ -100,6 +100,19 @@ func (fsOnDisk) IsDir(name string) bool { return info.IsDir() } +// ReadDir delegates to os.ReadDir +func (fsOnDisk) ReadDir(name string) ([]string, error) { + dirEntries, err := os.ReadDir(name) + if err != nil { + return nil, err + } + result := make([]string, len(dirEntries)) + for i := range dirEntries { + result[i] = dirEntries[i].Name() + } + return result, nil +} + // ReadFile delegates to ioutil.ReadFile. func (fsOnDisk) ReadFile(name string) ([]byte, error) { return ioutil.ReadFile(name) } diff --git a/vendor/sigs.k8s.io/kustomize/api/filesys/util.go b/vendor/sigs.k8s.io/kustomize/kyaml/filesys/util.go similarity index 100% rename from vendor/sigs.k8s.io/kustomize/api/filesys/util.go rename to vendor/sigs.k8s.io/kustomize/kyaml/filesys/util.go diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/filtersutil/doc.go b/vendor/sigs.k8s.io/kustomize/kyaml/filtersutil/doc.go deleted file mode 100644 index b5cb975fa29..00000000000 --- a/vendor/sigs.k8s.io/kustomize/kyaml/filtersutil/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -// Package filtersutil provides utilities for working with yaml.Filter and -// kio.Filter interfaces. -package filtersutil diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/filtersutil/filtersutil.go b/vendor/sigs.k8s.io/kustomize/kyaml/filtersutil/filtersutil.go deleted file mode 100644 index 80e4505ada5..00000000000 --- a/vendor/sigs.k8s.io/kustomize/kyaml/filtersutil/filtersutil.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filtersutil - -import ( - "encoding/json" - - "sigs.k8s.io/kustomize/kyaml/errors" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// ApplyToJSON applies the filter to the json objects. -// -// ApplyToJSON marshals the objects into a slice of yaml.RNodes, runs -// the filter on the slice, and then unmarshals the values back. -// -// The filter must not create or delete objects because the objects -// are updated in place. -func ApplyToJSON(filter kio.Filter, objs ...marshalerUnmarshaler) error { - var nodes []*yaml.RNode - - // convert the json objects to rnodes - for i := range objs { - node, err := GetRNode(objs[i]) - if err != nil { - return err - } - nodes = append(nodes, node) - } - - // apply the filter - nodes, err := filter.Filter(nodes) - if err != nil { - return err - } - if len(nodes) != len(objs) { - return errors.Errorf("filter cannot create or delete objects") - } - - // convert the rnodes to json objects - for i := range nodes { - err = setRNode(objs[i], nodes[i]) - if err != nil { - return err - } - } - - return nil -} - -type marshalerUnmarshaler interface { - json.Unmarshaler - json.Marshaler -} - -// GetRNode converts k into an RNode -func GetRNode(k json.Marshaler) (*yaml.RNode, error) { - j, err := k.MarshalJSON() - if err != nil { - return nil, err - } - return yaml.Parse(string(j)) -} - -// setRNode marshals node into k -func setRNode(k json.Unmarshaler, node *yaml.RNode) error { - s, err := node.String() - if err != nil { - return err - } - m := map[string]interface{}{} - if err := yaml.Unmarshal([]byte(s), &m); err != nil { - return err - } - - b, err := json.Marshal(m) - if err != nil { - return err - } - return k.UnmarshalJSON(b) -} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/runtimeutil.go b/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/runtimeutil.go index 29e2ea0adf9..2454aa4cb25 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/runtimeutil.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/runtimeutil.go @@ -42,7 +42,7 @@ type FunctionFilter struct { DeferFailure bool // results saves the results emitted from Run - results *yaml.RNode + Results *yaml.RNode // exit saves the error returned from Run exit error @@ -250,7 +250,7 @@ func (c *FunctionFilter) doResults(r *kio.ByteReader) error { } if r.Results != nil { - c.results = r.Results + c.Results = r.Results } return nil } diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/LICENSE b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/LICENSE new file mode 100644 index 00000000000..2683e4bb1f2 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/LICENSE @@ -0,0 +1,50 @@ + +This project is covered by two different licenses: MIT and Apache. + +#### MIT License #### + +The following files were ported to Go from C files of libyaml, and thus +are still covered by their original MIT license, with the additional +copyright staring in 2011 when the project was ported over: + + apic.go emitterc.go parserc.go readerc.go scannerc.go + writerc.go yamlh.go yamlprivateh.go + +Copyright (c) 2006-2010 Kirill Simonov +Copyright (c) 2006-2011 Kirill Simonov + +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. + +### Apache License ### + +All the remaining project files are covered by the Apache license: + +Copyright (c) 2011-2019 Canonical Ltd + +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/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/NOTICE b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/NOTICE new file mode 100644 index 00000000000..866d74a7ad7 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/NOTICE @@ -0,0 +1,13 @@ +Copyright 2011-2016 Canonical Ltd. + +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/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/README.md b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/README.md new file mode 100644 index 00000000000..08eb1babddf --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/README.md @@ -0,0 +1,150 @@ +# YAML support for the Go language + +Introduction +------------ + +The yaml package enables Go programs to comfortably encode and decode YAML +values. It was developed within [Canonical](https://www.canonical.com) as +part of the [juju](https://juju.ubuntu.com) project, and is based on a +pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) +C library to parse and generate YAML data quickly and reliably. + +Compatibility +------------- + +The yaml package supports most of YAML 1.2, but preserves some behavior +from 1.1 for backwards compatibility. + +Specifically, as of v3 of the yaml package: + + - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being + decoded into a typed bool value. Otherwise they behave as a string. Booleans + in YAML 1.2 are _true/false_ only. + - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_ + as specified in YAML 1.2, because most parsers still use the old format. + Octals in the _0o777_ format are supported though, so new files work. + - Does not support base-60 floats. These are gone from YAML 1.2, and were + actually never supported by this package as it's clearly a poor choice. + +and offers backwards +compatibility with YAML 1.1 in some cases. +1.2, including support for +anchors, tags, map merging, etc. Multi-document unmarshalling is not yet +implemented, and base-60 floats from YAML 1.1 are purposefully not +supported since they're a poor design and are gone in YAML 1.2. + +Installation and usage +---------------------- + +The import path for the package is *gopkg.in/yaml.v3*. + +To install it, run: + + go get gopkg.in/yaml.v3 + +API documentation +----------------- + +If opened in a browser, the import path itself leads to the API documentation: + + - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) + +API stability +------------- + +The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in). + + +License +------- + +The yaml package is licensed under the MIT and Apache License 2.0 licenses. +Please see the LICENSE file for details. + + +Example +------- + +```Go +package main + +import ( + "fmt" + "log" + + "gopkg.in/yaml.v3" +) + +var data = ` +a: Easy! +b: + c: 2 + 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 { + RenamedC int `yaml:"c"` + D []int `yaml:",flow"` + } +} + +func main() { + t := T{} + + err := yaml.Unmarshal([]byte(data), &t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t:\n%v\n\n", t) + + d, err := yaml.Marshal(&t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t dump:\n%s\n\n", string(d)) + + m := make(map[interface{}]interface{}) + + err = yaml.Unmarshal([]byte(data), &m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m:\n%v\n\n", m) + + d, err = yaml.Marshal(&m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m dump:\n%s\n\n", string(d)) +} +``` + +This example will generate the following output: + +``` +--- t: +{Easy! {2 [3 4]}} + +--- t dump: +a: Easy! +b: + c: 2 + d: [3, 4] + + +--- m: +map[a:Easy! b:map[c:2 d:[3 4]]] + +--- m dump: +a: Easy! +b: + c: 2 + d: + - 3 + - 4 +``` + diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/apic.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/apic.go new file mode 100644 index 00000000000..ae7d049f182 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/apic.go @@ -0,0 +1,747 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +import ( + "io" +) + +func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { + //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) + + // Check if we can move the queue at the beginning of the buffer. + if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { + if parser.tokens_head != len(parser.tokens) { + copy(parser.tokens, parser.tokens[parser.tokens_head:]) + } + parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] + parser.tokens_head = 0 + } + parser.tokens = append(parser.tokens, *token) + if pos < 0 { + return + } + copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) + parser.tokens[parser.tokens_head+pos] = *token +} + +// Create a new parser object. +func yaml_parser_initialize(parser *yaml_parser_t) bool { + *parser = yaml_parser_t{ + raw_buffer: make([]byte, 0, input_raw_buffer_size), + buffer: make([]byte, 0, input_buffer_size), + } + return true +} + +// Destroy a parser object. +func yaml_parser_delete(parser *yaml_parser_t) { + *parser = yaml_parser_t{} +} + +// String read handler. +func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { + if parser.input_pos == len(parser.input) { + return 0, io.EOF + } + n = copy(buffer, parser.input[parser.input_pos:]) + parser.input_pos += n + return n, nil +} + +// Reader read handler. +func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { + return parser.input_reader.Read(buffer) +} + +// Set a string input. +func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { + if parser.read_handler != nil { + panic("must set the input source only once") + } + parser.read_handler = yaml_string_read_handler + parser.input = input + parser.input_pos = 0 +} + +// Set a file input. +func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { + if parser.read_handler != nil { + panic("must set the input source only once") + } + parser.read_handler = yaml_reader_read_handler + parser.input_reader = r +} + +// Set the source encoding. +func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { + if parser.encoding != yaml_ANY_ENCODING { + panic("must set the encoding only once") + } + parser.encoding = encoding +} + +// Create a new emitter object. +func yaml_emitter_initialize(emitter *yaml_emitter_t) { + *emitter = yaml_emitter_t{ + buffer: make([]byte, output_buffer_size), + raw_buffer: make([]byte, 0, output_raw_buffer_size), + states: make([]yaml_emitter_state_t, 0, initial_stack_size), + events: make([]yaml_event_t, 0, initial_queue_size), + best_width: -1, + } +} + +// Destroy an emitter object. +func yaml_emitter_delete(emitter *yaml_emitter_t) { + *emitter = yaml_emitter_t{} +} + +// String write handler. +func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { + *emitter.output_buffer = append(*emitter.output_buffer, buffer...) + return nil +} + +// yaml_writer_write_handler uses emitter.output_writer to write the +// emitted text. +func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { + _, err := emitter.output_writer.Write(buffer) + return err +} + +// Set a string output. +func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { + if emitter.write_handler != nil { + panic("must set the output target only once") + } + emitter.write_handler = yaml_string_write_handler + emitter.output_buffer = output_buffer +} + +// Set a file output. +func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { + if emitter.write_handler != nil { + panic("must set the output target only once") + } + emitter.write_handler = yaml_writer_write_handler + emitter.output_writer = w +} + +// Set the output encoding. +func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { + if emitter.encoding != yaml_ANY_ENCODING { + panic("must set the output encoding only once") + } + emitter.encoding = encoding +} + +// Set the canonical output style. +func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { + emitter.canonical = canonical +} + +// Set the indentation increment. +func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { + if indent < 2 || indent > 9 { + indent = 2 + } + emitter.best_indent = indent +} + +// Set the preferred line width. +func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { + if width < 0 { + width = -1 + } + emitter.best_width = width +} + +// Set if unescaped non-ASCII characters are allowed. +func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { + emitter.unicode = unicode +} + +// Set the preferred line break character. +func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { + emitter.line_break = line_break +} + +///* +// * Destroy a token object. +// */ +// +//YAML_DECLARE(void) +//yaml_token_delete(yaml_token_t *token) +//{ +// assert(token); // Non-NULL token object expected. +// +// switch (token.type) +// { +// case YAML_TAG_DIRECTIVE_TOKEN: +// yaml_free(token.data.tag_directive.handle); +// yaml_free(token.data.tag_directive.prefix); +// break; +// +// case YAML_ALIAS_TOKEN: +// yaml_free(token.data.alias.value); +// break; +// +// case YAML_ANCHOR_TOKEN: +// yaml_free(token.data.anchor.value); +// break; +// +// case YAML_TAG_TOKEN: +// yaml_free(token.data.tag.handle); +// yaml_free(token.data.tag.suffix); +// break; +// +// case YAML_SCALAR_TOKEN: +// yaml_free(token.data.scalar.value); +// break; +// +// default: +// break; +// } +// +// memset(token, 0, sizeof(yaml_token_t)); +//} +// +///* +// * Check if a string is a valid UTF-8 sequence. +// * +// * Check 'reader.c' for more details on UTF-8 encoding. +// */ +// +//static int +//yaml_check_utf8(yaml_char_t *start, size_t length) +//{ +// yaml_char_t *end = start+length; +// yaml_char_t *pointer = start; +// +// while (pointer < end) { +// unsigned char octet; +// unsigned int width; +// unsigned int value; +// size_t k; +// +// octet = pointer[0]; +// width = (octet & 0x80) == 0x00 ? 1 : +// (octet & 0xE0) == 0xC0 ? 2 : +// (octet & 0xF0) == 0xE0 ? 3 : +// (octet & 0xF8) == 0xF0 ? 4 : 0; +// value = (octet & 0x80) == 0x00 ? octet & 0x7F : +// (octet & 0xE0) == 0xC0 ? octet & 0x1F : +// (octet & 0xF0) == 0xE0 ? octet & 0x0F : +// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; +// if (!width) return 0; +// if (pointer+width > end) return 0; +// for (k = 1; k < width; k ++) { +// octet = pointer[k]; +// if ((octet & 0xC0) != 0x80) return 0; +// value = (value << 6) + (octet & 0x3F); +// } +// if (!((width == 1) || +// (width == 2 && value >= 0x80) || +// (width == 3 && value >= 0x800) || +// (width == 4 && value >= 0x10000))) return 0; +// +// pointer += width; +// } +// +// return 1; +//} +// + +// Create STREAM-START. +func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { + *event = yaml_event_t{ + typ: yaml_STREAM_START_EVENT, + encoding: encoding, + } +} + +// Create STREAM-END. +func yaml_stream_end_event_initialize(event *yaml_event_t) { + *event = yaml_event_t{ + typ: yaml_STREAM_END_EVENT, + } +} + +// Create DOCUMENT-START. +func yaml_document_start_event_initialize( + event *yaml_event_t, + version_directive *yaml_version_directive_t, + tag_directives []yaml_tag_directive_t, + implicit bool, +) { + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + version_directive: version_directive, + tag_directives: tag_directives, + implicit: implicit, + } +} + +// Create DOCUMENT-END. +func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { + *event = yaml_event_t{ + typ: yaml_DOCUMENT_END_EVENT, + implicit: implicit, + } +} + +// Create ALIAS. +func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool { + *event = yaml_event_t{ + typ: yaml_ALIAS_EVENT, + anchor: anchor, + } + return true +} + +// Create SCALAR. +func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + anchor: anchor, + tag: tag, + value: value, + implicit: plain_implicit, + quoted_implicit: quoted_implicit, + style: yaml_style_t(style), + } + return true +} + +// Create SEQUENCE-START. +func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(style), + } + return true +} + +// Create SEQUENCE-END. +func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + } + return true +} + +// Create MAPPING-START. +func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(style), + } +} + +// Create MAPPING-END. +func yaml_mapping_end_event_initialize(event *yaml_event_t) { + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + } +} + +// Destroy an event object. +func yaml_event_delete(event *yaml_event_t) { + *event = yaml_event_t{} +} + +///* +// * Create a document object. +// */ +// +//YAML_DECLARE(int) +//yaml_document_initialize(document *yaml_document_t, +// version_directive *yaml_version_directive_t, +// tag_directives_start *yaml_tag_directive_t, +// tag_directives_end *yaml_tag_directive_t, +// start_implicit int, end_implicit int) +//{ +// struct { +// error yaml_error_type_t +// } context +// struct { +// start *yaml_node_t +// end *yaml_node_t +// top *yaml_node_t +// } nodes = { NULL, NULL, NULL } +// version_directive_copy *yaml_version_directive_t = NULL +// struct { +// start *yaml_tag_directive_t +// end *yaml_tag_directive_t +// top *yaml_tag_directive_t +// } tag_directives_copy = { NULL, NULL, NULL } +// value yaml_tag_directive_t = { NULL, NULL } +// mark yaml_mark_t = { 0, 0, 0 } +// +// assert(document) // Non-NULL document object is expected. +// assert((tag_directives_start && tag_directives_end) || +// (tag_directives_start == tag_directives_end)) +// // Valid tag directives are expected. +// +// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error +// +// if (version_directive) { +// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) +// if (!version_directive_copy) goto error +// version_directive_copy.major = version_directive.major +// version_directive_copy.minor = version_directive.minor +// } +// +// if (tag_directives_start != tag_directives_end) { +// tag_directive *yaml_tag_directive_t +// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) +// goto error +// for (tag_directive = tag_directives_start +// tag_directive != tag_directives_end; tag_directive ++) { +// assert(tag_directive.handle) +// assert(tag_directive.prefix) +// if (!yaml_check_utf8(tag_directive.handle, +// strlen((char *)tag_directive.handle))) +// goto error +// if (!yaml_check_utf8(tag_directive.prefix, +// strlen((char *)tag_directive.prefix))) +// goto error +// value.handle = yaml_strdup(tag_directive.handle) +// value.prefix = yaml_strdup(tag_directive.prefix) +// if (!value.handle || !value.prefix) goto error +// if (!PUSH(&context, tag_directives_copy, value)) +// goto error +// value.handle = NULL +// value.prefix = NULL +// } +// } +// +// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, +// tag_directives_copy.start, tag_directives_copy.top, +// start_implicit, end_implicit, mark, mark) +// +// return 1 +// +//error: +// STACK_DEL(&context, nodes) +// yaml_free(version_directive_copy) +// while (!STACK_EMPTY(&context, tag_directives_copy)) { +// value yaml_tag_directive_t = POP(&context, tag_directives_copy) +// yaml_free(value.handle) +// yaml_free(value.prefix) +// } +// STACK_DEL(&context, tag_directives_copy) +// yaml_free(value.handle) +// yaml_free(value.prefix) +// +// return 0 +//} +// +///* +// * Destroy a document object. +// */ +// +//YAML_DECLARE(void) +//yaml_document_delete(document *yaml_document_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// tag_directive *yaml_tag_directive_t +// +// context.error = YAML_NO_ERROR // Eliminate a compiler warning. +// +// assert(document) // Non-NULL document object is expected. +// +// while (!STACK_EMPTY(&context, document.nodes)) { +// node yaml_node_t = POP(&context, document.nodes) +// yaml_free(node.tag) +// switch (node.type) { +// case YAML_SCALAR_NODE: +// yaml_free(node.data.scalar.value) +// break +// case YAML_SEQUENCE_NODE: +// STACK_DEL(&context, node.data.sequence.items) +// break +// case YAML_MAPPING_NODE: +// STACK_DEL(&context, node.data.mapping.pairs) +// break +// default: +// assert(0) // Should not happen. +// } +// } +// STACK_DEL(&context, document.nodes) +// +// yaml_free(document.version_directive) +// for (tag_directive = document.tag_directives.start +// tag_directive != document.tag_directives.end +// tag_directive++) { +// yaml_free(tag_directive.handle) +// yaml_free(tag_directive.prefix) +// } +// yaml_free(document.tag_directives.start) +// +// memset(document, 0, sizeof(yaml_document_t)) +//} +// +///** +// * Get a document node. +// */ +// +//YAML_DECLARE(yaml_node_t *) +//yaml_document_get_node(document *yaml_document_t, index int) +//{ +// assert(document) // Non-NULL document object is expected. +// +// if (index > 0 && document.nodes.start + index <= document.nodes.top) { +// return document.nodes.start + index - 1 +// } +// return NULL +//} +// +///** +// * Get the root object. +// */ +// +//YAML_DECLARE(yaml_node_t *) +//yaml_document_get_root_node(document *yaml_document_t) +//{ +// assert(document) // Non-NULL document object is expected. +// +// if (document.nodes.top != document.nodes.start) { +// return document.nodes.start +// } +// return NULL +//} +// +///* +// * Add a scalar node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_scalar(document *yaml_document_t, +// tag *yaml_char_t, value *yaml_char_t, length int, +// style yaml_scalar_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// value_copy *yaml_char_t = NULL +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// assert(value) // Non-NULL value is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (length < 0) { +// length = strlen((char *)value) +// } +// +// if (!yaml_check_utf8(value, length)) goto error +// value_copy = yaml_malloc(length+1) +// if (!value_copy) goto error +// memcpy(value_copy, value, length) +// value_copy[length] = '\0' +// +// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// yaml_free(tag_copy) +// yaml_free(value_copy) +// +// return 0 +//} +// +///* +// * Add a sequence node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_sequence(document *yaml_document_t, +// tag *yaml_char_t, style yaml_sequence_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// struct { +// start *yaml_node_item_t +// end *yaml_node_item_t +// top *yaml_node_item_t +// } items = { NULL, NULL, NULL } +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error +// +// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, +// style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// STACK_DEL(&context, items) +// yaml_free(tag_copy) +// +// return 0 +//} +// +///* +// * Add a mapping node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_mapping(document *yaml_document_t, +// tag *yaml_char_t, style yaml_mapping_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// struct { +// start *yaml_node_pair_t +// end *yaml_node_pair_t +// top *yaml_node_pair_t +// } pairs = { NULL, NULL, NULL } +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error +// +// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, +// style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// STACK_DEL(&context, pairs) +// yaml_free(tag_copy) +// +// return 0 +//} +// +///* +// * Append an item to a sequence node. +// */ +// +//YAML_DECLARE(int) +//yaml_document_append_sequence_item(document *yaml_document_t, +// sequence int, item int) +//{ +// struct { +// error yaml_error_type_t +// } context +// +// assert(document) // Non-NULL document is required. +// assert(sequence > 0 +// && document.nodes.start + sequence <= document.nodes.top) +// // Valid sequence id is required. +// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) +// // A sequence node is required. +// assert(item > 0 && document.nodes.start + item <= document.nodes.top) +// // Valid item id is required. +// +// if (!PUSH(&context, +// document.nodes.start[sequence-1].data.sequence.items, item)) +// return 0 +// +// return 1 +//} +// +///* +// * Append a pair of a key and a value to a mapping node. +// */ +// +//YAML_DECLARE(int) +//yaml_document_append_mapping_pair(document *yaml_document_t, +// mapping int, key int, value int) +//{ +// struct { +// error yaml_error_type_t +// } context +// +// pair yaml_node_pair_t +// +// assert(document) // Non-NULL document is required. +// assert(mapping > 0 +// && document.nodes.start + mapping <= document.nodes.top) +// // Valid mapping id is required. +// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) +// // A mapping node is required. +// assert(key > 0 && document.nodes.start + key <= document.nodes.top) +// // Valid key id is required. +// assert(value > 0 && document.nodes.start + value <= document.nodes.top) +// // Valid value id is required. +// +// pair.key = key +// pair.value = value +// +// if (!PUSH(&context, +// document.nodes.start[mapping-1].data.mapping.pairs, pair)) +// return 0 +// +// return 1 +//} +// +// diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/decode.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/decode.go new file mode 100644 index 00000000000..df36e3a30f5 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/decode.go @@ -0,0 +1,950 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// 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. + +package yaml + +import ( + "encoding" + "encoding/base64" + "fmt" + "io" + "math" + "reflect" + "strconv" + "time" +) + +// ---------------------------------------------------------------------------- +// Parser, produces a node tree out of a libyaml event stream. + +type parser struct { + parser yaml_parser_t + event yaml_event_t + doc *Node + anchors map[string]*Node + doneInit bool + textless bool +} + +func newParser(b []byte) *parser { + p := parser{} + if !yaml_parser_initialize(&p.parser) { + panic("failed to initialize YAML emitter") + } + if len(b) == 0 { + b = []byte{'\n'} + } + yaml_parser_set_input_string(&p.parser, b) + return &p +} + +func newParserFromReader(r io.Reader) *parser { + p := parser{} + if !yaml_parser_initialize(&p.parser) { + panic("failed to initialize YAML emitter") + } + yaml_parser_set_input_reader(&p.parser, r) + return &p +} + +func (p *parser) init() { + if p.doneInit { + return + } + p.anchors = make(map[string]*Node) + p.expect(yaml_STREAM_START_EVENT) + p.doneInit = true +} + +func (p *parser) destroy() { + if p.event.typ != yaml_NO_EVENT { + yaml_event_delete(&p.event) + } + yaml_parser_delete(&p.parser) +} + +// expect consumes an event from the event stream and +// checks that it's of the expected type. +func (p *parser) expect(e yaml_event_type_t) { + if p.event.typ == yaml_NO_EVENT { + if !yaml_parser_parse(&p.parser, &p.event) { + p.fail() + } + } + if p.event.typ == yaml_STREAM_END_EVENT { + failf("attempted to go past the end of stream; corrupted value?") + } + if p.event.typ != e { + p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) + p.fail() + } + yaml_event_delete(&p.event) + p.event.typ = yaml_NO_EVENT +} + +// peek peeks at the next event in the event stream, +// puts the results into p.event and returns the event type. +func (p *parser) peek() yaml_event_type_t { + if p.event.typ != yaml_NO_EVENT { + return p.event.typ + } + if !yaml_parser_parse(&p.parser, &p.event) { + p.fail() + } + return p.event.typ +} + +func (p *parser) fail() { + var where string + var line int + if p.parser.context_mark.line != 0 { + line = p.parser.context_mark.line + // Scanner errors don't iterate line before returning error + if p.parser.error == yaml_SCANNER_ERROR { + line++ + } + } else if p.parser.problem_mark.line != 0 { + line = p.parser.problem_mark.line + // Scanner errors don't iterate line before returning error + if p.parser.error == yaml_SCANNER_ERROR { + line++ + } + } + if line != 0 { + where = "line " + strconv.Itoa(line) + ": " + } + var msg string + if len(p.parser.problem) > 0 { + msg = p.parser.problem + } else { + msg = "unknown problem parsing YAML content" + } + failf("%s%s", where, msg) +} + +func (p *parser) anchor(n *Node, anchor []byte) { + if anchor != nil { + n.Anchor = string(anchor) + p.anchors[n.Anchor] = n + } +} + +func (p *parser) parse() *Node { + p.init() + switch p.peek() { + case yaml_SCALAR_EVENT: + return p.scalar() + case yaml_ALIAS_EVENT: + return p.alias() + case yaml_MAPPING_START_EVENT: + return p.mapping() + case yaml_SEQUENCE_START_EVENT: + return p.sequence() + case yaml_DOCUMENT_START_EVENT: + return p.document() + case yaml_STREAM_END_EVENT: + // Happens when attempting to decode an empty buffer. + return nil + case yaml_TAIL_COMMENT_EVENT: + panic("internal error: unexpected tail comment event (please report)") + default: + panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String()) + } +} + +func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node { + var style Style + if tag != "" && tag != "!" { + tag = shortTag(tag) + style = TaggedStyle + } else if defaultTag != "" { + tag = defaultTag + } else if kind == ScalarNode { + tag, _ = resolve("", value) + } + n := &Node{ + Kind: kind, + Tag: tag, + Value: value, + Style: style, + } + if !p.textless { + n.Line = p.event.start_mark.line + 1 + n.Column = p.event.start_mark.column + 1 + n.HeadComment = string(p.event.head_comment) + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + } + return n +} + +func (p *parser) parseChild(parent *Node) *Node { + child := p.parse() + parent.Content = append(parent.Content, child) + return child +} + +func (p *parser) document() *Node { + n := p.node(DocumentNode, "", "", "") + p.doc = n + p.expect(yaml_DOCUMENT_START_EVENT) + p.parseChild(n) + if p.peek() == yaml_DOCUMENT_END_EVENT { + n.FootComment = string(p.event.foot_comment) + } + p.expect(yaml_DOCUMENT_END_EVENT) + return n +} + +func (p *parser) alias() *Node { + n := p.node(AliasNode, "", "", string(p.event.anchor)) + n.Alias = p.anchors[n.Value] + if n.Alias == nil { + failf("unknown anchor '%s' referenced", n.Value) + } + p.expect(yaml_ALIAS_EVENT) + return n +} + +func (p *parser) scalar() *Node { + var parsedStyle = p.event.scalar_style() + var nodeStyle Style + switch { + case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0: + nodeStyle = DoubleQuotedStyle + case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0: + nodeStyle = SingleQuotedStyle + case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0: + nodeStyle = LiteralStyle + case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0: + nodeStyle = FoldedStyle + } + var nodeValue = string(p.event.value) + var nodeTag = string(p.event.tag) + var defaultTag string + if nodeStyle == 0 { + if nodeValue == "<<" { + defaultTag = mergeTag + } + } else { + defaultTag = strTag + } + n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue) + n.Style |= nodeStyle + p.anchor(n, p.event.anchor) + p.expect(yaml_SCALAR_EVENT) + return n +} + +func (p *parser) sequence() *Node { + n := p.node(SequenceNode, seqTag, string(p.event.tag), "") + if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 { + n.Style |= FlowStyle + } + p.anchor(n, p.event.anchor) + p.expect(yaml_SEQUENCE_START_EVENT) + for p.peek() != yaml_SEQUENCE_END_EVENT { + p.parseChild(n) + } + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + p.expect(yaml_SEQUENCE_END_EVENT) + return n +} + +func (p *parser) mapping() *Node { + n := p.node(MappingNode, mapTag, string(p.event.tag), "") + block := true + if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 { + block = false + n.Style |= FlowStyle + } + p.anchor(n, p.event.anchor) + p.expect(yaml_MAPPING_START_EVENT) + for p.peek() != yaml_MAPPING_END_EVENT { + k := p.parseChild(n) + if block && k.FootComment != "" { + // Must be a foot comment for the prior value when being dedented. + if len(n.Content) > 2 { + n.Content[len(n.Content)-3].FootComment = k.FootComment + k.FootComment = "" + } + } + v := p.parseChild(n) + if k.FootComment == "" && v.FootComment != "" { + k.FootComment = v.FootComment + v.FootComment = "" + } + if p.peek() == yaml_TAIL_COMMENT_EVENT { + if k.FootComment == "" { + k.FootComment = string(p.event.foot_comment) + } + p.expect(yaml_TAIL_COMMENT_EVENT) + } + } + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 { + n.Content[len(n.Content)-2].FootComment = n.FootComment + n.FootComment = "" + } + p.expect(yaml_MAPPING_END_EVENT) + return n +} + +// ---------------------------------------------------------------------------- +// Decoder, unmarshals a node into a provided value. + +type decoder struct { + doc *Node + aliases map[*Node]bool + terrors []string + + stringMapType reflect.Type + generalMapType reflect.Type + + knownFields bool + uniqueKeys bool + decodeCount int + aliasCount int + aliasDepth int +} + +var ( + nodeType = reflect.TypeOf(Node{}) + durationType = reflect.TypeOf(time.Duration(0)) + stringMapType = reflect.TypeOf(map[string]interface{}{}) + generalMapType = reflect.TypeOf(map[interface{}]interface{}{}) + ifaceType = generalMapType.Elem() + timeType = reflect.TypeOf(time.Time{}) + ptrTimeType = reflect.TypeOf(&time.Time{}) +) + +func newDecoder() *decoder { + d := &decoder{ + stringMapType: stringMapType, + generalMapType: generalMapType, + uniqueKeys: true, + } + d.aliases = make(map[*Node]bool) + return d +} + +func (d *decoder) terror(n *Node, tag string, out reflect.Value) { + if n.Tag != "" { + tag = n.Tag + } + value := n.Value + if tag != seqTag && tag != mapTag { + if len(value) > 10 { + value = " `" + value[:7] + "...`" + } else { + value = " `" + value + "`" + } + } + d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type())) +} + +func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) { + err := u.UnmarshalYAML(n) + if e, ok := err.(*TypeError); ok { + d.terrors = append(d.terrors, e.Errors...) + return false + } + if err != nil { + fail(err) + } + return true +} + +func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) { + terrlen := len(d.terrors) + err := u.UnmarshalYAML(func(v interface{}) (err error) { + defer handleErr(&err) + d.unmarshal(n, reflect.ValueOf(v)) + if len(d.terrors) > terrlen { + issues := d.terrors[terrlen:] + d.terrors = d.terrors[:terrlen] + return &TypeError{issues} + } + return nil + }) + if e, ok := err.(*TypeError); ok { + d.terrors = append(d.terrors, e.Errors...) + return false + } + if err != nil { + fail(err) + } + return true +} + +// d.prepare initializes and dereferences pointers and calls UnmarshalYAML +// if a value is found to implement it. +// It returns the initialized and dereferenced out value, whether +// unmarshalling was already done by UnmarshalYAML, and if so whether +// its types unmarshalled appropriately. +// +// 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.ShortTag() == nullTag { + return out, false, false + } + again := true + for again { + again = false + if out.Kind() == reflect.Ptr { + if out.IsNil() { + out.Set(reflect.New(out.Type().Elem())) + } + out = out.Elem() + again = true + } + if out.CanAddr() { + outi := out.Addr().Interface() + if u, ok := outi.(Unmarshaler); ok { + good = d.callUnmarshaler(n, u) + return out, true, good + } + if u, ok := outi.(obsoleteUnmarshaler); ok { + good = d.callObsoleteUnmarshaler(n, u) + return out, true, good + } + } + } + return out, false, false +} + +func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) { + if n.ShortTag() == nullTag { + return reflect.Value{} + } + for _, num := range index { + for { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + continue + } + break + } + v = v.Field(num) + } + return v +} + +const ( + // 400,000 decode operations is ~500kb of dense object declarations, or + // ~5kb of dense object declarations with 10000% alias expansion + alias_ratio_range_low = 400000 + + // 4,000,000 decode operations is ~5MB of dense object declarations, or + // ~4.5MB of dense object declarations with 10% alias expansion + alias_ratio_range_high = 4000000 + + // alias_ratio_range is the range over which we scale allowed alias ratios + alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low) +) + +func allowedAliasRatio(decodeCount int) float64 { + switch { + case decodeCount <= alias_ratio_range_low: + // allow 99% to come from alias expansion for small-to-medium documents + return 0.99 + case decodeCount >= alias_ratio_range_high: + // allow 10% to come from alias expansion for very large documents + return 0.10 + default: + // scale smoothly from 99% down to 10% over the range. + // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range. + // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps). + return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range) + } +} + +func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) { + d.decodeCount++ + if d.aliasDepth > 0 { + d.aliasCount++ + } + if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) { + failf("document contains excessive aliasing") + } + if out.Type() == nodeType { + out.Set(reflect.ValueOf(n).Elem()) + return true + } + switch n.Kind { + case DocumentNode: + return d.document(n, out) + case AliasNode: + return d.alias(n, out) + } + out, unmarshaled, good := d.prepare(n, out) + if unmarshaled { + return good + } + switch n.Kind { + case ScalarNode: + good = d.scalar(n, out) + case MappingNode: + good = d.mapping(n, out) + case SequenceNode: + good = d.sequence(n, out) + case 0: + if n.IsZero() { + return d.null(out) + } + fallthrough + default: + failf("cannot decode node with unknown kind %d", n.Kind) + } + return good +} + +func (d *decoder) document(n *Node, out reflect.Value) (good bool) { + if len(n.Content) == 1 { + d.doc = n + d.unmarshal(n.Content[0], out) + return true + } + return false +} + +func (d *decoder) alias(n *Node, out reflect.Value) (good bool) { + if d.aliases[n] { + // TODO this could actually be allowed in some circumstances. + failf("anchor '%s' value contains itself", n.Value) + } + d.aliases[n] = true + d.aliasDepth++ + good = d.unmarshal(n.Alias, out) + d.aliasDepth-- + delete(d.aliases, n) + return good +} + +var zeroValue reflect.Value + +func resetMap(out reflect.Value) { + for _, k := range out.MapKeys() { + out.SetMapIndex(k, zeroValue) + } +} + +func (d *decoder) null(out reflect.Value) bool { + if out.CanAddr() { + switch out.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + out.Set(reflect.Zero(out.Type())) + return true + } + } + return false +} + +func (d *decoder) scalar(n *Node, out reflect.Value) bool { + var tag string + var resolved interface{} + if n.indicatedString() { + tag = strTag + resolved = n.Value + } else { + tag, resolved = resolve(n.Tag, n.Value) + if tag == binaryTag { + data, err := base64.StdEncoding.DecodeString(resolved.(string)) + if err != nil { + failf("!!binary value contains invalid base64 data") + } + resolved = string(data) + } + } + if resolved == nil { + return d.null(out) + } + if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { + // We've resolved to exactly the type we want, so use that. + out.Set(resolvedv) + return true + } + // Perhaps we can use the value as a TextUnmarshaler to + // set its value. + if out.CanAddr() { + u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) + if ok { + var text []byte + if tag == binaryTag { + text = []byte(resolved.(string)) + } else { + // We let any value be unmarshaled into TextUnmarshaler. + // That might be more lax than we'd like, but the + // TextUnmarshaler itself should bowl out any dubious values. + text = []byte(n.Value) + } + err := u.UnmarshalText(text) + if err != nil { + fail(err) + } + return true + } + } + switch out.Kind() { + case reflect.String: + if tag == binaryTag { + out.SetString(resolved.(string)) + return true + } + out.SetString(n.Value) + return true + case reflect.Interface: + out.Set(reflect.ValueOf(resolved)) + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // This used to work in v2, but it's very unfriendly. + isDuration := out.Type() == durationType + + switch resolved := resolved.(type) { + case int: + if !isDuration && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case int64: + if !isDuration && !out.OverflowInt(resolved) { + out.SetInt(resolved) + return true + } + case uint64: + if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case float64: + if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case string: + if out.Type() == durationType { + d, err := time.ParseDuration(resolved) + if err == nil { + out.SetInt(int64(d)) + return true + } + } + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + switch resolved := resolved.(type) { + case int: + if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case int64: + if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case uint64: + if !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case float64: + if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + } + case reflect.Bool: + switch resolved := resolved.(type) { + case bool: + out.SetBool(resolved) + return true + case string: + // This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html). + // It only works if explicitly attempting to unmarshal into a typed bool value. + switch resolved { + case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON": + out.SetBool(true) + return true + case "n", "N", "no", "No", "NO", "off", "Off", "OFF": + out.SetBool(false) + return true + } + } + case reflect.Float32, reflect.Float64: + switch resolved := resolved.(type) { + case int: + out.SetFloat(float64(resolved)) + return true + case int64: + out.SetFloat(float64(resolved)) + return true + case uint64: + out.SetFloat(float64(resolved)) + return true + case float64: + out.SetFloat(resolved) + return true + } + case reflect.Struct: + if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { + out.Set(resolvedv) + return true + } + case reflect.Ptr: + panic("yaml internal error: please report the issue") + } + d.terror(n, tag, out) + return false +} + +func settableValueOf(i interface{}) reflect.Value { + v := reflect.ValueOf(i) + sv := reflect.New(v.Type()).Elem() + sv.Set(v) + return sv +} + +func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) { + l := len(n.Content) + + var iface reflect.Value + switch out.Kind() { + case reflect.Slice: + out.Set(reflect.MakeSlice(out.Type(), l, l)) + case reflect.Array: + if l != out.Len() { + failf("invalid array: want %d elements but got %d", out.Len(), l) + } + case reflect.Interface: + // No type hints. Will have to use a generic sequence. + iface = out + out = settableValueOf(make([]interface{}, l)) + default: + d.terror(n, seqTag, out) + return false + } + et := out.Type().Elem() + + j := 0 + for i := 0; i < l; i++ { + e := reflect.New(et).Elem() + if ok := d.unmarshal(n.Content[i], e); ok { + out.Index(j).Set(e) + j++ + } + } + if out.Kind() != reflect.Array { + out.Set(out.Slice(0, j)) + } + if iface.IsValid() { + iface.Set(out) + } + return true +} + +func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { + l := len(n.Content) + if d.uniqueKeys { + nerrs := len(d.terrors) + for i := 0; i < l; i += 2 { + ni := n.Content[i] + for j := i + 2; j < l; j += 2 { + nj := n.Content[j] + if ni.Kind == nj.Kind && ni.Value == nj.Value { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line)) + } + } + } + if len(d.terrors) > nerrs { + return false + } + } + switch out.Kind() { + case reflect.Struct: + return d.mappingStruct(n, out) + case reflect.Map: + // okay + case reflect.Interface: + iface := out + if isStringMap(n) { + out = reflect.MakeMap(d.stringMapType) + } else { + out = reflect.MakeMap(d.generalMapType) + } + iface.Set(out) + default: + d.terror(n, mapTag, out) + return false + } + + outt := out.Type() + kt := outt.Key() + et := outt.Elem() + + stringMapType := d.stringMapType + generalMapType := d.generalMapType + if outt.Elem() == ifaceType { + if outt.Key().Kind() == reflect.String { + d.stringMapType = outt + } else if outt.Key() == ifaceType { + d.generalMapType = outt + } + } + + mapIsNew := false + if out.IsNil() { + out.Set(reflect.MakeMap(outt)) + mapIsNew = true + } + for i := 0; i < l; i += 2 { + if isMerge(n.Content[i]) { + d.merge(n.Content[i+1], out) + continue + } + k := reflect.New(kt).Elem() + if d.unmarshal(n.Content[i], k) { + kkind := k.Kind() + if kkind == reflect.Interface { + kkind = k.Elem().Kind() + } + if kkind == reflect.Map || kkind == reflect.Slice { + failf("invalid map key: %#v", k.Interface()) + } + e := reflect.New(et).Elem() + if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) { + out.SetMapIndex(k, e) + } + } + } + d.stringMapType = stringMapType + d.generalMapType = generalMapType + return true +} + +func isStringMap(n *Node) bool { + if n.Kind != MappingNode { + return false + } + l := len(n.Content) + for i := 0; i < l; i += 2 { + if n.Content[i].ShortTag() != strTag { + return false + } + } + return true +} + +func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { + sinfo, err := getStructInfo(out.Type()) + if err != nil { + panic(err) + } + + var inlineMap reflect.Value + var elemType reflect.Type + if sinfo.InlineMap != -1 { + inlineMap = out.Field(sinfo.InlineMap) + inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) + elemType = inlineMap.Type().Elem() + } + + for _, index := range sinfo.InlineUnmarshalers { + field := d.fieldByIndex(n, out, index) + d.prepare(n, field) + } + + var doneFields []bool + if d.uniqueKeys { + doneFields = make([]bool, len(sinfo.FieldsList)) + } + name := settableValueOf("") + l := len(n.Content) + for i := 0; i < l; i += 2 { + ni := n.Content[i] + if isMerge(ni) { + d.merge(n.Content[i+1], out) + continue + } + if !d.unmarshal(ni, name) { + continue + } + if info, ok := sinfo.FieldsMap[name.String()]; ok { + if d.uniqueKeys { + if doneFields[info.Id] { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type())) + continue + } + doneFields[info.Id] = true + } + var field reflect.Value + if info.Inline == nil { + field = out.Field(info.Num) + } else { + field = d.fieldByIndex(n, out, info.Inline) + } + d.unmarshal(n.Content[i+1], field) + } else if sinfo.InlineMap != -1 { + if inlineMap.IsNil() { + inlineMap.Set(reflect.MakeMap(inlineMap.Type())) + } + value := reflect.New(elemType).Elem() + d.unmarshal(n.Content[i+1], value) + inlineMap.SetMapIndex(name, value) + } else if d.knownFields { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type())) + } + } + return true +} + +func failWantMap() { + failf("map merge requires map or sequence of maps as the value") +} + +func (d *decoder) merge(n *Node, out reflect.Value) { + switch n.Kind { + case MappingNode: + d.unmarshal(n, out) + case AliasNode: + if n.Alias != nil && n.Alias.Kind != MappingNode { + failWantMap() + } + d.unmarshal(n, out) + case SequenceNode: + // Step backwards as earlier nodes take precedence. + for i := len(n.Content) - 1; i >= 0; i-- { + ni := n.Content[i] + if ni.Kind == AliasNode { + if ni.Alias != nil && ni.Alias.Kind != MappingNode { + failWantMap() + } + } else if ni.Kind != MappingNode { + failWantMap() + } + d.unmarshal(ni, out) + } + default: + failWantMap() + } +} + +func isMerge(n *Node) bool { + return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag) +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/emitterc.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/emitterc.go new file mode 100644 index 00000000000..f0f3d1867f7 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/emitterc.go @@ -0,0 +1,2028 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +import ( + "bytes" + "fmt" +) + +// Flush the buffer if needed. +func flush(emitter *yaml_emitter_t) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) { + return yaml_emitter_flush(emitter) + } + return true +} + +// Put a character to the output buffer. +func put(emitter *yaml_emitter_t, value byte) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + emitter.buffer[emitter.buffer_pos] = value + emitter.buffer_pos++ + emitter.column++ + return true +} + +// Put a line break to the output buffer. +func put_break(emitter *yaml_emitter_t) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + switch emitter.line_break { + case yaml_CR_BREAK: + emitter.buffer[emitter.buffer_pos] = '\r' + emitter.buffer_pos += 1 + case yaml_LN_BREAK: + emitter.buffer[emitter.buffer_pos] = '\n' + emitter.buffer_pos += 1 + case yaml_CRLN_BREAK: + emitter.buffer[emitter.buffer_pos+0] = '\r' + emitter.buffer[emitter.buffer_pos+1] = '\n' + emitter.buffer_pos += 2 + default: + panic("unknown line break setting") + } + if emitter.column == 0 { + emitter.space_above = true + } + emitter.column = 0 + emitter.line++ + // [Go] Do this here and below and drop from everywhere else (see commented lines). + emitter.indention = true + return true +} + +// Copy a character from a string into buffer. +func write(emitter *yaml_emitter_t, s []byte, i *int) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + p := emitter.buffer_pos + w := width(s[*i]) + switch w { + case 4: + emitter.buffer[p+3] = s[*i+3] + fallthrough + case 3: + emitter.buffer[p+2] = s[*i+2] + fallthrough + case 2: + emitter.buffer[p+1] = s[*i+1] + fallthrough + case 1: + emitter.buffer[p+0] = s[*i+0] + default: + panic("unknown character width") + } + emitter.column++ + emitter.buffer_pos += w + *i += w + return true +} + +// Write a whole string into buffer. +func write_all(emitter *yaml_emitter_t, s []byte) bool { + for i := 0; i < len(s); { + if !write(emitter, s, &i) { + return false + } + } + return true +} + +// Copy a line break character from a string into buffer. +func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { + if s[*i] == '\n' { + if !put_break(emitter) { + return false + } + *i++ + } else { + if !write(emitter, s, i) { + return false + } + if emitter.column == 0 { + emitter.space_above = true + } + emitter.column = 0 + emitter.line++ + // [Go] Do this here and above and drop from everywhere else (see commented lines). + emitter.indention = true + } + return true +} + +// Set an emitter error and return false. +func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { + emitter.error = yaml_EMITTER_ERROR + emitter.problem = problem + return false +} + +// Emit an event. +func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { + emitter.events = append(emitter.events, *event) + for !yaml_emitter_need_more_events(emitter) { + event := &emitter.events[emitter.events_head] + if !yaml_emitter_analyze_event(emitter, event) { + return false + } + if !yaml_emitter_state_machine(emitter, event) { + return false + } + yaml_event_delete(event) + emitter.events_head++ + } + return true +} + +// Check if we need to accumulate more events before emitting. +// +// We accumulate extra +// - 1 event for DOCUMENT-START +// - 2 events for SEQUENCE-START +// - 3 events for MAPPING-START +// +func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { + if emitter.events_head == len(emitter.events) { + return true + } + var accumulate int + switch emitter.events[emitter.events_head].typ { + case yaml_DOCUMENT_START_EVENT: + accumulate = 1 + break + case yaml_SEQUENCE_START_EVENT: + accumulate = 2 + break + case yaml_MAPPING_START_EVENT: + accumulate = 3 + break + default: + return false + } + if len(emitter.events)-emitter.events_head > accumulate { + return false + } + var level int + for i := emitter.events_head; i < len(emitter.events); i++ { + switch emitter.events[i].typ { + case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: + level++ + case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: + level-- + } + if level == 0 { + return false + } + } + return true +} + +// Append a directive to the directives stack. +func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { + for i := 0; i < len(emitter.tag_directives); i++ { + if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { + if allow_duplicates { + return true + } + return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") + } + } + + // [Go] Do we actually need to copy this given garbage collection + // and the lack of deallocating destructors? + tag_copy := yaml_tag_directive_t{ + handle: make([]byte, len(value.handle)), + prefix: make([]byte, len(value.prefix)), + } + copy(tag_copy.handle, value.handle) + copy(tag_copy.prefix, value.prefix) + emitter.tag_directives = append(emitter.tag_directives, tag_copy) + return true +} + +// Increase the indentation level. +func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool, compact_seq bool) bool { + emitter.indents = append(emitter.indents, emitter.indent) + if emitter.indent < 0 { + if flow { + emitter.indent = emitter.best_indent + } else { + emitter.indent = 0 + } + } else if !indentless { + // [Go] This was changed so that indentations are more regular. + if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE { + // The first indent inside a sequence will just skip the "- " indicator. + emitter.indent += 2 + } else { + // Everything else aligns to the chosen indentation. + emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent) + } + if compact_seq { + emitter.indent = emitter.indent - 2 + } + } + return true +} + +// State dispatcher. +func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { + switch emitter.state { + default: + case yaml_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event) + + case yaml_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, true) + + case yaml_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, false) + + case yaml_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event) + + case yaml_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event) + + case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, true, false) + + case yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, false, true) + + case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, false, false) + + case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, true, false) + + case yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, false, true) + + case yaml_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, false, false) + + case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, true) + + case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, false) + + case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, true) + + case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, false) + + case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, true) + + case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, false) + + case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, true) + + case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, false) + + case yaml_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") + } + panic("invalid emitter state") +} + +// Expect STREAM-START. +func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if event.typ != yaml_STREAM_START_EVENT { + return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") + } + if emitter.encoding == yaml_ANY_ENCODING { + emitter.encoding = event.encoding + if emitter.encoding == yaml_ANY_ENCODING { + emitter.encoding = yaml_UTF8_ENCODING + } + } + if emitter.best_indent < 2 || emitter.best_indent > 9 { + emitter.best_indent = 2 + } + if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { + emitter.best_width = 80 + } + if emitter.best_width < 0 { + emitter.best_width = 1<<31 - 1 + } + if emitter.line_break == yaml_ANY_BREAK { + emitter.line_break = yaml_LN_BREAK + } + + emitter.indent = -1 + emitter.line = 0 + emitter.column = 0 + emitter.whitespace = true + emitter.indention = true + emitter.space_above = true + emitter.foot_indent = -1 + + if emitter.encoding != yaml_UTF8_ENCODING { + if !yaml_emitter_write_bom(emitter) { + return false + } + } + emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE + return true +} + +// Expect DOCUMENT-START or STREAM-END. +func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + + if event.typ == yaml_DOCUMENT_START_EVENT { + + if event.version_directive != nil { + if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { + return false + } + } + + for i := 0; i < len(event.tag_directives); i++ { + tag_directive := &event.tag_directives[i] + if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { + return false + } + if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { + return false + } + } + + for i := 0; i < len(default_tag_directives); i++ { + tag_directive := &default_tag_directives[i] + if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { + return false + } + } + + implicit := event.implicit + if !first || emitter.canonical { + implicit = false + } + + if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if event.version_directive != nil { + implicit = false + if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if len(event.tag_directives) > 0 { + implicit = false + for i := 0; i < len(event.tag_directives); i++ { + tag_directive := &event.tag_directives[i] + if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { + return false + } + if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { + return false + } + if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + } + + if yaml_emitter_check_empty_document(emitter) { + implicit = false + } + if !implicit { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { + return false + } + if emitter.canonical || true { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + } + + if len(emitter.head_comment) > 0 { + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if !put_break(emitter) { + return false + } + } + + emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE + return true + } + + if event.typ == yaml_STREAM_END_EVENT { + if emitter.open_ended { + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_flush(emitter) { + return false + } + emitter.state = yaml_EMIT_END_STATE + return true + } + + return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") +} + +// Expect the root node. +func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { + emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) + + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if !yaml_emitter_emit_node(emitter, event, true, false, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect DOCUMENT-END. +func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if event.typ != yaml_DOCUMENT_END_EVENT { + return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") + } + // [Go] Force document foot separation. + emitter.foot_indent = 0 + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + emitter.foot_indent = -1 + if !yaml_emitter_write_indent(emitter) { + return false + } + if !event.implicit { + // [Go] Allocate the slice elsewhere. + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_flush(emitter) { + return false + } + emitter.state = yaml_EMIT_DOCUMENT_START_STATE + emitter.tag_directives = emitter.tag_directives[:0] + return true +} + +// Expect a flow item node. +func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool { + if first { + if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false, false) { + return false + } + emitter.flow_level++ + } + + if event.typ == yaml_SEQUENCE_END_EVENT { + if emitter.canonical && !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + emitter.flow_level-- + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + if emitter.column == 0 || emitter.canonical && !first { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + + return true + } + + if !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if emitter.column == 0 { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE) + } else { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) + } + if !yaml_emitter_emit_node(emitter, event, false, true, false, false) { + return false + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect a flow key node. +func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool { + if first { + if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false, false) { + return false + } + emitter.flow_level++ + } + + if event.typ == yaml_MAPPING_END_EVENT { + if (emitter.canonical || len(emitter.head_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0) && !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if !yaml_emitter_process_head_comment(emitter) { + return false + } + emitter.flow_level-- + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + if emitter.canonical && !first { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + + if !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + + if !yaml_emitter_process_head_comment(emitter) { + return false + } + + if emitter.column == 0 { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, true) + } + if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a flow value node. +func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { + if simple { + if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { + return false + } + } else { + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { + return false + } + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE) + } else { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) + } + if !yaml_emitter_emit_node(emitter, event, false, false, true, false) { + return false + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect a block item node. +func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + seq := emitter.mapping_context && (emitter.column == 0 || !emitter.indention) && + emitter.compact_sequence_indent + if !yaml_emitter_increase_indent(emitter, false, false, seq){ + return false + } + } + if event.typ == yaml_SEQUENCE_END_EVENT { + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) + if !yaml_emitter_emit_node(emitter, event, false, true, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect a block key node. +func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_increase_indent(emitter, false, false, false) { + return false + } + } + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if event.typ == yaml_MAPPING_END_EVENT { + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if len(emitter.line_comment) > 0 { + // [Go] A line comment was provided for the key. That's unusual as the + // scanner associates line comments with the value. Either way, + // save the line comment and render it appropriately later. + emitter.key_line_comment = emitter.line_comment + emitter.line_comment = nil + } + if yaml_emitter_check_simple_key(emitter) { + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, true) + } + if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a block value node. +func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { + if simple { + if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { + return false + } + } else { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { + return false + } + } + if len(emitter.key_line_comment) > 0 { + // [Go] Line comments are generally associated with the value, but when there's + // no value on the same line as a mapping key they end up attached to the + // key itself. + if event.typ == yaml_SCALAR_EVENT { + if len(emitter.line_comment) == 0 { + // A scalar is coming and it has no line comments by itself yet, + // so just let it handle the line comment as usual. If it has a + // line comment, we can't have both so the one from the key is lost. + emitter.line_comment = emitter.key_line_comment + emitter.key_line_comment = nil + } + } else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) { + // An indented block follows, so write the comment right now. + emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment + } + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) + if !yaml_emitter_emit_node(emitter, event, false, false, true, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter, false) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { + return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0 +} + +// Expect a node. +func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, + root bool, sequence bool, mapping bool, simple_key bool) bool { + + emitter.root_context = root + emitter.sequence_context = sequence + emitter.mapping_context = mapping + emitter.simple_key_context = simple_key + + switch event.typ { + case yaml_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event) + case yaml_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event) + case yaml_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event) + case yaml_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event) + default: + return yaml_emitter_set_emitter_error(emitter, + fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) + } +} + +// Expect ALIAS. +func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true +} + +// Expect SCALAR. +func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_select_scalar_style(emitter, event) { + return false + } + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false, false) { + return false + } + if !yaml_emitter_process_scalar(emitter) { + return false + } + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true +} + +// Expect SEQUENCE-START. +func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || + yaml_emitter_check_empty_sequence(emitter) { + emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE + } else { + emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE + } + return true +} + +// Expect MAPPING-START. +func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || + yaml_emitter_check_empty_mapping(emitter) { + emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE + } else { + emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE + } + return true +} + +// Check if the document content is an empty scalar. +func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { + return false // [Go] Huh? +} + +// Check if the next events represent an empty sequence. +func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { + if len(emitter.events)-emitter.events_head < 2 { + return false + } + return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && + emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT +} + +// Check if the next events represent an empty mapping. +func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { + if len(emitter.events)-emitter.events_head < 2 { + return false + } + return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && + emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT +} + +// Check if the next node can be expressed as a simple key. +func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { + length := 0 + switch emitter.events[emitter.events_head].typ { + case yaml_ALIAS_EVENT: + length += len(emitter.anchor_data.anchor) + case yaml_SCALAR_EVENT: + if emitter.scalar_data.multiline { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + + len(emitter.scalar_data.value) + case yaml_SEQUENCE_START_EVENT: + if !yaml_emitter_check_empty_sequence(emitter) { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + case yaml_MAPPING_START_EVENT: + if !yaml_emitter_check_empty_mapping(emitter) { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + default: + return false + } + return length <= 128 +} + +// Determine an acceptable scalar style. +func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { + + no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 + if no_tag && !event.implicit && !event.quoted_implicit { + return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") + } + + style := event.scalar_style() + if style == yaml_ANY_SCALAR_STYLE { + style = yaml_PLAIN_SCALAR_STYLE + } + if emitter.canonical { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + if emitter.simple_key_context && emitter.scalar_data.multiline { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + + if style == yaml_PLAIN_SCALAR_STYLE { + if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || + emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + if no_tag && !event.implicit { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + } + if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { + if !emitter.scalar_data.single_quoted_allowed { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + } + if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { + if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + } + + if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { + emitter.tag_data.handle = []byte{'!'} + } + emitter.scalar_data.style = style + return true +} + +// Write an anchor. +func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { + if emitter.anchor_data.anchor == nil { + return true + } + c := []byte{'&'} + if emitter.anchor_data.alias { + c[0] = '*' + } + if !yaml_emitter_write_indicator(emitter, c, true, false, false) { + return false + } + return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) +} + +// Write a tag. +func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { + if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { + return true + } + if len(emitter.tag_data.handle) > 0 { + if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { + return false + } + if len(emitter.tag_data.suffix) > 0 { + if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { + return false + } + } + } else { + // [Go] Allocate these slices elsewhere. + if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { + return false + } + if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { + return false + } + } + return true +} + +// Write a scalar. +func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { + switch emitter.scalar_data.style { + case yaml_PLAIN_SCALAR_STYLE: + return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_SINGLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_DOUBLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_LITERAL_SCALAR_STYLE: + return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) + + case yaml_FOLDED_SCALAR_STYLE: + return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) + } + panic("unknown scalar style") +} + +// Write a head comment. +func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool { + if len(emitter.tail_comment) > 0 { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_comment(emitter, emitter.tail_comment) { + return false + } + emitter.tail_comment = emitter.tail_comment[:0] + emitter.foot_indent = emitter.indent + if emitter.foot_indent < 0 { + emitter.foot_indent = 0 + } + } + + if len(emitter.head_comment) == 0 { + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_comment(emitter, emitter.head_comment) { + return false + } + emitter.head_comment = emitter.head_comment[:0] + return true +} + +// Write an line comment. +func yaml_emitter_process_line_comment(emitter *yaml_emitter_t, linebreak bool) bool { + if len(emitter.line_comment) == 0 { + if linebreak && !put_break(emitter) { + return false + } + return true + } + if !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !yaml_emitter_write_comment(emitter, emitter.line_comment) { + return false + } + emitter.line_comment = emitter.line_comment[:0] + return true +} + +// Write a foot comment. +func yaml_emitter_process_foot_comment(emitter *yaml_emitter_t) bool { + if len(emitter.foot_comment) == 0 { + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_comment(emitter, emitter.foot_comment) { + return false + } + emitter.foot_comment = emitter.foot_comment[:0] + emitter.foot_indent = emitter.indent + if emitter.foot_indent < 0 { + emitter.foot_indent = 0 + } + return true +} + +// Check if a %YAML directive is valid. +func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { + if version_directive.major != 1 || version_directive.minor != 1 { + return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") + } + return true +} + +// Check if a %TAG directive is valid. +func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { + handle := tag_directive.handle + prefix := tag_directive.prefix + if len(handle) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") + } + if handle[0] != '!' { + return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") + } + if handle[len(handle)-1] != '!' { + return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") + } + for i := 1; i < len(handle)-1; i += width(handle[i]) { + if !is_alpha(handle, i) { + return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") + } + } + if len(prefix) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") + } + return true +} + +// Check if an anchor is valid. +func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { + if len(anchor) == 0 { + problem := "anchor value must not be empty" + if alias { + problem = "alias value must not be empty" + } + return yaml_emitter_set_emitter_error(emitter, problem) + } + for i := 0; i < len(anchor); i += width(anchor[i]) { + if !is_alpha(anchor, i) { + problem := "anchor value must contain alphanumerical characters only" + if alias { + problem = "alias value must contain alphanumerical characters only" + } + return yaml_emitter_set_emitter_error(emitter, problem) + } + } + emitter.anchor_data.anchor = anchor + emitter.anchor_data.alias = alias + return true +} + +// Check if a tag is valid. +func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { + if len(tag) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") + } + for i := 0; i < len(emitter.tag_directives); i++ { + tag_directive := &emitter.tag_directives[i] + if bytes.HasPrefix(tag, tag_directive.prefix) { + emitter.tag_data.handle = tag_directive.handle + emitter.tag_data.suffix = tag[len(tag_directive.prefix):] + return true + } + } + emitter.tag_data.suffix = tag + return true +} + +// Check if a scalar is valid. +func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { + var ( + block_indicators = false + flow_indicators = false + line_breaks = false + special_characters = false + tab_characters = false + + leading_space = false + leading_break = false + trailing_space = false + trailing_break = false + break_space = false + space_break = false + + preceded_by_whitespace = false + followed_by_whitespace = false + previous_space = false + previous_break = false + ) + + emitter.scalar_data.value = value + + if len(value) == 0 { + emitter.scalar_data.multiline = false + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = true + emitter.scalar_data.single_quoted_allowed = true + emitter.scalar_data.block_allowed = false + return true + } + + if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { + block_indicators = true + flow_indicators = 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) + + if i == 0 { + switch value[i] { + case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': + flow_indicators = true + block_indicators = true + case '?', ':': + flow_indicators = true + if followed_by_whitespace { + block_indicators = true + } + case '-': + if followed_by_whitespace { + flow_indicators = true + block_indicators = true + } + } + } else { + switch value[i] { + case ',', '?', '[', ']', '{', '}': + flow_indicators = true + case ':': + flow_indicators = true + if followed_by_whitespace { + block_indicators = true + } + case '#': + if preceded_by_whitespace { + flow_indicators = true + block_indicators = true + } + } + } + + if value[i] == '\t' { + tab_characters = true + } else if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { + special_characters = true + } + if is_space(value, i) { + if i == 0 { + leading_space = true + } + if i+width(value[i]) == len(value) { + trailing_space = true + } + if previous_break { + break_space = true + } + previous_space = true + previous_break = false + } else if is_break(value, i) { + line_breaks = true + if i == 0 { + leading_break = true + } + if i+width(value[i]) == len(value) { + trailing_break = true + } + if previous_space { + space_break = true + } + previous_space = false + previous_break = true + } else { + previous_space = false + previous_break = false + } + + // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. + preceded_by_whitespace = is_blankz(value, i) + } + + emitter.scalar_data.multiline = line_breaks + emitter.scalar_data.flow_plain_allowed = true + emitter.scalar_data.block_plain_allowed = true + emitter.scalar_data.single_quoted_allowed = true + emitter.scalar_data.block_allowed = true + + if leading_space || leading_break || trailing_space || trailing_break { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + } + if trailing_space { + emitter.scalar_data.block_allowed = false + } + if break_space { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + emitter.scalar_data.single_quoted_allowed = false + } + if space_break || tab_characters || special_characters { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + emitter.scalar_data.single_quoted_allowed = false + } + if space_break || special_characters { + emitter.scalar_data.block_allowed = false + } + if line_breaks { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + } + if flow_indicators { + emitter.scalar_data.flow_plain_allowed = false + } + if block_indicators { + emitter.scalar_data.block_plain_allowed = false + } + return true +} + +// Check if the event data is valid. +func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { + + emitter.anchor_data.anchor = nil + emitter.tag_data.handle = nil + emitter.tag_data.suffix = nil + emitter.scalar_data.value = nil + + if len(event.head_comment) > 0 { + emitter.head_comment = event.head_comment + } + if len(event.line_comment) > 0 { + emitter.line_comment = event.line_comment + } + if len(event.foot_comment) > 0 { + emitter.foot_comment = event.foot_comment + } + if len(event.tail_comment) > 0 { + emitter.tail_comment = event.tail_comment + } + + switch event.typ { + case yaml_ALIAS_EVENT: + if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { + return false + } + + case yaml_SCALAR_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + if !yaml_emitter_analyze_scalar(emitter, event.value) { + return false + } + + case yaml_SEQUENCE_START_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + + case yaml_MAPPING_START_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + } + return true +} + +// Write the BOM character. +func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { + if !flush(emitter) { + return false + } + pos := emitter.buffer_pos + emitter.buffer[pos+0] = '\xEF' + emitter.buffer[pos+1] = '\xBB' + emitter.buffer[pos+2] = '\xBF' + emitter.buffer_pos += 3 + return true +} + +func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { + indent := emitter.indent + if indent < 0 { + indent = 0 + } + if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { + if !put_break(emitter) { + return false + } + } + if emitter.foot_indent == indent { + if !put_break(emitter) { + return false + } + } + for emitter.column < indent { + if !put(emitter, ' ') { + return false + } + } + emitter.whitespace = true + //emitter.indention = true + emitter.space_above = false + emitter.foot_indent = -1 + return true +} + +func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { + if need_whitespace && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !write_all(emitter, indicator) { + return false + } + emitter.whitespace = is_whitespace + emitter.indention = (emitter.indention && is_indention) + emitter.open_ended = false + return true +} + +func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { + if !write_all(emitter, value) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { + if !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !write_all(emitter, value) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { + if need_whitespace && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + for i := 0; i < len(value); { + var must_write bool + switch value[i] { + case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': + must_write = true + default: + must_write = is_alpha(value, i) + } + if must_write { + if !write(emitter, value, &i) { + return false + } + } else { + w := width(value[i]) + for k := 0; k < w; k++ { + octet := value[i] + i++ + if !put(emitter, '%') { + return false + } + + c := octet >> 4 + if c < 10 { + c += '0' + } else { + c += 'A' - 10 + } + if !put(emitter, c) { + return false + } + + c = octet & 0x0f + if c < 10 { + c += '0' + } else { + c += 'A' - 10 + } + if !put(emitter, c) { + return false + } + } + } + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + if len(value) > 0 && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + + spaces := false + breaks := false + for i := 0; i < len(value); { + if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + spaces = true + } else if is_break(value, i) { + if !breaks && value[i] == '\n' { + if !put_break(emitter) { + return false + } + } + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + spaces = false + breaks = false + } + } + + if len(value) > 0 { + emitter.whitespace = false + } + emitter.indention = false + if emitter.root_context { + emitter.open_ended = true + } + + return true +} + +func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + + if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { + return false + } + + spaces := false + breaks := false + for i := 0; i < len(value); { + if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + spaces = true + } else if is_break(value, i) { + if !breaks && value[i] == '\n' { + if !put_break(emitter) { + return false + } + } + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if value[i] == '\'' { + if !put(emitter, '\'') { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + spaces = false + breaks = false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + spaces := false + if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { + return false + } + + for i := 0; i < len(value); { + if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || + is_bom(value, i) || is_break(value, i) || + value[i] == '"' || value[i] == '\\' { + + octet := value[i] + + var w int + var v rune + switch { + case octet&0x80 == 0x00: + w, v = 1, rune(octet&0x7F) + case octet&0xE0 == 0xC0: + w, v = 2, rune(octet&0x1F) + case octet&0xF0 == 0xE0: + w, v = 3, rune(octet&0x0F) + case octet&0xF8 == 0xF0: + w, v = 4, rune(octet&0x07) + } + for k := 1; k < w; k++ { + octet = value[i+k] + v = (v << 6) + (rune(octet) & 0x3F) + } + i += w + + if !put(emitter, '\\') { + return false + } + + var ok bool + switch v { + case 0x00: + ok = put(emitter, '0') + case 0x07: + ok = put(emitter, 'a') + case 0x08: + ok = put(emitter, 'b') + case 0x09: + ok = put(emitter, 't') + case 0x0A: + ok = put(emitter, 'n') + case 0x0b: + ok = put(emitter, 'v') + case 0x0c: + ok = put(emitter, 'f') + case 0x0d: + ok = put(emitter, 'r') + case 0x1b: + ok = put(emitter, 'e') + case 0x22: + ok = put(emitter, '"') + case 0x5c: + ok = put(emitter, '\\') + case 0x85: + ok = put(emitter, 'N') + case 0xA0: + ok = put(emitter, '_') + case 0x2028: + ok = put(emitter, 'L') + case 0x2029: + ok = put(emitter, 'P') + default: + if v <= 0xFF { + ok = put(emitter, 'x') + w = 2 + } else if v <= 0xFFFF { + ok = put(emitter, 'u') + w = 4 + } else { + ok = put(emitter, 'U') + w = 8 + } + for k := (w - 1) * 4; ok && k >= 0; k -= 4 { + digit := byte((v >> uint(k)) & 0x0F) + if digit < 10 { + ok = put(emitter, digit+'0') + } else { + ok = put(emitter, digit+'A'-10) + } + } + } + if !ok { + return false + } + spaces = false + } else if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { + if !yaml_emitter_write_indent(emitter) { + return false + } + if is_space(value, i+1) { + if !put(emitter, '\\') { + return false + } + } + i += width(value[i]) + } else if !write(emitter, value, &i) { + return false + } + spaces = true + } else { + if !write(emitter, value, &i) { + return false + } + spaces = false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { + if is_space(value, 0) || is_break(value, 0) { + indent_hint := []byte{'0' + byte(emitter.best_indent)} + if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { + return false + } + } + + emitter.open_ended = false + + var chomp_hint [1]byte + if len(value) == 0 { + chomp_hint[0] = '-' + } else { + i := len(value) - 1 + for value[i]&0xC0 == 0x80 { + i-- + } + if !is_break(value, i) { + chomp_hint[0] = '-' + } else if i == 0 { + chomp_hint[0] = '+' + emitter.open_ended = true + } else { + i-- + for value[i]&0xC0 == 0x80 { + i-- + } + if is_break(value, i) { + chomp_hint[0] = '+' + emitter.open_ended = true + } + } + } + if chomp_hint[0] != 0 { + if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { + return false + } + } + return true +} + +func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { + if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { + return false + } + if !yaml_emitter_write_block_scalar_hints(emitter, value) { + return false + } + if !yaml_emitter_process_line_comment(emitter, true) { + return false + } + //emitter.indention = true + emitter.whitespace = true + breaks := true + for i := 0; i < len(value); { + if is_break(value, i) { + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + breaks = false + } + } + + return true +} + +func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { + if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { + return false + } + if !yaml_emitter_write_block_scalar_hints(emitter, value) { + return false + } + if !yaml_emitter_process_line_comment(emitter, true) { + return false + } + + //emitter.indention = true + emitter.whitespace = true + + breaks := true + leading_spaces := true + for i := 0; i < len(value); { + if is_break(value, i) { + if !breaks && !leading_spaces && value[i] == '\n' { + k := 0 + for is_break(value, k) { + k += width(value[k]) + } + if !is_blankz(value, k) { + if !put_break(emitter) { + return false + } + } + } + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + leading_spaces = is_blank(value, i) + } + if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + emitter.indention = false + breaks = false + } + } + return true +} + +func yaml_emitter_write_comment(emitter *yaml_emitter_t, comment []byte) bool { + breaks := false + pound := false + for i := 0; i < len(comment); { + if is_break(comment, i) { + if !write_break(emitter, comment, &i) { + return false + } + //emitter.indention = true + breaks = true + pound = false + } else { + if breaks && !yaml_emitter_write_indent(emitter) { + return false + } + if !pound { + if comment[i] != '#' && (!put(emitter, '#') || !put(emitter, ' ')) { + return false + } + pound = true + } + if !write(emitter, comment, &i) { + return false + } + emitter.indention = false + breaks = false + } + } + if !breaks && !put_break(emitter) { + return false + } + + emitter.whitespace = true + //emitter.indention = true + return true +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/encode.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/encode.go new file mode 100644 index 00000000000..de9e72a3e63 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/encode.go @@ -0,0 +1,577 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// 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. + +package yaml + +import ( + "encoding" + "fmt" + "io" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +type encoder struct { + emitter yaml_emitter_t + event yaml_event_t + out []byte + flow bool + indent int + doneInit bool +} + +func newEncoder() *encoder { + e := &encoder{} + yaml_emitter_initialize(&e.emitter) + yaml_emitter_set_output_string(&e.emitter, &e.out) + yaml_emitter_set_unicode(&e.emitter, true) + return e +} + +func newEncoderWithWriter(w io.Writer) *encoder { + e := &encoder{} + yaml_emitter_initialize(&e.emitter) + yaml_emitter_set_output_writer(&e.emitter, w) + yaml_emitter_set_unicode(&e.emitter, true) + return e +} + +func (e *encoder) init() { + if e.doneInit { + return + } + if e.indent == 0 { + e.indent = 4 + } + e.emitter.best_indent = e.indent + yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) + e.emit() + e.doneInit = true +} + +func (e *encoder) finish() { + e.emitter.open_ended = false + yaml_stream_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) destroy() { + yaml_emitter_delete(&e.emitter) +} + +func (e *encoder) emit() { + // This will internally delete the e.event value. + e.must(yaml_emitter_emit(&e.emitter, &e.event)) +} + +func (e *encoder) must(ok bool) { + if !ok { + msg := e.emitter.problem + if msg == "" { + msg = "unknown problem generating YAML content" + } + failf("%s", msg) + } +} + +func (e *encoder) marshalDoc(tag string, in reflect.Value) { + e.init() + var node *Node + if in.IsValid() { + node, _ = in.Interface().(*Node) + } + if node != nil && node.Kind == DocumentNode { + e.nodev(in) + } else { + yaml_document_start_event_initialize(&e.event, nil, nil, true) + e.emit() + e.marshal(tag, in) + yaml_document_end_event_initialize(&e.event, true) + e.emit() + } +} + +func (e *encoder) marshal(tag string, in reflect.Value) { + tag = shortTag(tag) + if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { + e.nilv() + return + } + iface := in.Interface() + switch value := iface.(type) { + case *Node: + e.nodev(in) + return + case Node: + if !in.CanAddr() { + var n = reflect.New(in.Type()).Elem() + n.Set(in) + in = n + } + e.nodev(in.Addr()) + return + case time.Time: + e.timev(tag, in) + return + case *time.Time: + e.timev(tag, in.Elem()) + return + case time.Duration: + e.stringv(tag, reflect.ValueOf(value.String())) + return + case Marshaler: + v, err := value.MarshalYAML() + if err != nil { + fail(err) + } + if v == nil { + e.nilv() + return + } + e.marshal(tag, reflect.ValueOf(v)) + return + case encoding.TextMarshaler: + text, err := value.MarshalText() + if err != nil { + fail(err) + } + in = reflect.ValueOf(string(text)) + case nil: + e.nilv() + return + } + switch in.Kind() { + case reflect.Interface: + e.marshal(tag, in.Elem()) + case reflect.Map: + e.mapv(tag, in) + case reflect.Ptr: + e.marshal(tag, in.Elem()) + case reflect.Struct: + e.structv(tag, in) + case reflect.Slice, reflect.Array: + e.slicev(tag, in) + case reflect.String: + e.stringv(tag, in) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + e.intv(tag, in) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + e.uintv(tag, in) + case reflect.Float32, reflect.Float64: + e.floatv(tag, in) + case reflect.Bool: + e.boolv(tag, in) + default: + panic("cannot marshal type: " + in.Type().String()) + } +} + +func (e *encoder) mapv(tag string, in reflect.Value) { + e.mappingv(tag, func() { + keys := keyList(in.MapKeys()) + sort.Sort(keys) + for _, k := range keys { + e.marshal("", k) + e.marshal("", in.MapIndex(k)) + } + }) +} + +func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) { + for _, num := range index { + for { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return reflect.Value{} + } + v = v.Elem() + continue + } + break + } + v = v.Field(num) + } + return v +} + +func (e *encoder) structv(tag string, in reflect.Value) { + sinfo, err := getStructInfo(in.Type()) + if err != nil { + panic(err) + } + e.mappingv(tag, func() { + for _, info := range sinfo.FieldsList { + var value reflect.Value + if info.Inline == nil { + value = in.Field(info.Num) + } else { + value = e.fieldByIndex(in, info.Inline) + if !value.IsValid() { + continue + } + } + if info.OmitEmpty && isZero(value) { + continue + } + e.marshal("", reflect.ValueOf(info.Key)) + e.flow = info.Flow + e.marshal("", value) + } + if sinfo.InlineMap >= 0 { + m := in.Field(sinfo.InlineMap) + if m.Len() > 0 { + e.flow = false + keys := keyList(m.MapKeys()) + sort.Sort(keys) + for _, k := range keys { + if _, found := sinfo.FieldsMap[k.String()]; found { + panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String())) + } + e.marshal("", k) + e.flow = false + e.marshal("", m.MapIndex(k)) + } + } + } + }) +} + +func (e *encoder) mappingv(tag string, f func()) { + implicit := tag == "" + style := yaml_BLOCK_MAPPING_STYLE + if e.flow { + e.flow = false + style = yaml_FLOW_MAPPING_STYLE + } + yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) + e.emit() + f() + yaml_mapping_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) slicev(tag string, in reflect.Value) { + implicit := tag == "" + style := yaml_BLOCK_SEQUENCE_STYLE + if e.flow { + e.flow = false + style = yaml_FLOW_SEQUENCE_STYLE + } + e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) + e.emit() + n := in.Len() + for i := 0; i < n; i++ { + e.marshal("", in.Index(i)) + } + e.must(yaml_sequence_end_event_initialize(&e.event)) + e.emit() +} + +// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. +// +// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported +// in YAML 1.2 and by this package, but these should be marshalled quoted for +// the time being for compatibility with other parsers. +func isBase60Float(s string) (result bool) { + // Fast path. + if s == "" { + return false + } + c := s[0] + if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { + return false + } + // Do the full match. + return base60float.MatchString(s) +} + +// From http://yaml.org/type/float.html, except the regular expression there +// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. +var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) + +// isOldBool returns whether s is bool notation as defined in YAML 1.1. +// +// We continue to force strings that YAML 1.1 would interpret as booleans to be +// rendered as quotes strings so that the marshalled output valid for YAML 1.1 +// parsing. +func isOldBool(s string) (result bool) { + switch s { + case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON", + "n", "N", "no", "No", "NO", "off", "Off", "OFF": + return true + default: + return false + } +} + +func (e *encoder) stringv(tag string, in reflect.Value) { + var style yaml_scalar_style_t + s := in.String() + canUsePlain := true + switch { + case !utf8.ValidString(s): + if tag == binaryTag { + failf("explicitly tagged !!binary data must be base64-encoded") + } + if tag != "" { + failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) + } + // It can't be encoded directly as YAML so use a binary tag + // and encode it as base64. + tag = binaryTag + s = encodeBase64(s) + case tag == "": + // Check to see if it would resolve to a specific + // tag when encoded unquoted. If it doesn't, + // there's no need to quote it. + rtag, _ := resolve("", s) + canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s)) + } + // Note: it's possible for user code to emit invalid YAML + // if they explicitly specify a tag and a string containing + // text that's incompatible with that tag. + switch { + case strings.Contains(s, "\n"): + if e.flow { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } else { + style = yaml_LITERAL_SCALAR_STYLE + } + case canUsePlain: + style = yaml_PLAIN_SCALAR_STYLE + default: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + e.emitScalar(s, "", tag, style, nil, nil, nil, nil) +} + +func (e *encoder) boolv(tag string, in reflect.Value) { + var s string + if in.Bool() { + s = "true" + } else { + s = "false" + } + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) intv(tag string, in reflect.Value) { + s := strconv.FormatInt(in.Int(), 10) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) uintv(tag string, in reflect.Value) { + s := strconv.FormatUint(in.Uint(), 10) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) timev(tag string, in reflect.Value) { + t := in.Interface().(time.Time) + s := t.Format(time.RFC3339Nano) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) floatv(tag string, in reflect.Value) { + // Issue #352: When formatting, use the precision of the underlying value + precision := 64 + if in.Kind() == reflect.Float32 { + precision = 32 + } + + s := strconv.FormatFloat(in.Float(), 'g', -1, precision) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) nilv() { + e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) { + // TODO Kill this function. Replace all initialize calls by their underlining Go literals. + implicit := tag == "" + if !implicit { + tag = longTag(tag) + } + e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) + e.event.head_comment = head + e.event.line_comment = line + e.event.foot_comment = foot + e.event.tail_comment = tail + e.emit() +} + +func (e *encoder) nodev(in reflect.Value) { + e.node(in.Interface().(*Node), "") +} + +func (e *encoder) node(node *Node, tail string) { + // Zero nodes behave as nil. + if node.Kind == 0 && node.IsZero() { + e.nilv() + return + } + + // If the tag was not explicitly requested, and dropping it won't change the + // implicit tag of the value, don't include it in the presentation. + var tag = node.Tag + var stag = shortTag(tag) + var forceQuoting bool + if tag != "" && node.Style&TaggedStyle == 0 { + if node.Kind == ScalarNode { + if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 { + tag = "" + } else { + rtag, _ := resolve("", node.Value) + if rtag == stag { + tag = "" + } else if stag == strTag { + tag = "" + forceQuoting = true + } + } + } else { + var rtag string + switch node.Kind { + case MappingNode: + rtag = mapTag + case SequenceNode: + rtag = seqTag + } + if rtag == stag { + tag = "" + } + } + } + + switch node.Kind { + case DocumentNode: + yaml_document_start_event_initialize(&e.event, nil, nil, true) + e.event.head_comment = []byte(node.HeadComment) + e.emit() + for _, node := range node.Content { + e.node(node, "") + } + yaml_document_end_event_initialize(&e.event, true) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case SequenceNode: + style := yaml_BLOCK_SEQUENCE_STYLE + if node.Style&FlowStyle != 0 { + style = yaml_FLOW_SEQUENCE_STYLE + } + e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)) + e.event.head_comment = []byte(node.HeadComment) + e.emit() + for _, node := range node.Content { + e.node(node, "") + } + e.must(yaml_sequence_end_event_initialize(&e.event)) + e.event.line_comment = []byte(node.LineComment) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case MappingNode: + style := yaml_BLOCK_MAPPING_STYLE + if node.Style&FlowStyle != 0 { + style = yaml_FLOW_MAPPING_STYLE + } + yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style) + e.event.tail_comment = []byte(tail) + e.event.head_comment = []byte(node.HeadComment) + e.emit() + + // The tail logic below moves the foot comment of prior keys to the following key, + // since the value for each key may be a nested structure and the foot needs to be + // processed only the entirety of the value is streamed. The last tail is processed + // with the mapping end event. + var tail string + for i := 0; i+1 < len(node.Content); i += 2 { + k := node.Content[i] + foot := k.FootComment + if foot != "" { + kopy := *k + kopy.FootComment = "" + k = &kopy + } + e.node(k, tail) + tail = foot + + v := node.Content[i+1] + e.node(v, "") + } + + yaml_mapping_end_event_initialize(&e.event) + e.event.tail_comment = []byte(tail) + e.event.line_comment = []byte(node.LineComment) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case AliasNode: + yaml_alias_event_initialize(&e.event, []byte(node.Value)) + e.event.head_comment = []byte(node.HeadComment) + e.event.line_comment = []byte(node.LineComment) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case ScalarNode: + value := node.Value + if !utf8.ValidString(value) { + if stag == binaryTag { + failf("explicitly tagged !!binary data must be base64-encoded") + } + if stag != "" { + failf("cannot marshal invalid UTF-8 data as %s", stag) + } + // It can't be encoded directly as YAML so use a binary tag + // and encode it as base64. + tag = binaryTag + value = encodeBase64(value) + } + + style := yaml_PLAIN_SCALAR_STYLE + switch { + case node.Style&DoubleQuotedStyle != 0: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + case node.Style&SingleQuotedStyle != 0: + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + case node.Style&LiteralStyle != 0: + style = yaml_LITERAL_SCALAR_STYLE + case node.Style&FoldedStyle != 0: + style = yaml_FOLDED_SCALAR_STYLE + case strings.Contains(value, "\n"): + style = yaml_LITERAL_SCALAR_STYLE + case forceQuoting: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + + e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail)) + default: + failf("cannot encode node with unknown kind %d", node.Kind) + } +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/parserc.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/parserc.go new file mode 100644 index 00000000000..ac66fccc059 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/parserc.go @@ -0,0 +1,1249 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +import ( + "bytes" +) + +// The parser implements the following grammar: +// +// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END +// implicit_document ::= block_node DOCUMENT-END* +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// block_node_or_indentless_sequence ::= +// ALIAS +// | properties (block_content | indentless_block_sequence)? +// | block_content +// | indentless_block_sequence +// block_node ::= ALIAS +// | properties block_content? +// | block_content +// flow_node ::= ALIAS +// | properties flow_content? +// | flow_content +// properties ::= TAG ANCHOR? | ANCHOR TAG? +// block_content ::= block_collection | flow_collection | SCALAR +// flow_content ::= flow_collection | SCALAR +// block_collection ::= block_sequence | block_mapping +// flow_collection ::= flow_sequence | flow_mapping +// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END +// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ +// block_mapping ::= BLOCK-MAPPING_START +// ((KEY block_node_or_indentless_sequence?)? +// (VALUE block_node_or_indentless_sequence?)?)* +// BLOCK-END +// flow_sequence ::= FLOW-SEQUENCE-START +// (flow_sequence_entry FLOW-ENTRY)* +// flow_sequence_entry? +// FLOW-SEQUENCE-END +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// flow_mapping ::= FLOW-MAPPING-START +// (flow_mapping_entry FLOW-ENTRY)* +// flow_mapping_entry? +// FLOW-MAPPING-END +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + +// Peek the next token in the token queue. +func peek_token(parser *yaml_parser_t) *yaml_token_t { + if parser.token_available || yaml_parser_fetch_more_tokens(parser) { + token := &parser.tokens[parser.tokens_head] + yaml_parser_unfold_comments(parser, token) + return token + } + return nil +} + +// yaml_parser_unfold_comments walks through the comments queue and joins all +// comments behind the position of the provided token into the respective +// top-level comment slices in the parser. +func yaml_parser_unfold_comments(parser *yaml_parser_t, token *yaml_token_t) { + for parser.comments_head < len(parser.comments) && token.start_mark.index >= parser.comments[parser.comments_head].token_mark.index { + comment := &parser.comments[parser.comments_head] + if len(comment.head) > 0 { + if token.typ == yaml_BLOCK_END_TOKEN { + // No heads on ends, so keep comment.head for a follow up token. + break + } + if len(parser.head_comment) > 0 { + parser.head_comment = append(parser.head_comment, '\n') + } + parser.head_comment = append(parser.head_comment, comment.head...) + } + if len(comment.foot) > 0 { + if len(parser.foot_comment) > 0 { + parser.foot_comment = append(parser.foot_comment, '\n') + } + parser.foot_comment = append(parser.foot_comment, comment.foot...) + } + if len(comment.line) > 0 { + if len(parser.line_comment) > 0 { + parser.line_comment = append(parser.line_comment, '\n') + } + parser.line_comment = append(parser.line_comment, comment.line...) + } + *comment = yaml_comment_t{} + parser.comments_head++ + } +} + +// Remove the next token from the queue (must be called after peek_token). +func skip_token(parser *yaml_parser_t) { + parser.token_available = false + parser.tokens_parsed++ + parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN + parser.tokens_head++ +} + +// Get the next event. +func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { + // Erase the event object. + *event = yaml_event_t{} + + // No events after the end of the stream or error. + if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { + return true + } + + // Generate the next event. + return yaml_parser_state_machine(parser, event) +} + +// Set parser error. +func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { + parser.error = yaml_PARSER_ERROR + parser.problem = problem + parser.problem_mark = problem_mark + return false +} + +func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { + parser.error = yaml_PARSER_ERROR + parser.context = context + parser.context_mark = context_mark + parser.problem = problem + parser.problem_mark = problem_mark + return false +} + +// State dispatcher. +func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { + //trace("yaml_parser_state_machine", "state:", parser.state.String()) + + switch parser.state { + case yaml_PARSE_STREAM_START_STATE: + return yaml_parser_parse_stream_start(parser, event) + + case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, true) + + case yaml_PARSE_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, false) + + case yaml_PARSE_DOCUMENT_CONTENT_STATE: + return yaml_parser_parse_document_content(parser, event) + + case yaml_PARSE_DOCUMENT_END_STATE: + return yaml_parser_parse_document_end(parser, event) + + case yaml_PARSE_BLOCK_NODE_STATE: + return yaml_parser_parse_node(parser, event, true, false) + + case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return yaml_parser_parse_node(parser, event, true, true) + + case yaml_PARSE_FLOW_NODE_STATE: + return yaml_parser_parse_node(parser, event, false, false) + + case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, true) + + case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, false) + + case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_indentless_sequence_entry(parser, event) + + case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, true) + + case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, false) + + case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: + return yaml_parser_parse_block_mapping_value(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, true) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, false) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) + + case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, true) + + case yaml_PARSE_FLOW_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, false) + + case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, false) + + case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, true) + + default: + panic("invalid parser state") + } +} + +// Parse the production: +// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END +// ************ +func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_STREAM_START_TOKEN { + return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) + } + parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE + *event = yaml_event_t{ + typ: yaml_STREAM_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + encoding: token.encoding, + } + skip_token(parser) + return true +} + +// Parse the productions: +// implicit_document ::= block_node DOCUMENT-END* +// * +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// ************************* +func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { + + token := peek_token(parser) + if token == nil { + return false + } + + // Parse extra document end indicators. + if !implicit { + for token.typ == yaml_DOCUMENT_END_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } + + if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && + token.typ != yaml_TAG_DIRECTIVE_TOKEN && + token.typ != yaml_DOCUMENT_START_TOKEN && + token.typ != yaml_STREAM_END_TOKEN { + // Parse an implicit document. + if !yaml_parser_process_directives(parser, nil, nil) { + return false + } + parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) + parser.state = yaml_PARSE_BLOCK_NODE_STATE + + var head_comment []byte + if len(parser.head_comment) > 0 { + // [Go] Scan the header comment backwards, and if an empty line is found, break + // the header so the part before the last empty line goes into the + // document header, while the bottom of it goes into a follow up event. + for i := len(parser.head_comment) - 1; i > 0; i-- { + if parser.head_comment[i] == '\n' { + if i == len(parser.head_comment)-1 { + head_comment = parser.head_comment[:i] + parser.head_comment = parser.head_comment[i+1:] + break + } else if parser.head_comment[i-1] == '\n' { + head_comment = parser.head_comment[:i-1] + parser.head_comment = parser.head_comment[i+1:] + break + } + } + } + } + + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + + head_comment: head_comment, + } + + } else if token.typ != yaml_STREAM_END_TOKEN { + // Parse an explicit document. + var version_directive *yaml_version_directive_t + var tag_directives []yaml_tag_directive_t + start_mark := token.start_mark + if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { + return false + } + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_DOCUMENT_START_TOKEN { + yaml_parser_set_parser_error(parser, + "did not find expected ", token.start_mark) + return false + } + parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) + parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE + end_mark := token.end_mark + + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + version_directive: version_directive, + tag_directives: tag_directives, + implicit: false, + } + skip_token(parser) + + } else { + // Parse the stream end. + parser.state = yaml_PARSE_END_STATE + *event = yaml_event_t{ + typ: yaml_STREAM_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + skip_token(parser) + } + + return true +} + +// Parse the productions: +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// *********** +// +func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || + token.typ == yaml_TAG_DIRECTIVE_TOKEN || + token.typ == yaml_DOCUMENT_START_TOKEN || + token.typ == yaml_DOCUMENT_END_TOKEN || + token.typ == yaml_STREAM_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + return yaml_parser_process_empty_scalar(parser, event, + token.start_mark) + } + return yaml_parser_parse_node(parser, event, true, false) +} + +// Parse the productions: +// implicit_document ::= block_node DOCUMENT-END* +// ************* +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// +func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + start_mark := token.start_mark + end_mark := token.start_mark + + implicit := true + if token.typ == yaml_DOCUMENT_END_TOKEN { + end_mark = token.end_mark + skip_token(parser) + implicit = false + } + + parser.tag_directives = parser.tag_directives[:0] + + parser.state = yaml_PARSE_DOCUMENT_START_STATE + *event = yaml_event_t{ + typ: yaml_DOCUMENT_END_EVENT, + start_mark: start_mark, + end_mark: end_mark, + implicit: implicit, + } + yaml_parser_set_event_comments(parser, event) + if len(event.head_comment) > 0 && len(event.foot_comment) == 0 { + event.foot_comment = event.head_comment + event.head_comment = nil + } + return true +} + +func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) { + event.head_comment = parser.head_comment + event.line_comment = parser.line_comment + event.foot_comment = parser.foot_comment + parser.head_comment = nil + parser.line_comment = nil + parser.foot_comment = nil + parser.tail_comment = nil + parser.stem_comment = nil +} + +// Parse the productions: +// block_node_or_indentless_sequence ::= +// ALIAS +// ***** +// | properties (block_content | indentless_block_sequence)? +// ********** * +// | block_content | indentless_block_sequence +// * +// block_node ::= ALIAS +// ***** +// | properties block_content? +// ********** * +// | block_content +// * +// flow_node ::= ALIAS +// ***** +// | properties flow_content? +// ********** * +// | flow_content +// * +// properties ::= TAG ANCHOR? | ANCHOR TAG? +// ************************* +// block_content ::= block_collection | flow_collection | SCALAR +// ****** +// flow_content ::= flow_collection | SCALAR +// ****** +func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { + //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_ALIAS_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + *event = yaml_event_t{ + typ: yaml_ALIAS_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + anchor: token.value, + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true + } + + start_mark := token.start_mark + end_mark := token.start_mark + + var tag_token bool + var tag_handle, tag_suffix, anchor []byte + var tag_mark yaml_mark_t + if token.typ == yaml_ANCHOR_TOKEN { + anchor = token.value + start_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_TAG_TOKEN { + tag_token = true + tag_handle = token.value + tag_suffix = token.suffix + tag_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } else if token.typ == yaml_TAG_TOKEN { + tag_token = true + tag_handle = token.value + tag_suffix = token.suffix + start_mark = token.start_mark + tag_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_ANCHOR_TOKEN { + anchor = token.value + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } + + var tag []byte + if tag_token { + if len(tag_handle) == 0 { + tag = tag_suffix + tag_suffix = nil + } else { + for i := range parser.tag_directives { + if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { + tag = append([]byte(nil), parser.tag_directives[i].prefix...) + tag = append(tag, tag_suffix...) + break + } + } + if len(tag) == 0 { + yaml_parser_set_parser_error_context(parser, + "while parsing a node", start_mark, + "found undefined tag handle", tag_mark) + return false + } + } + } + + implicit := len(tag) == 0 + if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), + } + return true + } + if token.typ == yaml_SCALAR_TOKEN { + var plain_implicit, quoted_implicit bool + end_mark = token.end_mark + if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { + plain_implicit = true + } else if len(tag) == 0 { + quoted_implicit = true + } + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + value: token.value, + implicit: plain_implicit, + quoted_implicit: quoted_implicit, + style: yaml_style_t(token.style), + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true + } + if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { + // [Go] Some of the events below can be merged as they differ only on style. + end_mark = token.end_mark + parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), + } + yaml_parser_set_event_comments(parser, event) + return true + } + if token.typ == yaml_FLOW_MAPPING_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), + } + yaml_parser_set_event_comments(parser, event) + return true + } + if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), + } + if parser.stem_comment != nil { + event.head_comment = parser.stem_comment + parser.stem_comment = nil + } + return true + } + if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), + } + if parser.stem_comment != nil { + event.head_comment = parser.stem_comment + parser.stem_comment = nil + } + return true + } + if len(anchor) > 0 || len(tag) > 0 { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + quoted_implicit: false, + style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), + } + return true + } + + context := "while parsing a flow node" + if block { + context = "while parsing a block node" + } + yaml_parser_set_parser_error_context(parser, context, start_mark, + "did not find expected node content", token.start_mark) + return false +} + +// Parse the productions: +// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END +// ******************** *********** * ********* +// +func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_BLOCK_ENTRY_TOKEN { + mark := token.end_mark + prior_head_len := len(parser.head_comment) + skip_token(parser) + yaml_parser_split_stem_comment(parser, prior_head_len) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, true, false) + } else { + parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + } + if token.typ == yaml_BLOCK_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + + skip_token(parser) + return true + } + + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a block collection", context_mark, + "did not find expected '-' indicator", token.start_mark) +} + +// Parse the productions: +// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ +// *********** * +func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_BLOCK_ENTRY_TOKEN { + mark := token.end_mark + prior_head_len := len(parser.head_comment) + skip_token(parser) + yaml_parser_split_stem_comment(parser, prior_head_len) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_BLOCK_ENTRY_TOKEN && + token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, true, false) + } + parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? + } + return true +} + +// Split stem comment from head comment. +// +// When a sequence or map is found under a sequence entry, the former head comment +// is assigned to the underlying sequence or map as a whole, not the individual +// sequence or map entry as would be expected otherwise. To handle this case the +// previous head comment is moved aside as the stem comment. +func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { + if stem_len == 0 { + return + } + + token := peek_token(parser) + if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { + return + } + + parser.stem_comment = parser.head_comment[:stem_len] + if len(parser.head_comment) == stem_len { + parser.head_comment = nil + } else { + // Copy suffix to prevent very strange bugs if someone ever appends + // further bytes to the prefix in the stem_comment slice above. + parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...) + } +} + +// Parse the productions: +// block_mapping ::= BLOCK-MAPPING_START +// ******************* +// ((KEY block_node_or_indentless_sequence?)? +// *** * +// (VALUE block_node_or_indentless_sequence?)?)* +// +// BLOCK-END +// ********* +// +func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + // [Go] A tail comment was left from the prior mapping value processed. Emit an event + // as it needs to be processed with that value and not the following key. + if len(parser.tail_comment) > 0 { + *event = yaml_event_t{ + typ: yaml_TAIL_COMMENT_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + foot_comment: parser.tail_comment, + } + parser.tail_comment = nil + return true + } + + if token.typ == yaml_KEY_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, true, true) + } else { + parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + } else if token.typ == yaml_BLOCK_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true + } + + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a block mapping", context_mark, + "did not find expected key", token.start_mark) +} + +// Parse the productions: +// block_mapping ::= BLOCK-MAPPING_START +// +// ((KEY block_node_or_indentless_sequence?)? +// +// (VALUE block_node_or_indentless_sequence?)?)* +// ***** * +// BLOCK-END +// +// +func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VALUE_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) + return yaml_parser_parse_node(parser, event, true, true) + } + parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Parse the productions: +// flow_sequence ::= FLOW-SEQUENCE-START +// ******************* +// (flow_sequence_entry FLOW-ENTRY)* +// * ********** +// flow_sequence_entry? +// * +// FLOW-SEQUENCE-END +// ***************** +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * +// +func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + if !first { + if token.typ == yaml_FLOW_ENTRY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } else { + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow sequence", context_mark, + "did not find expected ',' or ']'", token.start_mark) + } + } + + if token.typ == yaml_KEY_TOKEN { + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + implicit: true, + style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), + } + skip_token(parser) + return true + } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + yaml_parser_set_event_comments(parser, event) + + skip_token(parser) + return true +} + +// +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// *** * +// +func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_FLOW_ENTRY_TOKEN && + token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + mark := token.end_mark + skip_token(parser) + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) +} + +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// ***** * +// +func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VALUE_TOKEN { + skip_token(parser) + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * +// +func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? + } + return true +} + +// Parse the productions: +// flow_mapping ::= FLOW-MAPPING-START +// ****************** +// (flow_mapping_entry FLOW-ENTRY)* +// * ********** +// flow_mapping_entry? +// ****************** +// FLOW-MAPPING-END +// **************** +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * *** * +// +func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ != yaml_FLOW_MAPPING_END_TOKEN { + if !first { + if token.typ == yaml_FLOW_ENTRY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } else { + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow mapping", context_mark, + "did not find expected ',' or '}'", token.start_mark) + } + } + + if token.typ == yaml_KEY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_FLOW_ENTRY_TOKEN && + token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } else { + parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) + } + } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true +} + +// Parse the productions: +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * ***** * +// +func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { + token := peek_token(parser) + if token == nil { + return false + } + if empty { + parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) + } + if token.typ == yaml_VALUE_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Generate an empty scalar event. +func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: mark, + end_mark: mark, + value: nil, // Empty + implicit: true, + style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), + } + return true +} + +var default_tag_directives = []yaml_tag_directive_t{ + {[]byte("!"), []byte("!")}, + {[]byte("!!"), []byte("tag:yaml.org,2002:")}, +} + +// Parse directives. +func yaml_parser_process_directives(parser *yaml_parser_t, + version_directive_ref **yaml_version_directive_t, + tag_directives_ref *[]yaml_tag_directive_t) bool { + + var version_directive *yaml_version_directive_t + var tag_directives []yaml_tag_directive_t + + token := peek_token(parser) + if token == nil { + return false + } + + for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { + if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { + if version_directive != nil { + yaml_parser_set_parser_error(parser, + "found duplicate %YAML directive", token.start_mark) + return false + } + if token.major != 1 || token.minor != 1 { + yaml_parser_set_parser_error(parser, + "found incompatible YAML document", token.start_mark) + return false + } + version_directive = &yaml_version_directive_t{ + major: token.major, + minor: token.minor, + } + } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { + value := yaml_tag_directive_t{ + handle: token.value, + prefix: token.prefix, + } + if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { + return false + } + tag_directives = append(tag_directives, value) + } + + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + + for i := range default_tag_directives { + if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { + return false + } + } + + if version_directive_ref != nil { + *version_directive_ref = version_directive + } + if tag_directives_ref != nil { + *tag_directives_ref = tag_directives + } + return true +} + +// Append a tag directive to the directives stack. +func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { + for i := range parser.tag_directives { + if bytes.Equal(value.handle, parser.tag_directives[i].handle) { + if allow_duplicates { + return true + } + return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) + } + } + + // [Go] I suspect the copy is unnecessary. This was likely done + // because there was no way to track ownership of the data. + value_copy := yaml_tag_directive_t{ + handle: make([]byte, len(value.handle)), + prefix: make([]byte, len(value.prefix)), + } + copy(value_copy.handle, value.handle) + copy(value_copy.prefix, value.prefix) + parser.tag_directives = append(parser.tag_directives, value_copy) + return true +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/readerc.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/readerc.go new file mode 100644 index 00000000000..b7de0a89c46 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/readerc.go @@ -0,0 +1,434 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +import ( + "io" +) + +// Set the reader error and return 0. +func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { + parser.error = yaml_READER_ERROR + parser.problem = problem + parser.problem_offset = offset + parser.problem_value = value + return false +} + +// Byte order marks. +const ( + bom_UTF8 = "\xef\xbb\xbf" + bom_UTF16LE = "\xff\xfe" + bom_UTF16BE = "\xfe\xff" +) + +// Determine the input stream encoding by checking the BOM symbol. If no BOM is +// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. +func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { + // Ensure that we had enough bytes in the raw buffer. + for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { + if !yaml_parser_update_raw_buffer(parser) { + return false + } + } + + // Determine the encoding. + buf := parser.raw_buffer + pos := parser.raw_buffer_pos + avail := len(buf) - pos + if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { + parser.encoding = yaml_UTF16LE_ENCODING + parser.raw_buffer_pos += 2 + parser.offset += 2 + } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { + parser.encoding = yaml_UTF16BE_ENCODING + parser.raw_buffer_pos += 2 + parser.offset += 2 + } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { + parser.encoding = yaml_UTF8_ENCODING + parser.raw_buffer_pos += 3 + parser.offset += 3 + } else { + parser.encoding = yaml_UTF8_ENCODING + } + return true +} + +// Update the raw buffer. +func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { + size_read := 0 + + // Return if the raw buffer is full. + if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { + return true + } + + // Return on EOF. + if parser.eof { + return true + } + + // Move the remaining bytes in the raw buffer to the beginning. + if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { + copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) + } + parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] + parser.raw_buffer_pos = 0 + + // Call the read handler to fill the buffer. + size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) + parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] + if err == io.EOF { + parser.eof = true + } else if err != nil { + return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) + } + return true +} + +// Ensure that the buffer contains at least `length` characters. +// Return true on success, false on failure. +// +// The length is supposed to be significantly less that the buffer size. +func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { + if parser.read_handler == nil { + panic("read handler must be set") + } + + // [Go] This function was changed to guarantee the requested length size at EOF. + // The fact we need to do this is pretty awful, but the description above implies + // for that to be the case, and there are tests + + // If the EOF flag is set and the raw buffer is empty, do nothing. + if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { + // [Go] ACTUALLY! Read the documentation of this function above. + // This is just broken. To return true, we need to have the + // given length in the buffer. Not doing that means every single + // check that calls this function to make sure the buffer has a + // given length is Go) panicking; or C) accessing invalid memory. + //return true + } + + // Return if the buffer contains enough characters. + if parser.unread >= length { + return true + } + + // Determine the input encoding if it is not known yet. + if parser.encoding == yaml_ANY_ENCODING { + if !yaml_parser_determine_encoding(parser) { + return false + } + } + + // Move the unread characters to the beginning of the buffer. + buffer_len := len(parser.buffer) + if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { + copy(parser.buffer, parser.buffer[parser.buffer_pos:]) + buffer_len -= parser.buffer_pos + parser.buffer_pos = 0 + } else if parser.buffer_pos == buffer_len { + buffer_len = 0 + parser.buffer_pos = 0 + } + + // Open the whole buffer for writing, and cut it before returning. + parser.buffer = parser.buffer[:cap(parser.buffer)] + + // Fill the buffer until it has enough characters. + first := true + for parser.unread < length { + + // Fill the raw buffer if necessary. + if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { + if !yaml_parser_update_raw_buffer(parser) { + parser.buffer = parser.buffer[:buffer_len] + return false + } + } + first = false + + // Decode the raw buffer. + inner: + for parser.raw_buffer_pos != len(parser.raw_buffer) { + var value rune + var width int + + raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos + + // Decode the next character. + switch parser.encoding { + case yaml_UTF8_ENCODING: + // Decode a UTF-8 character. Check RFC 3629 + // (http://www.ietf.org/rfc/rfc3629.txt) for more details. + // + // The following table (taken from the RFC) is used for + // decoding. + // + // Char. number range | UTF-8 octet sequence + // (hexadecimal) | (binary) + // --------------------+------------------------------------ + // 0000 0000-0000 007F | 0xxxxxxx + // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // + // Additionally, the characters in the range 0xD800-0xDFFF + // are prohibited as they are reserved for use with UTF-16 + // surrogate pairs. + + // Determine the length of the UTF-8 sequence. + octet := parser.raw_buffer[parser.raw_buffer_pos] + switch { + case octet&0x80 == 0x00: + width = 1 + case octet&0xE0 == 0xC0: + width = 2 + case octet&0xF0 == 0xE0: + width = 3 + case octet&0xF8 == 0xF0: + width = 4 + default: + // The leading octet is invalid. + return yaml_parser_set_reader_error(parser, + "invalid leading UTF-8 octet", + parser.offset, int(octet)) + } + + // Check if the raw buffer contains an incomplete character. + if width > raw_unread { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-8 octet sequence", + parser.offset, -1) + } + break inner + } + + // Decode the leading octet. + switch { + case octet&0x80 == 0x00: + value = rune(octet & 0x7F) + case octet&0xE0 == 0xC0: + value = rune(octet & 0x1F) + case octet&0xF0 == 0xE0: + value = rune(octet & 0x0F) + case octet&0xF8 == 0xF0: + value = rune(octet & 0x07) + default: + value = 0 + } + + // Check and decode the trailing octets. + for k := 1; k < width; k++ { + octet = parser.raw_buffer[parser.raw_buffer_pos+k] + + // Check if the octet is valid. + if (octet & 0xC0) != 0x80 { + return yaml_parser_set_reader_error(parser, + "invalid trailing UTF-8 octet", + parser.offset+k, int(octet)) + } + + // Decode the octet. + value = (value << 6) + rune(octet&0x3F) + } + + // Check the length of the sequence against the value. + switch { + case width == 1: + case width == 2 && value >= 0x80: + case width == 3 && value >= 0x800: + case width == 4 && value >= 0x10000: + default: + return yaml_parser_set_reader_error(parser, + "invalid length of a UTF-8 sequence", + parser.offset, -1) + } + + // Check the range of the value. + if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { + return yaml_parser_set_reader_error(parser, + "invalid Unicode character", + parser.offset, int(value)) + } + + case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: + var low, high int + if parser.encoding == yaml_UTF16LE_ENCODING { + low, high = 0, 1 + } else { + low, high = 1, 0 + } + + // The UTF-16 encoding is not as simple as one might + // naively think. Check RFC 2781 + // (http://www.ietf.org/rfc/rfc2781.txt). + // + // Normally, two subsequent bytes describe a Unicode + // character. However a special technique (called a + // surrogate pair) is used for specifying character + // values larger than 0xFFFF. + // + // A surrogate pair consists of two pseudo-characters: + // high surrogate area (0xD800-0xDBFF) + // low surrogate area (0xDC00-0xDFFF) + // + // The following formulas are used for decoding + // and encoding characters using surrogate pairs: + // + // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) + // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) + // W1 = 110110yyyyyyyyyy + // W2 = 110111xxxxxxxxxx + // + // where U is the character value, W1 is the high surrogate + // area, W2 is the low surrogate area. + + // Check for incomplete UTF-16 character. + if raw_unread < 2 { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 character", + parser.offset, -1) + } + break inner + } + + // Get the character. + value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + + (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) + + // Check for unexpected low surrogate area. + if value&0xFC00 == 0xDC00 { + return yaml_parser_set_reader_error(parser, + "unexpected low surrogate area", + parser.offset, int(value)) + } + + // Check for a high surrogate area. + if value&0xFC00 == 0xD800 { + width = 4 + + // Check for incomplete surrogate pair. + if raw_unread < 4 { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 surrogate pair", + parser.offset, -1) + } + break inner + } + + // Get the next character. + value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + + (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) + + // Check for a low surrogate area. + if value2&0xFC00 != 0xDC00 { + return yaml_parser_set_reader_error(parser, + "expected low surrogate area", + parser.offset+2, int(value2)) + } + + // Generate the value of the surrogate pair. + value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) + } else { + width = 2 + } + + default: + panic("impossible") + } + + // Check if the character is in the allowed range: + // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) + // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) + // | [#x10000-#x10FFFF] (32 bit) + switch { + case value == 0x09: + case value == 0x0A: + case value == 0x0D: + case value >= 0x20 && value <= 0x7E: + case value == 0x85: + case value >= 0xA0 && value <= 0xD7FF: + case value >= 0xE000 && value <= 0xFFFD: + case value >= 0x10000 && value <= 0x10FFFF: + default: + return yaml_parser_set_reader_error(parser, + "control characters are not allowed", + parser.offset, int(value)) + } + + // Move the raw pointers. + parser.raw_buffer_pos += width + parser.offset += width + + // Finally put the character into the buffer. + if value <= 0x7F { + // 0000 0000-0000 007F . 0xxxxxxx + parser.buffer[buffer_len+0] = byte(value) + buffer_len += 1 + } else if value <= 0x7FF { + // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) + parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) + buffer_len += 2 + } else if value <= 0xFFFF { + // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) + parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) + parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) + buffer_len += 3 + } else { + // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) + parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) + parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) + parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) + buffer_len += 4 + } + + parser.unread++ + } + + // On EOF, put NUL into the buffer and return. + if parser.eof { + parser.buffer[buffer_len] = 0 + buffer_len++ + parser.unread++ + break + } + } + // [Go] Read the documentation of this function above. To return true, + // we need to have the given length in the buffer. Not doing that means + // every single check that calls this function to make sure the buffer + // has a given length is Go) panicking; or C) accessing invalid memory. + // This happens here due to the EOF above breaking early. + for buffer_len < length { + parser.buffer[buffer_len] = 0 + buffer_len++ + } + parser.buffer = parser.buffer[:buffer_len] + return true +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/resolve.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/resolve.go new file mode 100644 index 00000000000..64ae888057a --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/resolve.go @@ -0,0 +1,326 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// 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. + +package yaml + +import ( + "encoding/base64" + "math" + "regexp" + "strconv" + "strings" + "time" +) + +type resolveMapItem struct { + value interface{} + tag string +} + +var resolveTable = make([]byte, 256) +var resolveMap = make(map[string]resolveMapItem) + +func init() { + t := resolveTable + t[int('+')] = 'S' // Sign + t[int('-')] = 'S' + for _, c := range "0123456789" { + t[int(c)] = 'D' // Digit + } + for _, c := range "yYnNtTfFoO~" { + t[int(c)] = 'M' // In map + } + t[int('.')] = '.' // Float (potentially in map) + + var resolveMapList = []struct { + v interface{} + tag string + l []string + }{ + {true, boolTag, []string{"true", "True", "TRUE"}}, + {false, boolTag, []string{"false", "False", "FALSE"}}, + {nil, nullTag, []string{"", "~", "null", "Null", "NULL"}}, + {math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}}, + {math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}}, + {math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}}, + {math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}}, + {"<<", mergeTag, []string{"<<"}}, + } + + m := resolveMap + for _, item := range resolveMapList { + for _, s := range item.l { + m[s] = resolveMapItem{item.v, item.tag} + } + } +} + +const ( + nullTag = "!!null" + boolTag = "!!bool" + strTag = "!!str" + intTag = "!!int" + floatTag = "!!float" + timestampTag = "!!timestamp" + seqTag = "!!seq" + mapTag = "!!map" + binaryTag = "!!binary" + mergeTag = "!!merge" +) + +var longTags = make(map[string]string) +var shortTags = make(map[string]string) + +func init() { + for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} { + ltag := longTag(stag) + longTags[stag] = ltag + shortTags[ltag] = stag + } +} + +const longTagPrefix = "tag:yaml.org,2002:" + +func shortTag(tag string) string { + if strings.HasPrefix(tag, longTagPrefix) { + if stag, ok := shortTags[tag]; ok { + return stag + } + return "!!" + tag[len(longTagPrefix):] + } + return tag +} + +func longTag(tag string) string { + if strings.HasPrefix(tag, "!!") { + if ltag, ok := longTags[tag]; ok { + return ltag + } + return longTagPrefix + tag[2:] + } + return tag +} + +func resolvableTag(tag string) bool { + switch tag { + case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag: + return true + } + return false +} + +var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`) + +func resolve(tag string, in string) (rtag string, out interface{}) { + tag = shortTag(tag) + if !resolvableTag(tag) { + return tag, in + } + + defer func() { + switch tag { + case "", rtag, strTag, binaryTag: + return + case floatTag: + if rtag == intTag { + switch v := out.(type) { + case int64: + rtag = floatTag + out = float64(v) + return + case int: + rtag = floatTag + out = float64(v) + return + } + } + } + failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) + }() + + // Any data is accepted as a !!str or !!binary. + // Otherwise, the prefix is enough of a hint about what it might be. + hint := byte('N') + if in != "" { + hint = resolveTable[in[0]] + } + if hint != 0 && tag != strTag && tag != binaryTag { + // Handle things we can lookup in a map. + if item, ok := resolveMap[in]; ok { + return item.tag, item.value + } + + // Base 60 floats are a bad idea, were dropped in YAML 1.2, and + // are purposefully unsupported here. They're still quoted on + // the way out for compatibility with other parser, though. + + switch hint { + case 'M': + // We've already checked the map above. + + case '.': + // Not in the map, so maybe a normal float. + floatv, err := strconv.ParseFloat(in, 64) + if err == nil { + return floatTag, floatv + } + + case 'D', 'S': + // Int, float, or timestamp. + // Only try values as a timestamp if the value is unquoted or there's an explicit + // !!timestamp tag. + if tag == "" || tag == timestampTag { + t, ok := parseTimestamp(in) + if ok { + return timestampTag, t + } + } + + plain := strings.Replace(in, "_", "", -1) + intv, err := strconv.ParseInt(plain, 0, 64) + if err == nil { + if intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + uintv, err := strconv.ParseUint(plain, 0, 64) + if err == nil { + return intTag, uintv + } + if yamlStyleFloat.MatchString(plain) { + floatv, err := strconv.ParseFloat(plain, 64) + if err == nil { + return floatTag, floatv + } + } + if strings.HasPrefix(plain, "0b") { + intv, err := strconv.ParseInt(plain[2:], 2, 64) + if err == nil { + if intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + uintv, err := strconv.ParseUint(plain[2:], 2, 64) + if err == nil { + return intTag, uintv + } + } else if strings.HasPrefix(plain, "-0b") { + intv, err := strconv.ParseInt("-"+plain[3:], 2, 64) + if err == nil { + if true || intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + } + // Octals as introduced in version 1.2 of the spec. + // Octals from the 1.1 spec, spelled as 0777, are still + // decoded by default in v3 as well for compatibility. + // May be dropped in v4 depending on how usage evolves. + if strings.HasPrefix(plain, "0o") { + intv, err := strconv.ParseInt(plain[2:], 8, 64) + if err == nil { + if intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + uintv, err := strconv.ParseUint(plain[2:], 8, 64) + if err == nil { + return intTag, uintv + } + } else if strings.HasPrefix(plain, "-0o") { + intv, err := strconv.ParseInt("-"+plain[3:], 8, 64) + if err == nil { + if true || intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + } + default: + panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")") + } + } + return strTag, in +} + +// encodeBase64 encodes s as base64 that is broken up into multiple lines +// as appropriate for the resulting length. +func encodeBase64(s string) string { + const lineLen = 70 + encLen := base64.StdEncoding.EncodedLen(len(s)) + lines := encLen/lineLen + 1 + buf := make([]byte, encLen*2+lines) + in := buf[0:encLen] + out := buf[encLen:] + base64.StdEncoding.Encode(in, []byte(s)) + k := 0 + for i := 0; i < len(in); i += lineLen { + j := i + lineLen + if j > len(in) { + j = len(in) + } + k += copy(out[k:], in[i:j]) + if lines > 1 { + out[k] = '\n' + k++ + } + } + return string(out[:k]) +} + +// This is a subset of the formats allowed by the regular expression +// defined at http://yaml.org/type/timestamp.html. +var allowedTimestampFormats = []string{ + "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. + "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". + "2006-1-2 15:4:5.999999999", // space separated with no time zone + "2006-1-2", // date only + // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" + // from the set of examples. +} + +// parseTimestamp parses s as a timestamp string and +// returns the timestamp and reports whether it succeeded. +// Timestamp formats are defined at http://yaml.org/type/timestamp.html +func parseTimestamp(s string) (time.Time, bool) { + // TODO write code to check all the formats supported by + // http://yaml.org/type/timestamp.html instead of using time.Parse. + + // Quick check: all date formats start with YYYY-. + i := 0 + for ; i < len(s); i++ { + if c := s[i]; c < '0' || c > '9' { + break + } + } + if i != 4 || i == len(s) || s[i] != '-' { + return time.Time{}, false + } + for _, format := range allowedTimestampFormats { + if t, err := time.Parse(format, s); err == nil { + return t, true + } + } + return time.Time{}, false +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/scannerc.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/scannerc.go new file mode 100644 index 00000000000..ca0070108f4 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/scannerc.go @@ -0,0 +1,3038 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +import ( + "bytes" + "fmt" +) + +// Introduction +// ************ +// +// The following notes assume that you are familiar with the YAML specification +// (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 +// divided on two steps: Scanning and Parsing. +// +// The Scanner transforms the input stream into a sequence of tokens, while the +// parser transform the sequence of tokens produced by the Scanner into a +// sequence of parsing events. +// +// The Scanner is rather clever and complicated. The Parser, on the contrary, +// is a straightforward implementation of a recursive-descendant parser (or, +// LL(1) parser, as it is usually called). +// +// Actually there are two issues of Scanning that might be called "clever", the +// rest is quite straightforward. The issues are "block collection start" and +// "simple keys". Both issues are explained below in details. +// +// Here the Scanning step is explained and implemented. We start with the list +// of all the tokens produced by the Scanner together with short descriptions. +// +// Now, tokens: +// +// STREAM-START(encoding) # The stream start. +// STREAM-END # The stream end. +// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. +// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. +// DOCUMENT-START # '---' +// DOCUMENT-END # '...' +// BLOCK-SEQUENCE-START # Indentation increase denoting a block +// BLOCK-MAPPING-START # sequence or a block mapping. +// BLOCK-END # Indentation decrease. +// FLOW-SEQUENCE-START # '[' +// FLOW-SEQUENCE-END # ']' +// BLOCK-SEQUENCE-START # '{' +// BLOCK-SEQUENCE-END # '}' +// BLOCK-ENTRY # '-' +// FLOW-ENTRY # ',' +// KEY # '?' or nothing (simple keys). +// VALUE # ':' +// ALIAS(anchor) # '*anchor' +// ANCHOR(anchor) # '&anchor' +// TAG(handle,suffix) # '!handle!suffix' +// SCALAR(value,style) # A scalar. +// +// The following two tokens are "virtual" tokens denoting the beginning and the +// end of the stream: +// +// STREAM-START(encoding) +// STREAM-END +// +// We pass the information about the input stream encoding with the +// STREAM-START token. +// +// The next two tokens are responsible for tags: +// +// VERSION-DIRECTIVE(major,minor) +// TAG-DIRECTIVE(handle,prefix) +// +// Example: +// +// %YAML 1.1 +// %TAG ! !foo +// %TAG !yaml! tag:yaml.org,2002: +// --- +// +// The correspoding sequence of tokens: +// +// STREAM-START(utf-8) +// VERSION-DIRECTIVE(1,1) +// TAG-DIRECTIVE("!","!foo") +// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") +// DOCUMENT-START +// STREAM-END +// +// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole +// line. +// +// The document start and end indicators are represented by: +// +// DOCUMENT-START +// DOCUMENT-END +// +// Note that if a YAML stream contains an implicit document (without '---' +// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be +// produced. +// +// In the following examples, we present whole documents together with the +// produced tokens. +// +// 1. An implicit document: +// +// 'a scalar' +// +// Tokens: +// +// STREAM-START(utf-8) +// SCALAR("a scalar",single-quoted) +// STREAM-END +// +// 2. An explicit document: +// +// --- +// 'a scalar' +// ... +// +// Tokens: +// +// STREAM-START(utf-8) +// DOCUMENT-START +// SCALAR("a scalar",single-quoted) +// DOCUMENT-END +// STREAM-END +// +// 3. Several documents in a stream: +// +// 'a scalar' +// --- +// 'another scalar' +// --- +// 'yet another scalar' +// +// Tokens: +// +// STREAM-START(utf-8) +// SCALAR("a scalar",single-quoted) +// DOCUMENT-START +// SCALAR("another scalar",single-quoted) +// DOCUMENT-START +// SCALAR("yet another scalar",single-quoted) +// STREAM-END +// +// We have already introduced the SCALAR token above. The following tokens are +// used to describe aliases, anchors, tag, and scalars: +// +// ALIAS(anchor) +// ANCHOR(anchor) +// TAG(handle,suffix) +// SCALAR(value,style) +// +// The following series of examples illustrate the usage of these tokens: +// +// 1. A recursive sequence: +// +// &A [ *A ] +// +// Tokens: +// +// STREAM-START(utf-8) +// ANCHOR("A") +// FLOW-SEQUENCE-START +// ALIAS("A") +// FLOW-SEQUENCE-END +// STREAM-END +// +// 2. A tagged scalar: +// +// !!float "3.14" # A good approximation. +// +// Tokens: +// +// STREAM-START(utf-8) +// TAG("!!","float") +// SCALAR("3.14",double-quoted) +// STREAM-END +// +// 3. Various scalar styles: +// +// --- # Implicit empty plain scalars do not produce tokens. +// --- a plain scalar +// --- 'a single-quoted scalar' +// --- "a double-quoted scalar" +// --- |- +// a literal scalar +// --- >- +// a folded +// scalar +// +// Tokens: +// +// STREAM-START(utf-8) +// DOCUMENT-START +// DOCUMENT-START +// SCALAR("a plain scalar",plain) +// DOCUMENT-START +// SCALAR("a single-quoted scalar",single-quoted) +// DOCUMENT-START +// SCALAR("a double-quoted scalar",double-quoted) +// DOCUMENT-START +// SCALAR("a literal scalar",literal) +// DOCUMENT-START +// SCALAR("a folded scalar",folded) +// STREAM-END +// +// Now it's time to review collection-related tokens. We will start with +// flow collections: +// +// FLOW-SEQUENCE-START +// FLOW-SEQUENCE-END +// FLOW-MAPPING-START +// FLOW-MAPPING-END +// FLOW-ENTRY +// KEY +// VALUE +// +// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and +// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' +// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the +// indicators '?' and ':', which are used for denoting mapping keys and values, +// are represented by the KEY and VALUE tokens. +// +// The following examples show flow collections: +// +// 1. A flow sequence: +// +// [item 1, item 2, item 3] +// +// Tokens: +// +// STREAM-START(utf-8) +// FLOW-SEQUENCE-START +// SCALAR("item 1",plain) +// FLOW-ENTRY +// SCALAR("item 2",plain) +// FLOW-ENTRY +// SCALAR("item 3",plain) +// FLOW-SEQUENCE-END +// STREAM-END +// +// 2. A flow mapping: +// +// { +// a simple key: a value, # Note that the KEY token is produced. +// ? a complex key: another value, +// } +// +// Tokens: +// +// STREAM-START(utf-8) +// FLOW-MAPPING-START +// KEY +// SCALAR("a simple key",plain) +// VALUE +// SCALAR("a value",plain) +// FLOW-ENTRY +// KEY +// SCALAR("a complex key",plain) +// VALUE +// SCALAR("another value",plain) +// FLOW-ENTRY +// FLOW-MAPPING-END +// STREAM-END +// +// A simple key is a key which is not denoted by the '?' indicator. Note that +// the Scanner still produce the KEY token whenever it encounters a simple key. +// +// For scanning block collections, the following tokens are used (note that we +// repeat KEY and VALUE here): +// +// BLOCK-SEQUENCE-START +// BLOCK-MAPPING-START +// BLOCK-END +// BLOCK-ENTRY +// KEY +// VALUE +// +// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation +// increase that precedes a block collection (cf. the INDENT token in Python). +// The token BLOCK-END denote indentation decrease that ends a block collection +// (cf. the DEDENT token in Python). However YAML has some syntax pecularities +// that makes detections of these tokens more complex. +// +// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators +// '-', '?', and ':' correspondingly. +// +// The following examples show how the tokens BLOCK-SEQUENCE-START, +// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: +// +// 1. Block sequences: +// +// - item 1 +// - item 2 +// - +// - item 3.1 +// - item 3.2 +// - +// key 1: value 1 +// key 2: value 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-ENTRY +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 3.1",plain) +// BLOCK-ENTRY +// SCALAR("item 3.2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// 2. Block mappings: +// +// a simple key: a value # The KEY token is produced here. +// ? a complex key +// : another value +// a mapping: +// key 1: value 1 +// key 2: value 2 +// a sequence: +// - item 1 +// - item 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("a simple key",plain) +// VALUE +// SCALAR("a value",plain) +// KEY +// SCALAR("a complex key",plain) +// VALUE +// SCALAR("another value",plain) +// KEY +// SCALAR("a mapping",plain) +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// KEY +// SCALAR("a sequence",plain) +// VALUE +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// YAML does not always require to start a new block collection from a new +// line. If the current line contains only '-', '?', and ':' indicators, a new +// block collection may start at the current line. The following examples +// illustrate this case: +// +// 1. Collections in a sequence: +// +// - - item 1 +// - item 2 +// - key 1: value 1 +// key 2: value 2 +// - ? complex key +// : complex value +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("complex key") +// VALUE +// SCALAR("complex value") +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// 2. Collections in a mapping: +// +// ? a sequence +// : - item 1 +// - item 2 +// ? a mapping +// : key 1: value 1 +// key 2: value 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("a sequence",plain) +// VALUE +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// KEY +// SCALAR("a mapping",plain) +// VALUE +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// YAML also permits non-indented sequences if they are included into a block +// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: +// +// key: +// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. +// - item 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("key",plain) +// VALUE +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// + +// Ensure that the buffer contains the required number of characters. +// Return true on success, false on failure (reader error or memory error). +func cache(parser *yaml_parser_t, length int) bool { + // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) + return parser.unread >= length || yaml_parser_update_buffer(parser, length) +} + +// Advance the buffer pointer. +func skip(parser *yaml_parser_t) { + if !is_blank(parser.buffer, parser.buffer_pos) { + parser.newlines = 0 + } + parser.mark.index++ + parser.mark.column++ + parser.unread-- + parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) +} + +func skip_line(parser *yaml_parser_t) { + if is_crlf(parser.buffer, parser.buffer_pos) { + parser.mark.index += 2 + parser.mark.column = 0 + parser.mark.line++ + parser.unread -= 2 + parser.buffer_pos += 2 + parser.newlines++ + } else if is_break(parser.buffer, parser.buffer_pos) { + parser.mark.index++ + parser.mark.column = 0 + parser.mark.line++ + parser.unread-- + parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) + parser.newlines++ + } +} + +// Copy a character to a string buffer and advance pointers. +func read(parser *yaml_parser_t, s []byte) []byte { + if !is_blank(parser.buffer, parser.buffer_pos) { + parser.newlines = 0 + } + w := width(parser.buffer[parser.buffer_pos]) + if w == 0 { + panic("invalid character sequence") + } + if len(s) == 0 { + s = make([]byte, 0, 32) + } + if w == 1 && len(s)+w <= cap(s) { + s = s[:len(s)+1] + s[len(s)-1] = parser.buffer[parser.buffer_pos] + parser.buffer_pos++ + } else { + s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) + parser.buffer_pos += w + } + parser.mark.index++ + parser.mark.column++ + parser.unread-- + return s +} + +// Copy a line break character to a string buffer and advance pointers. +func read_line(parser *yaml_parser_t, s []byte) []byte { + buf := parser.buffer + pos := parser.buffer_pos + switch { + case buf[pos] == '\r' && buf[pos+1] == '\n': + // CR LF . LF + s = append(s, '\n') + parser.buffer_pos += 2 + parser.mark.index++ + parser.unread-- + case buf[pos] == '\r' || buf[pos] == '\n': + // CR|LF . LF + s = append(s, '\n') + parser.buffer_pos += 1 + case buf[pos] == '\xC2' && buf[pos+1] == '\x85': + // NEL . LF + s = append(s, '\n') + parser.buffer_pos += 2 + case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): + // LS|PS . LS|PS + s = append(s, buf[parser.buffer_pos:pos+3]...) + parser.buffer_pos += 3 + default: + return s + } + parser.mark.index++ + parser.mark.column = 0 + parser.mark.line++ + parser.unread-- + parser.newlines++ + return s +} + +// Get the next token. +func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { + // Erase the token object. + *token = yaml_token_t{} // [Go] Is this necessary? + + // No tokens after STREAM-END or error. + if parser.stream_end_produced || parser.error != yaml_NO_ERROR { + return true + } + + // Ensure that the tokens queue contains enough tokens. + if !parser.token_available { + if !yaml_parser_fetch_more_tokens(parser) { + return false + } + } + + // Fetch the next token from the queue. + *token = parser.tokens[parser.tokens_head] + parser.tokens_head++ + parser.tokens_parsed++ + parser.token_available = false + + if token.typ == yaml_STREAM_END_TOKEN { + parser.stream_end_produced = true + } + return true +} + +// Set the scanner error and return false. +func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { + parser.error = yaml_SCANNER_ERROR + parser.context = context + parser.context_mark = context_mark + parser.problem = problem + parser.problem_mark = parser.mark + return false +} + +func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { + context := "while parsing a tag" + if directive { + context = "while parsing a %TAG directive" + } + return yaml_parser_set_scanner_error(parser, context, context_mark, problem) +} + +func trace(args ...interface{}) func() { + pargs := append([]interface{}{"+++"}, args...) + fmt.Println(pargs...) + pargs = append([]interface{}{"---"}, args...) + return func() { fmt.Println(pargs...) } +} + +// Ensure that the tokens queue contains at least one token which can be +// returned to the Parser. +func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { + // While we need more tokens to fetch, do it. + for { + // [Go] The comment parsing logic requires a lookahead of two tokens + // so that foot comments may be parsed in time of associating them + // with the tokens that are parsed before them, and also for line + // comments to be transformed into head comments in some edge cases. + if parser.tokens_head < len(parser.tokens)-2 { + // If a potential simple key is at the head position, we need to fetch + // the next token to disambiguate it. + head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed] + if !ok { + break + } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok { + return false + } else if !valid { + break + } + } + // Fetch the next token. + if !yaml_parser_fetch_next_token(parser) { + return false + } + } + + parser.token_available = true + return true +} + +// The dispatcher for token fetchers. +func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) { + // Ensure that the buffer is initialized. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check if we just started scanning. Fetch STREAM-START then. + if !parser.stream_start_produced { + return yaml_parser_fetch_stream_start(parser) + } + + scan_mark := parser.mark + + // Eat whitespaces and comments until we reach the next token. + if !yaml_parser_scan_to_next_token(parser) { + return false + } + + // [Go] While unrolling indents, transform the head comments of prior + // indentation levels observed after scan_start into foot comments at + // the respective indexes. + + // Check the indentation level against the current column. + if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) { + return false + } + + // Ensure that the buffer contains at least 4 characters. 4 is the length + // of the longest indicators ('--- ' and '... '). + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + + // Is it the end of the stream? + if is_z(parser.buffer, parser.buffer_pos) { + return yaml_parser_fetch_stream_end(parser) + } + + // Is it a directive? + if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { + return yaml_parser_fetch_directive(parser) + } + + buf := parser.buffer + pos := parser.buffer_pos + + // Is it the document start indicator? + if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { + return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) + } + + // Is it the document end indicator? + if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { + return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) + } + + comment_mark := parser.mark + if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') { + // Associate any following comments with the prior token. + comment_mark = parser.tokens[len(parser.tokens)-1].start_mark + } + defer func() { + if !ok { + return + } + if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN { + // Sequence indicators alone have no line comments. It becomes + // a head comment for whatever follows. + return + } + if !yaml_parser_scan_line_comment(parser, comment_mark) { + ok = false + return + } + }() + + // Is it the flow sequence start indicator? + if buf[pos] == '[' { + return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) + } + + // Is it the flow mapping start indicator? + if parser.buffer[parser.buffer_pos] == '{' { + return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) + } + + // Is it the flow sequence end indicator? + if parser.buffer[parser.buffer_pos] == ']' { + return yaml_parser_fetch_flow_collection_end(parser, + yaml_FLOW_SEQUENCE_END_TOKEN) + } + + // Is it the flow mapping end indicator? + if parser.buffer[parser.buffer_pos] == '}' { + return yaml_parser_fetch_flow_collection_end(parser, + yaml_FLOW_MAPPING_END_TOKEN) + } + + // Is it the flow entry indicator? + if parser.buffer[parser.buffer_pos] == ',' { + return yaml_parser_fetch_flow_entry(parser) + } + + // Is it the block entry indicator? + if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { + return yaml_parser_fetch_block_entry(parser) + } + + // Is it the key indicator? + if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_key(parser) + } + + // Is it the value indicator? + if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_value(parser) + } + + // Is it an alias? + if parser.buffer[parser.buffer_pos] == '*' { + return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) + } + + // Is it an anchor? + if parser.buffer[parser.buffer_pos] == '&' { + return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) + } + + // Is it a tag? + if parser.buffer[parser.buffer_pos] == '!' { + return yaml_parser_fetch_tag(parser) + } + + // Is it a literal scalar? + if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { + return yaml_parser_fetch_block_scalar(parser, true) + } + + // Is it a folded scalar? + if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { + return yaml_parser_fetch_block_scalar(parser, false) + } + + // Is it a single-quoted scalar? + if parser.buffer[parser.buffer_pos] == '\'' { + return yaml_parser_fetch_flow_scalar(parser, true) + } + + // Is it a double-quoted scalar? + if parser.buffer[parser.buffer_pos] == '"' { + return yaml_parser_fetch_flow_scalar(parser, false) + } + + // Is it a plain scalar? + // + // A plain scalar may start with any non-blank characters except + // + // '-', '?', ':', ',', '[', ']', '{', '}', + // '#', '&', '*', '!', '|', '>', '\'', '\"', + // '%', '@', '`'. + // + // In the block context (and, for the '-' indicator, in the flow context + // too), it may also start with the characters + // + // '-', '?', ':' + // + // if it is followed by a non-space character. + // + // The last rule is more restrictive than the specification requires. + // [Go] TODO Make this logic more reasonable. + //switch parser.buffer[parser.buffer_pos] { + //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': + //} + if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || + parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || + parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || + parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || + parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || + parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || + parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || + parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || + parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || + (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || + (parser.flow_level == 0 && + (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && + !is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_plain_scalar(parser) + } + + // If we don't determine the token type so far, it is an error. + return yaml_parser_set_scanner_error(parser, + "while scanning for the next token", parser.mark, + "found character that cannot start any token") +} + +func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) { + if !simple_key.possible { + return false, true + } + + // The 1.2 specification says: + // + // "If the ? indicator is omitted, parsing needs to see past the + // implicit key to recognize it as such. To limit the amount of + // lookahead required, the “:” indicator must appear at most 1024 + // Unicode characters beyond the start of the key. In addition, the key + // is restricted to a single line." + // + if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index { + // Check if the potential simple key to be removed is required. + if simple_key.required { + return false, yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key.mark, + "could not find expected ':'") + } + simple_key.possible = false + return false, true + } + return true, true +} + +// Check if a simple key may start at the current position and add it if +// needed. +func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { + // A simple key is required at the current position if the scanner is in + // the block context and the current column coincides with the indentation + // level. + + required := parser.flow_level == 0 && parser.indent == parser.mark.column + + // + // If the current position may start a simple key, save it. + // + if parser.simple_key_allowed { + simple_key := yaml_simple_key_t{ + possible: true, + required: required, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + } + + if !yaml_parser_remove_simple_key(parser) { + return false + } + parser.simple_keys[len(parser.simple_keys)-1] = simple_key + parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1 + } + return true +} + +// Remove a potential simple key at the current flow level. +func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { + i := len(parser.simple_keys) - 1 + if parser.simple_keys[i].possible { + // If the key is required, it is an error. + if parser.simple_keys[i].required { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", parser.simple_keys[i].mark, + "could not find expected ':'") + } + // Remove the key from the stack. + parser.simple_keys[i].possible = false + delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number) + } + return true +} + +// max_flow_level limits the flow_level +const max_flow_level = 10000 + +// Increase the flow level and resize the simple key list if needed. +func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { + // Reset the simple key on the next level. + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{ + possible: false, + required: false, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + }) + + // Increase the flow level. + parser.flow_level++ + if parser.flow_level > max_flow_level { + return yaml_parser_set_scanner_error(parser, + "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark, + fmt.Sprintf("exceeded max depth of %d", max_flow_level)) + } + return true +} + +// Decrease the flow level. +func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { + if parser.flow_level > 0 { + parser.flow_level-- + last := len(parser.simple_keys) - 1 + delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number) + parser.simple_keys = parser.simple_keys[:last] + } + return true +} + +// max_indents limits the indents stack size +const max_indents = 10000 + +// Push the current indentation level to the stack and set the new level +// the current column is greater than the indentation level. In this case, +// append or insert the specified token into the token queue. +func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { + // In the flow context, do nothing. + if parser.flow_level > 0 { + return true + } + + if parser.indent < column { + // Push the current indentation level to the stack and set the new + // indentation level. + parser.indents = append(parser.indents, parser.indent) + parser.indent = column + if len(parser.indents) > max_indents { + return yaml_parser_set_scanner_error(parser, + "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark, + fmt.Sprintf("exceeded max depth of %d", max_indents)) + } + + // Create a token and insert it into the queue. + token := yaml_token_t{ + typ: typ, + start_mark: mark, + end_mark: mark, + } + if number > -1 { + number -= parser.tokens_parsed + } + yaml_insert_token(parser, number, &token) + } + return true +} + +// Pop indentation levels from the indents stack until the current level +// becomes less or equal to the column. For each indentation level, append +// the BLOCK-END token. +func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool { + // In the flow context, do nothing. + if parser.flow_level > 0 { + return true + } + + block_mark := scan_mark + block_mark.index-- + + // Loop through the indentation levels in the stack. + for parser.indent > column { + + // [Go] Reposition the end token before potential following + // foot comments of parent blocks. For that, search + // backwards for recent comments that were at the same + // indent as the block that is ending now. + stop_index := block_mark.index + for i := len(parser.comments) - 1; i >= 0; i-- { + comment := &parser.comments[i] + + if comment.end_mark.index < stop_index { + // Don't go back beyond the start of the comment/whitespace scan, unless column < 0. + // If requested indent column is < 0, then the document is over and everything else + // is a foot anyway. + break + } + if comment.start_mark.column == parser.indent+1 { + // This is a good match. But maybe there's a former comment + // at that same indent level, so keep searching. + block_mark = comment.start_mark + } + + // While the end of the former comment matches with + // the start of the following one, we know there's + // nothing in between and scanning is still safe. + stop_index = comment.scan_mark.index + } + + // Create a token and append it to the queue. + token := yaml_token_t{ + typ: yaml_BLOCK_END_TOKEN, + start_mark: block_mark, + end_mark: block_mark, + } + yaml_insert_token(parser, -1, &token) + + // Pop the indentation level. + parser.indent = parser.indents[len(parser.indents)-1] + parser.indents = parser.indents[:len(parser.indents)-1] + } + return true +} + +// Initialize the scanner and produce the STREAM-START token. +func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { + + // Set the initial indentation. + parser.indent = -1 + + // Initialize the simple key stack. + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) + + parser.simple_keys_by_tok = make(map[int]int) + + // A simple key is allowed at the beginning of the stream. + parser.simple_key_allowed = true + + // We have started. + parser.stream_start_produced = true + + // Create the STREAM-START token and append it to the queue. + token := yaml_token_t{ + typ: yaml_STREAM_START_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + encoding: parser.encoding, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the STREAM-END token and shut down the scanner. +func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { + + // Force new line. + if parser.mark.column != 0 { + parser.mark.column = 0 + parser.mark.line++ + } + + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1, parser.mark) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Create the STREAM-END token and append it to the queue. + token := yaml_token_t{ + typ: yaml_STREAM_END_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. +func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1, parser.mark) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. + token := yaml_token_t{} + if !yaml_parser_scan_directive(parser, &token) { + return false + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the DOCUMENT-START or DOCUMENT-END token. +func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1, parser.mark) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Consume the token. + start_mark := parser.mark + + skip(parser) + skip(parser) + skip(parser) + + end_mark := parser.mark + + // Create the DOCUMENT-START or DOCUMENT-END token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. +func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { + + // The indicators '[' and '{' may start a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // Increase the flow level. + if !yaml_parser_increase_flow_level(parser) { + return false + } + + // A simple key may follow the indicators '[' and '{'. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. +func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // Reset any potential simple key on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Decrease the flow level. + if !yaml_parser_decrease_flow_level(parser) { + return false + } + + // No simple keys after the indicators ']' and '}'. + parser.simple_key_allowed = false + + // Consume the token. + + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-ENTRY token. +func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after ','. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-ENTRY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_FLOW_ENTRY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the BLOCK-ENTRY token. +func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { + // Check if the scanner is in the block context. + if parser.flow_level == 0 { + // Check if we are allowed to start a new entry. + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "block sequence entries are not allowed in this context") + } + // Add the BLOCK-SEQUENCE-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { + return false + } + } else { + // It is an error for the '-' indicator to occur in the flow context, + // but we let the Parser detect and report about it because the Parser + // is able to point to the context. + } + + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after '-'. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the BLOCK-ENTRY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_BLOCK_ENTRY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the KEY token. +func yaml_parser_fetch_key(parser *yaml_parser_t) bool { + + // In the block context, additional checks are required. + if parser.flow_level == 0 { + // Check if we are allowed to start a new key (not nessesary simple). + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "mapping keys are not allowed in this context") + } + // Add the BLOCK-MAPPING-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { + return false + } + } + + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after '?' in the block context. + parser.simple_key_allowed = parser.flow_level == 0 + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the KEY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_KEY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the VALUE token. +func yaml_parser_fetch_value(parser *yaml_parser_t) bool { + + simple_key := &parser.simple_keys[len(parser.simple_keys)-1] + + // Have we found a simple key? + if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok { + return false + + } else if valid { + + // Create the KEY token and insert it into the queue. + token := yaml_token_t{ + typ: yaml_KEY_TOKEN, + start_mark: simple_key.mark, + end_mark: simple_key.mark, + } + yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) + + // In the block context, we may need to add the BLOCK-MAPPING-START token. + if !yaml_parser_roll_indent(parser, simple_key.mark.column, + simple_key.token_number, + yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { + return false + } + + // Remove the simple key. + simple_key.possible = false + delete(parser.simple_keys_by_tok, simple_key.token_number) + + // A simple key cannot follow another simple key. + parser.simple_key_allowed = false + + } else { + // The ':' indicator follows a complex key. + + // In the block context, extra checks are required. + if parser.flow_level == 0 { + + // Check if we are allowed to start a complex value. + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "mapping values are not allowed in this context") + } + + // Add the BLOCK-MAPPING-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { + return false + } + } + + // Simple keys after ':' are allowed in the block context. + parser.simple_key_allowed = parser.flow_level == 0 + } + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the VALUE token and append it to the queue. + token := yaml_token_t{ + typ: yaml_VALUE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the ALIAS or ANCHOR token. +func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // An anchor or an alias could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow an anchor or an alias. + parser.simple_key_allowed = false + + // Create the ALIAS or ANCHOR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_anchor(parser, &token, typ) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the TAG token. +func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { + // A tag could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a tag. + parser.simple_key_allowed = false + + // Create the TAG token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_tag(parser, &token) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. +func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { + // Remove any potential simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // A simple key may follow a block scalar. + parser.simple_key_allowed = true + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_block_scalar(parser, &token, literal) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. +func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { + // A plain scalar could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a flow scalar. + parser.simple_key_allowed = false + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_flow_scalar(parser, &token, single) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,plain) token. +func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { + // A plain scalar could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a flow scalar. + parser.simple_key_allowed = false + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_plain_scalar(parser, &token) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Eat whitespaces and comments until the next token is found. +func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { + + scan_mark := parser.mark + + // Until the next token is not found. + for { + // Allow the BOM mark to start a line. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { + skip(parser) + } + + // Eat whitespaces. + // Tabs are allowed: + // - in the flow context + // - in the block context, but not at the beginning of the line or + // after '-', '?', or ':' (complex value). + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if we just had a line comment under a sequence entry that + // looks more like a header to the following content. Similar to this: + // + // - # The comment + // - Some data + // + // If so, transform the line comment to a head comment and reposition. + if len(parser.comments) > 0 && len(parser.tokens) > 1 { + tokenA := parser.tokens[len(parser.tokens)-2] + tokenB := parser.tokens[len(parser.tokens)-1] + comment := &parser.comments[len(parser.comments)-1] + if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) { + // If it was in the prior line, reposition so it becomes a + // header of the follow up token. Otherwise, keep it in place + // so it becomes a header of the former. + comment.head = comment.line + comment.line = nil + if comment.start_mark.line == parser.mark.line-1 { + comment.token_mark = parser.mark + } + } + } + + // Eat a comment until a line break. + if parser.buffer[parser.buffer_pos] == '#' { + if !yaml_parser_scan_comments(parser, scan_mark) { + return false + } + } + + // If it is a line break, eat it. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + + // In the block context, a new line may start a simple key. + if parser.flow_level == 0 { + parser.simple_key_allowed = true + } + } else { + break // We have found a token. + } + } + + return true +} + +// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// +func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { + // Eat '%'. + start_mark := parser.mark + skip(parser) + + // Scan the directive name. + var name []byte + if !yaml_parser_scan_directive_name(parser, start_mark, &name) { + return false + } + + // Is it a YAML directive? + if bytes.Equal(name, []byte("YAML")) { + // Scan the VERSION directive value. + var major, minor int8 + if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { + return false + } + end_mark := parser.mark + + // Create a VERSION-DIRECTIVE token. + *token = yaml_token_t{ + typ: yaml_VERSION_DIRECTIVE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + major: major, + minor: minor, + } + + // Is it a TAG directive? + } else if bytes.Equal(name, []byte("TAG")) { + // Scan the TAG directive value. + var handle, prefix []byte + if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { + return false + } + end_mark := parser.mark + + // Create a TAG-DIRECTIVE token. + *token = yaml_token_t{ + typ: yaml_TAG_DIRECTIVE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: handle, + prefix: prefix, + } + + // Unknown directive. + } else { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unknown directive name") + return false + } + + // Eat the rest of the line including any comments. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + if parser.buffer[parser.buffer_pos] == '#' { + // [Go] Discard this inline comment for the time being. + //if !yaml_parser_scan_line_comment(parser, start_mark) { + // return false + //} + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // Check if we are at the end of the line. + if !is_breakz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "did not find expected comment or line break") + return false + } + + // Eat a line break. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } + + return true +} + +// Scan the directive name. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^ +// +func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { + // Consume the directive name. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + var s []byte + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the name is empty. + if len(s) == 0 { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "could not find expected directive name") + return false + } + + // Check for an blank character after the name. + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unexpected non-alphabetical character") + return false + } + *name = s + return true +} + +// Scan the value of VERSION-DIRECTIVE. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^^^ +func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { + // Eat whitespaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Consume the major version number. + if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { + return false + } + + // Eat '.'. + if parser.buffer[parser.buffer_pos] != '.' { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected digit or '.' character") + } + + skip(parser) + + // Consume the minor version number. + if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { + return false + } + return true +} + +const max_number_length = 2 + +// Scan the version number of VERSION-DIRECTIVE. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^ +// %YAML 1.1 # a comment \n +// ^ +func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { + + // Repeat while the next character is digit. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + var value, length int8 + for is_digit(parser.buffer, parser.buffer_pos) { + // Check if the number is too long. + length++ + if length > max_number_length { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "found extremely long version number") + } + value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the number was present. + if length == 0 { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected version number") + } + *number = value + return true +} + +// Scan the value of a TAG-DIRECTIVE token. +// +// Scope: +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// +func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { + var handle_value, prefix_value []byte + + // Eat whitespaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Scan a handle. + if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { + return false + } + + // Expect a whitespace. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blank(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace") + return false + } + + // Eat whitespaces. + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Scan a prefix. + if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { + return false + } + + // Expect a whitespace or line break. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace or line break") + return false + } + + *handle = handle_value + *prefix = prefix_value + return true +} + +func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { + var s []byte + + // Eat the indicator character. + start_mark := parser.mark + skip(parser) + + // Consume the value. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + end_mark := parser.mark + + /* + * Check if length of the anchor is greater than 0 and it is followed by + * a whitespace character or one of the indicators: + * + * '?', ':', ',', ']', '}', '%', '@', '`'. + */ + + if len(s) == 0 || + !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || + parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || + parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || + parser.buffer[parser.buffer_pos] == '`') { + context := "while scanning an alias" + if typ == yaml_ANCHOR_TOKEN { + context = "while scanning an anchor" + } + yaml_parser_set_scanner_error(parser, context, start_mark, + "did not find expected alphabetic or numeric character") + return false + } + + // Create a token. + *token = yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + value: s, + } + + return true +} + +/* + * Scan a TAG token. + */ + +func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { + var handle, suffix []byte + + start_mark := parser.mark + + // Check if the tag is in the canonical form. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + if parser.buffer[parser.buffer_pos+1] == '<' { + // Keep the handle as '' + + // Eat '!<' + skip(parser) + skip(parser) + + // Consume the tag value. + if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { + return false + } + + // Check for '>' and eat it. + if parser.buffer[parser.buffer_pos] != '>' { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find the expected '>'") + return false + } + + skip(parser) + } else { + // The tag has either the '!suffix' or the '!handle!suffix' form. + + // First, try to scan a handle. + if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { + return false + } + + // Check if it is, indeed, handle. + if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { + // Scan the suffix now. + if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { + return false + } + } else { + // It wasn't a handle after all. Scan the rest of the tag. + if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { + return false + } + + // Set the handle to '!'. + handle = []byte{'!'} + + // A special case: the '!' tag. Set the handle to '' and the + // suffix to '!'. + if len(suffix) == 0 { + handle, suffix = suffix, handle + } + } + } + + // Check the character which ends the tag. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find expected whitespace or line break") + return false + } + + end_mark := parser.mark + + // Create a token. + *token = yaml_token_t{ + typ: yaml_TAG_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: handle, + suffix: suffix, + } + return true +} + +// Scan a tag handle. +func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { + // Check the initial '!' character. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.buffer[parser.buffer_pos] != '!' { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected '!'") + return false + } + + var s []byte + + // Copy the '!' character. + s = read(parser, s) + + // Copy all subsequent alphabetical and numerical characters. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the trailing character is '!' and copy it. + if parser.buffer[parser.buffer_pos] == '!' { + s = read(parser, s) + } 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 && string(s) != "!" { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected '!'") + return false + } + } + + *handle = s + return true +} + +// Scan a tag. +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. + // + // Note that we don't copy the leading '!' character. + if len(head) > 1 { + s = append(s, head[1:]...) + } + + // Scan the tag. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // The set of characters that may appear in URI is as follows: + // + // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', + // '%'. + // [Go] TODO Convert this into more reasonable logic. + for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || + parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || + parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || + parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || + parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || + parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || + parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || + parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || + parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || + parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || + parser.buffer[parser.buffer_pos] == '%' { + // Check if it is a URI-escape sequence. + if parser.buffer[parser.buffer_pos] == '%' { + if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { + return false + } + } else { + s = read(parser, s) + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + hasTag = true + } + + if !hasTag { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected tag URI") + return false + } + *uri = s + return true +} + +// Decode an URI-escape sequence corresponding to a single UTF-8 character. +func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { + + // Decode the required number of characters. + w := 1024 + for w > 0 { + // Check for a URI-escaped octet. + if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { + return false + } + + if !(parser.buffer[parser.buffer_pos] == '%' && + is_hex(parser.buffer, parser.buffer_pos+1) && + is_hex(parser.buffer, parser.buffer_pos+2)) { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find URI escaped octet") + } + + // Get the octet. + octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) + + // If it is the leading octet, determine the length of the UTF-8 sequence. + if w == 1024 { + w = width(octet) + if w == 0 { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "found an incorrect leading UTF-8 octet") + } + } else { + // Check if the trailing octet is correct. + if octet&0xC0 != 0x80 { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "found an incorrect trailing UTF-8 octet") + } + } + + // Copy the octet and move the pointers. + *s = append(*s, octet) + skip(parser) + skip(parser) + skip(parser) + w-- + } + return true +} + +// Scan a block scalar. +func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { + // Eat the indicator '|' or '>'. + start_mark := parser.mark + skip(parser) + + // Scan the additional block scalar indicators. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check for a chomping indicator. + var chomping, increment int + if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { + // Set the chomping method and eat the indicator. + if parser.buffer[parser.buffer_pos] == '+' { + chomping = +1 + } else { + chomping = -1 + } + skip(parser) + + // Check for an indentation indicator. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_digit(parser.buffer, parser.buffer_pos) { + // Check that the indentation is greater than 0. + if parser.buffer[parser.buffer_pos] == '0' { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0") + return false + } + + // Get the indentation level and eat the indicator. + increment = as_digit(parser.buffer, parser.buffer_pos) + skip(parser) + } + + } else if is_digit(parser.buffer, parser.buffer_pos) { + // Do the same as above, but in the opposite order. + + if parser.buffer[parser.buffer_pos] == '0' { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0") + return false + } + increment = as_digit(parser.buffer, parser.buffer_pos) + skip(parser) + + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { + if parser.buffer[parser.buffer_pos] == '+' { + chomping = +1 + } else { + chomping = -1 + } + skip(parser) + } + } + + // Eat whitespaces and comments to the end of the line. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + if parser.buffer[parser.buffer_pos] == '#' { + if !yaml_parser_scan_line_comment(parser, start_mark) { + return false + } + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // Check if we are at the end of the line. + if !is_breakz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "did not find expected comment or line break") + return false + } + + // Eat a line break. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } + + end_mark := parser.mark + + // Set the indentation level if it was specified. + var indent int + if increment > 0 { + if parser.indent >= 0 { + indent = parser.indent + increment + } else { + indent = increment + } + } + + // Scan the leading line breaks and determine the indentation level if needed. + var s, leading_break, trailing_breaks []byte + if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { + return false + } + + // Scan the block scalar content. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + var leading_blank, trailing_blank bool + for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { + // We are at the beginning of a non-empty line. + + // Is it a trailing whitespace? + trailing_blank = is_blank(parser.buffer, parser.buffer_pos) + + // Check if we need to fold the leading line break. + if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { + // Do we need to join the lines by space? + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } + } else { + s = append(s, leading_break...) + } + leading_break = leading_break[:0] + + // Append the remaining line breaks. + s = append(s, trailing_breaks...) + trailing_breaks = trailing_breaks[:0] + + // Is it a leading whitespace? + leading_blank = is_blank(parser.buffer, parser.buffer_pos) + + // Consume the current line. + for !is_breakz(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Consume the line break. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + leading_break = read_line(parser, leading_break) + + // Eat the following indentation spaces and line breaks. + if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { + return false + } + } + + // Chomp the tail. + if chomping != -1 { + s = append(s, leading_break...) + } + if chomping == 1 { + s = append(s, trailing_breaks...) + } + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_LITERAL_SCALAR_STYLE, + } + if !literal { + token.style = yaml_FOLDED_SCALAR_STYLE + } + return true +} + +// Scan indentation spaces and line breaks for a block scalar. Determine the +// indentation level if needed. +func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { + *end_mark = parser.mark + + // Eat the indentation spaces and line breaks. + max_indent := 0 + for { + // Eat the indentation spaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + if parser.mark.column > max_indent { + max_indent = parser.mark.column + } + + // Check for a tab character messing the indentation. + if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { + return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found a tab character where an indentation space is expected") + } + + // Have we found a non-empty line? + if !is_break(parser.buffer, parser.buffer_pos) { + break + } + + // Consume the line break. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + // [Go] Should really be returning breaks instead. + *breaks = read_line(parser, *breaks) + *end_mark = parser.mark + } + + // Determine the indentation level if needed. + if *indent == 0 { + *indent = max_indent + if *indent < parser.indent+1 { + *indent = parser.indent + 1 + } + if *indent < 1 { + *indent = 1 + } + } + return true +} + +// Scan a quoted scalar. +func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { + // Eat the left quote. + start_mark := parser.mark + skip(parser) + + // Consume the content of the quoted scalar. + var s, leading_break, trailing_breaks, whitespaces []byte + for { + // Check that there are no document indicators at the beginning of the line. + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + + if parser.mark.column == 0 && + ((parser.buffer[parser.buffer_pos+0] == '-' && + parser.buffer[parser.buffer_pos+1] == '-' && + parser.buffer[parser.buffer_pos+2] == '-') || + (parser.buffer[parser.buffer_pos+0] == '.' && + parser.buffer[parser.buffer_pos+1] == '.' && + parser.buffer[parser.buffer_pos+2] == '.')) && + is_blankz(parser.buffer, parser.buffer_pos+3) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected document indicator") + return false + } + + // Check for EOF. + if is_z(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected end of stream") + return false + } + + // Consume non-blank characters. + leading_blanks := false + for !is_blankz(parser.buffer, parser.buffer_pos) { + if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { + // Is is an escaped single quote. + s = append(s, '\'') + skip(parser) + skip(parser) + + } else if single && parser.buffer[parser.buffer_pos] == '\'' { + // It is a right single quote. + break + } else if !single && parser.buffer[parser.buffer_pos] == '"' { + // It is a right double quote. + break + + } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { + // It is an escaped line break. + if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { + return false + } + skip(parser) + skip_line(parser) + leading_blanks = true + break + + } else if !single && parser.buffer[parser.buffer_pos] == '\\' { + // It is an escape sequence. + code_length := 0 + + // Check the escape character. + switch parser.buffer[parser.buffer_pos+1] { + case '0': + s = append(s, 0) + case 'a': + s = append(s, '\x07') + case 'b': + s = append(s, '\x08') + case 't', '\t': + s = append(s, '\x09') + case 'n': + s = append(s, '\x0A') + case 'v': + s = append(s, '\x0B') + case 'f': + s = append(s, '\x0C') + case 'r': + s = append(s, '\x0D') + case 'e': + s = append(s, '\x1B') + case ' ': + s = append(s, '\x20') + case '"': + s = append(s, '"') + case '\'': + s = append(s, '\'') + case '\\': + s = append(s, '\\') + case 'N': // NEL (#x85) + s = append(s, '\xC2') + s = append(s, '\x85') + case '_': // #xA0 + s = append(s, '\xC2') + s = append(s, '\xA0') + case 'L': // LS (#x2028) + s = append(s, '\xE2') + s = append(s, '\x80') + s = append(s, '\xA8') + case 'P': // PS (#x2029) + s = append(s, '\xE2') + s = append(s, '\x80') + s = append(s, '\xA9') + case 'x': + code_length = 2 + case 'u': + code_length = 4 + case 'U': + code_length = 8 + default: + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found unknown escape character") + return false + } + + skip(parser) + skip(parser) + + // Consume an arbitrary escape code. + if code_length > 0 { + var value int + + // Scan the character value. + if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { + return false + } + for k := 0; k < code_length; k++ { + if !is_hex(parser.buffer, parser.buffer_pos+k) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "did not find expected hexdecimal number") + return false + } + value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) + } + + // Check the value and write the character. + if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found invalid Unicode character escape code") + return false + } + if value <= 0x7F { + s = append(s, byte(value)) + } else if value <= 0x7FF { + s = append(s, byte(0xC0+(value>>6))) + s = append(s, byte(0x80+(value&0x3F))) + } else if value <= 0xFFFF { + s = append(s, byte(0xE0+(value>>12))) + s = append(s, byte(0x80+((value>>6)&0x3F))) + s = append(s, byte(0x80+(value&0x3F))) + } else { + s = append(s, byte(0xF0+(value>>18))) + s = append(s, byte(0x80+((value>>12)&0x3F))) + s = append(s, byte(0x80+((value>>6)&0x3F))) + s = append(s, byte(0x80+(value&0x3F))) + } + + // Advance the pointer. + for k := 0; k < code_length; k++ { + skip(parser) + } + } + } else { + // It is a non-escaped non-blank character. + s = read(parser, s) + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + } + + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check if we are at the end of the scalar. + if single { + if parser.buffer[parser.buffer_pos] == '\'' { + break + } + } else { + if parser.buffer[parser.buffer_pos] == '"' { + break + } + } + + // Consume blank characters. + for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { + if is_blank(parser.buffer, parser.buffer_pos) { + // Consume a space or a tab character. + if !leading_blanks { + whitespaces = read(parser, whitespaces) + } else { + skip(parser) + } + } else { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + // Check if it is a first line break. + if !leading_blanks { + whitespaces = whitespaces[:0] + leading_break = read_line(parser, leading_break) + leading_blanks = true + } else { + trailing_breaks = read_line(parser, trailing_breaks) + } + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Join the whitespaces or fold line breaks. + if leading_blanks { + // Do we need to fold line breaks? + if len(leading_break) > 0 && leading_break[0] == '\n' { + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } else { + s = append(s, trailing_breaks...) + } + } else { + s = append(s, leading_break...) + s = append(s, trailing_breaks...) + } + trailing_breaks = trailing_breaks[:0] + leading_break = leading_break[:0] + } else { + s = append(s, whitespaces...) + whitespaces = whitespaces[:0] + } + } + + // Eat the right quote. + skip(parser) + end_mark := parser.mark + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_SINGLE_QUOTED_SCALAR_STYLE, + } + if !single { + token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + return true +} + +// Scan a plain scalar. +func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { + + var s, leading_break, trailing_breaks, whitespaces []byte + var leading_blanks bool + var indent = parser.indent + 1 + + start_mark := parser.mark + end_mark := parser.mark + + // Consume the content of the plain scalar. + for { + // Check for a document indicator. + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + if parser.mark.column == 0 && + ((parser.buffer[parser.buffer_pos+0] == '-' && + parser.buffer[parser.buffer_pos+1] == '-' && + parser.buffer[parser.buffer_pos+2] == '-') || + (parser.buffer[parser.buffer_pos+0] == '.' && + parser.buffer[parser.buffer_pos+1] == '.' && + parser.buffer[parser.buffer_pos+2] == '.')) && + is_blankz(parser.buffer, parser.buffer_pos+3) { + break + } + + // Check for a comment. + if parser.buffer[parser.buffer_pos] == '#' { + break + } + + // Consume non-blank characters. + for !is_blankz(parser.buffer, parser.buffer_pos) { + + // Check for indicators that may end a plain scalar. + if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || + (parser.flow_level > 0 && + (parser.buffer[parser.buffer_pos] == ',' || + parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || + parser.buffer[parser.buffer_pos] == '}')) { + break + } + + // Check if we need to join whitespaces and breaks. + if leading_blanks || len(whitespaces) > 0 { + if leading_blanks { + // Do we need to fold line breaks? + if leading_break[0] == '\n' { + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } else { + s = append(s, trailing_breaks...) + } + } else { + s = append(s, leading_break...) + s = append(s, trailing_breaks...) + } + trailing_breaks = trailing_breaks[:0] + leading_break = leading_break[:0] + leading_blanks = false + } else { + s = append(s, whitespaces...) + whitespaces = whitespaces[:0] + } + } + + // Copy the character. + s = read(parser, s) + + end_mark = parser.mark + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + } + + // Is it the end? + if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { + break + } + + // Consume blank characters. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { + if is_blank(parser.buffer, parser.buffer_pos) { + + // Check for tab characters that abuse indentation. + if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found a tab character that violates indentation") + return false + } + + // Consume a space or a tab character. + if !leading_blanks { + whitespaces = read(parser, whitespaces) + } else { + skip(parser) + } + } else { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + // Check if it is a first line break. + if !leading_blanks { + whitespaces = whitespaces[:0] + leading_break = read_line(parser, leading_break) + leading_blanks = true + } else { + trailing_breaks = read_line(parser, trailing_breaks) + } + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check indentation level. + if parser.flow_level == 0 && parser.mark.column < indent { + break + } + } + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_PLAIN_SCALAR_STYLE, + } + + // Note that we change the 'simple_key_allowed' flag. + if leading_blanks { + parser.simple_key_allowed = true + } + return true +} + +func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool { + if parser.newlines > 0 { + return true + } + + var start_mark yaml_mark_t + var text []byte + + for peek := 0; peek < 512; peek++ { + if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) { + break + } + if is_blank(parser.buffer, parser.buffer_pos+peek) { + continue + } + if parser.buffer[parser.buffer_pos+peek] == '#' { + seen := parser.mark.index+peek + for { + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_breakz(parser.buffer, parser.buffer_pos) { + if parser.mark.index >= seen { + break + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } else if parser.mark.index >= seen { + if len(text) == 0 { + start_mark = parser.mark + } + text = read(parser, text) + } else { + skip(parser) + } + } + } + break + } + if len(text) > 0 { + parser.comments = append(parser.comments, yaml_comment_t{ + token_mark: token_mark, + start_mark: start_mark, + line: text, + }) + } + return true +} + +func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool { + token := parser.tokens[len(parser.tokens)-1] + + if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 { + token = parser.tokens[len(parser.tokens)-2] + } + + var token_mark = token.start_mark + var start_mark yaml_mark_t + var next_indent = parser.indent + if next_indent < 0 { + next_indent = 0 + } + + var recent_empty = false + var first_empty = parser.newlines <= 1 + + var line = parser.mark.line + var column = parser.mark.column + + var text []byte + + // The foot line is the place where a comment must start to + // still be considered as a foot of the prior content. + // If there's some content in the currently parsed line, then + // the foot is the line below it. + var foot_line = -1 + if scan_mark.line > 0 { + foot_line = parser.mark.line-parser.newlines+1 + if parser.newlines == 0 && parser.mark.column > 1 { + foot_line++ + } + } + + var peek = 0 + for ; peek < 512; peek++ { + if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) { + break + } + column++ + if is_blank(parser.buffer, parser.buffer_pos+peek) { + continue + } + c := parser.buffer[parser.buffer_pos+peek] + var close_flow = parser.flow_level > 0 && (c == ']' || c == '}') + if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) { + // Got line break or terminator. + if close_flow || !recent_empty { + if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) { + // This is the first empty line and there were no empty lines before, + // so this initial part of the comment is a foot of the prior token + // instead of being a head for the following one. Split it up. + // Alternatively, this might also be the last comment inside a flow + // scope, so it must be a footer. + if len(text) > 0 { + if start_mark.column-1 < next_indent { + // If dedented it's unrelated to the prior token. + token_mark = start_mark + } + parser.comments = append(parser.comments, yaml_comment_t{ + scan_mark: scan_mark, + token_mark: token_mark, + start_mark: start_mark, + end_mark: yaml_mark_t{parser.mark.index + peek, line, column}, + foot: text, + }) + scan_mark = yaml_mark_t{parser.mark.index + peek, line, column} + token_mark = scan_mark + text = nil + } + } else { + if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 { + text = append(text, '\n') + } + } + } + if !is_break(parser.buffer, parser.buffer_pos+peek) { + break + } + first_empty = false + recent_empty = true + column = 0 + line++ + continue + } + + if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) { + // The comment at the different indentation is a foot of the + // preceding data rather than a head of the upcoming one. + parser.comments = append(parser.comments, yaml_comment_t{ + scan_mark: scan_mark, + token_mark: token_mark, + start_mark: start_mark, + end_mark: yaml_mark_t{parser.mark.index + peek, line, column}, + foot: text, + }) + scan_mark = yaml_mark_t{parser.mark.index + peek, line, column} + token_mark = scan_mark + text = nil + } + + if parser.buffer[parser.buffer_pos+peek] != '#' { + break + } + + if len(text) == 0 { + start_mark = yaml_mark_t{parser.mark.index + peek, line, column} + } else { + text = append(text, '\n') + } + + recent_empty = false + + // Consume until after the consumed comment line. + seen := parser.mark.index+peek + for { + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_breakz(parser.buffer, parser.buffer_pos) { + if parser.mark.index >= seen { + break + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } else if parser.mark.index >= seen { + text = read(parser, text) + } else { + skip(parser) + } + } + + peek = 0 + column = 0 + line = parser.mark.line + next_indent = parser.indent + if next_indent < 0 { + next_indent = 0 + } + } + + if len(text) > 0 { + parser.comments = append(parser.comments, yaml_comment_t{ + scan_mark: scan_mark, + token_mark: start_mark, + start_mark: start_mark, + end_mark: yaml_mark_t{parser.mark.index + peek - 1, line, column}, + head: text, + }) + } + return true +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/sorter.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/sorter.go new file mode 100644 index 00000000000..9210ece7e97 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/sorter.go @@ -0,0 +1,134 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// 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. + +package yaml + +import ( + "reflect" + "unicode" +) + +type keyList []reflect.Value + +func (l keyList) Len() int { return len(l) } +func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l keyList) Less(i, j int) bool { + a := l[i] + b := l[j] + ak := a.Kind() + bk := b.Kind() + for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { + a = a.Elem() + ak = a.Kind() + } + for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { + b = b.Elem() + bk = b.Kind() + } + af, aok := keyFloat(a) + bf, bok := keyFloat(b) + if aok && bok { + if af != bf { + return af < bf + } + if ak != bk { + return ak < bk + } + return numLess(a, b) + } + if ak != reflect.String || bk != reflect.String { + return ak < bk + } + ar, br := []rune(a.String()), []rune(b.String()) + digits := false + for i := 0; i < len(ar) && i < len(br); i++ { + if ar[i] == br[i] { + digits = unicode.IsDigit(ar[i]) + continue + } + al := unicode.IsLetter(ar[i]) + bl := unicode.IsLetter(br[i]) + if al && bl { + return ar[i] < br[i] + } + if al || bl { + if digits { + return al + } else { + return bl + } + } + var ai, bi int + var an, bn int64 + if ar[i] == '0' || br[i] == '0' { + for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- { + if ar[j] != '0' { + an = 1 + bn = 1 + break + } + } + } + for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { + an = an*10 + int64(ar[ai]-'0') + } + for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { + bn = bn*10 + int64(br[bi]-'0') + } + if an != bn { + return an < bn + } + if ai != bi { + return ai < bi + } + return ar[i] < br[i] + } + return len(ar) < len(br) +} + +// keyFloat returns a float value for v if it is a number/bool +// and whether it is a number/bool or not. +func keyFloat(v reflect.Value) (f float64, ok bool) { + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float64(v.Int()), true + case reflect.Float32, reflect.Float64: + return v.Float(), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return float64(v.Uint()), true + case reflect.Bool: + if v.Bool() { + return 1, true + } + return 0, true + } + return 0, false +} + +// numLess returns whether a < b. +// a and b must necessarily have the same kind. +func numLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return a.Int() < b.Int() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Bool: + return !a.Bool() && b.Bool() + } + panic("not a number") +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/writerc.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/writerc.go new file mode 100644 index 00000000000..b8a116bf9a2 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/writerc.go @@ -0,0 +1,48 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +// Set the writer error and return false. +func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { + emitter.error = yaml_WRITER_ERROR + emitter.problem = problem + return false +} + +// Flush the output buffer. +func yaml_emitter_flush(emitter *yaml_emitter_t) bool { + if emitter.write_handler == nil { + panic("write handler not set") + } + + // Check if the buffer is empty. + if emitter.buffer_pos == 0 { + return true + } + + if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { + return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) + } + emitter.buffer_pos = 0 + return true +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yaml.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yaml.go new file mode 100644 index 00000000000..bb6418dba32 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yaml.go @@ -0,0 +1,708 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// 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. + +// Package yaml implements YAML support for the Go language. +// +// Source code and other details for the project are available at GitHub: +// +// https://github.com/go-yaml/yaml +// +package yaml + +import ( + "errors" + "fmt" + "io" + "reflect" + "strings" + "sync" + "unicode/utf8" +) + +// The Unmarshaler interface may be implemented by types to customize their +// behavior when being unmarshaled from a YAML document. +type Unmarshaler interface { + UnmarshalYAML(value *Node) error +} + +type obsoleteUnmarshaler interface { + UnmarshalYAML(unmarshal func(interface{}) error) error +} + +// The Marshaler interface may be implemented by types to customize their +// behavior when being marshaled into a YAML document. The returned value +// is marshaled in place of the original value implementing Marshaler. +// +// If an error is returned by MarshalYAML, the marshaling procedure stops +// and returns with the provided error. +type Marshaler interface { + MarshalYAML() (interface{}, error) +} + +// Unmarshal decodes the first document found within the in byte slice +// and assigns decoded values into the out value. +// +// Maps and pointers (to a struct, string, int, etc) are accepted as out +// values. If an internal pointer within a struct is not initialized, +// the yaml package will initialize it if necessary for unmarshalling +// the provided data. The out parameter must not be nil. +// +// The type of the decoded values should be compatible with the respective +// values in out. If one or more values cannot be decoded due to a type +// mismatches, decoding continues partially until the end of the YAML +// content, and a *yaml.TypeError is returned with details for all +// missed values. +// +// Struct fields are only unmarshalled if they are exported (have an +// upper case first letter), and are unmarshalled using the field name +// lowercased as the default key. Custom keys may be defined via the +// "yaml" name in the field tag: the content preceding the first comma +// is used as the key, and the following comma-separated options are +// used to tweak the marshalling process (see Marshal). +// Conflicting names result in a runtime error. +// +// For example: +// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// +// See the documentation of Marshal for the format of tags and a list of +// supported tag options. +// +func Unmarshal(in []byte, out interface{}) (err error) { + return unmarshal(in, out, false) +} + +// A Decoder reads and decodes YAML values from an input stream. +type Decoder struct { + parser *parser + knownFields bool +} + +// NewDecoder returns a new decoder that reads from r. +// +// The decoder introduces its own buffering and may read +// data from r beyond the YAML values requested. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{ + parser: newParserFromReader(r), + } +} + +// KnownFields ensures that the keys in decoded mappings to +// exist as fields in the struct being decoded into. +func (dec *Decoder) KnownFields(enable bool) { + dec.knownFields = enable +} + +// Decode reads the next YAML-encoded value from its input +// and stores it in the value pointed to by v. +// +// See the documentation for Unmarshal for details about the +// conversion of YAML into a Go value. +func (dec *Decoder) Decode(v interface{}) (err error) { + d := newDecoder() + d.knownFields = dec.knownFields + defer handleErr(&err) + node := dec.parser.parse() + if node == nil { + return io.EOF + } + out := reflect.ValueOf(v) + if out.Kind() == reflect.Ptr && !out.IsNil() { + out = out.Elem() + } + d.unmarshal(node, out) + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +// Decode decodes the node and stores its data into the value pointed to by v. +// +// See the documentation for Unmarshal for details about the +// conversion of YAML into a Go value. +func (n *Node) Decode(v interface{}) (err error) { + d := newDecoder() + defer handleErr(&err) + out := reflect.ValueOf(v) + if out.Kind() == reflect.Ptr && !out.IsNil() { + out = out.Elem() + } + d.unmarshal(n, out) + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +func unmarshal(in []byte, out interface{}, strict bool) (err error) { + defer handleErr(&err) + d := newDecoder() + p := newParser(in) + defer p.destroy() + node := p.parse() + if node != nil { + v := reflect.ValueOf(out) + if v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + d.unmarshal(node, v) + } + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +// Marshal serializes the value provided into a YAML document. The structure +// of the generated document will reflect the structure of the value itself. +// Maps and pointers (to struct, string, int, etc) are accepted as the in value. +// +// Struct fields are only marshalled if they are exported (have an upper case +// first letter), and are marshalled using the field name lowercased as the +// default key. Custom keys may be defined via the "yaml" name in the field +// tag: the content preceding the first comma is used as the key, and the +// following comma-separated options are used to tweak the marshalling process. +// Conflicting names result in a runtime error. +// +// The field tag format accepted is: +// +// `(...) yaml:"[][,[,]]" (...)` +// +// The following flags are currently supported: +// +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be excluded if IsZero returns true. +// +// flow Marshal using a flow style (useful for structs, +// sequences and maps). +// +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. +// +// In addition, if the key is "-", the field is ignored. +// +// For example: +// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" +// +func Marshal(in interface{}) (out []byte, err error) { + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshalDoc("", reflect.ValueOf(in)) + e.finish() + out = e.out + return +} + +// An Encoder writes YAML values to an output stream. +type Encoder struct { + encoder *encoder +} + +// NewEncoder returns a new encoder that writes to w. +// The Encoder should be closed after use to flush all data +// to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + encoder: newEncoderWithWriter(w), + } +} + +// Encode writes the YAML encoding of v to the stream. +// If multiple items are encoded to the stream, the +// second and subsequent document will be preceded +// with a "---" document separator, but the first will not. +// +// See the documentation for Marshal for details about the conversion of Go +// values to YAML. +func (e *Encoder) Encode(v interface{}) (err error) { + defer handleErr(&err) + e.encoder.marshalDoc("", reflect.ValueOf(v)) + return nil +} + +// Encode encodes value v and stores its representation in n. +// +// See the documentation for Marshal for details about the +// conversion of Go values into YAML. +func (n *Node) Encode(v interface{}) (err error) { + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshalDoc("", reflect.ValueOf(v)) + e.finish() + p := newParser(e.out) + p.textless = true + defer p.destroy() + doc := p.parse() + *n = *doc.Content[0] + return nil +} + +// SetIndent changes the used indentation used when encoding. +func (e *Encoder) SetIndent(spaces int) { + if spaces < 0 { + panic("yaml: cannot indent to a negative number of spaces") + } + e.encoder.indent = spaces +} + +// CompactSeqIndent makes it so that '- ' is considered part of the indentation. +func (e *Encoder) CompactSeqIndent() { + e.encoder.emitter.compact_sequence_indent = true +} + +// DefaultSeqIndent makes it so that '- ' is not considered part of the indentation. +func (e *Encoder) DefaultSeqIndent() { + e.encoder.emitter.compact_sequence_indent = false +} + +// Close closes the encoder by writing any remaining data. +// It does not write a stream terminating string "...". +func (e *Encoder) Close() (err error) { + defer handleErr(&err) + e.encoder.finish() + return nil +} + +func handleErr(err *error) { + if v := recover(); v != nil { + if e, ok := v.(yamlError); ok { + *err = e.err + } else { + panic(v) + } + } +} + +type yamlError struct { + err error +} + +func fail(err error) { + panic(yamlError{err}) +} + +func failf(format string, args ...interface{}) { + panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) +} + +// A TypeError is returned by Unmarshal when one or more fields in +// the YAML document cannot be properly decoded into the requested +// types. When this error is returned, the value is still +// unmarshaled partially. +type TypeError struct { + Errors []string +} + +func (e *TypeError) Error() string { + return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) +} + +type Kind uint32 + +const ( + DocumentNode Kind = 1 << iota + SequenceNode + MappingNode + ScalarNode + AliasNode +) + +type Style uint32 + +const ( + TaggedStyle Style = 1 << iota + DoubleQuotedStyle + SingleQuotedStyle + LiteralStyle + FoldedStyle + FlowStyle +) + +// Node represents an element in the YAML document hierarchy. While documents +// are typically encoded and decoded into higher level types, such as structs +// and maps, Node is an intermediate representation that allows detailed +// control over the content being decoded or encoded. +// +// It's worth noting that although Node offers access into details such as +// line numbers, colums, and comments, the content when re-encoded will not +// have its original textual representation preserved. An effort is made to +// render the data plesantly, and to preserve comments near the data they +// describe, though. +// +// Values that make use of the Node type interact with the yaml package in the +// same way any other type would do, by encoding and decoding yaml data +// directly or indirectly into them. +// +// For example: +// +// var person struct { +// Name string +// Address yaml.Node +// } +// err := yaml.Unmarshal(data, &person) +// +// Or by itself: +// +// var person Node +// err := yaml.Unmarshal(data, &person) +// +type Node struct { + // Kind defines whether the node is a document, a mapping, a sequence, + // a scalar value, or an alias to another node. The specific data type of + // scalar nodes may be obtained via the ShortTag and LongTag methods. + Kind Kind + + // Style allows customizing the apperance of the node in the tree. + Style Style + + // Tag holds the YAML tag defining the data type for the value. + // When decoding, this field will always be set to the resolved tag, + // even when it wasn't explicitly provided in the YAML content. + // When encoding, if this field is unset the value type will be + // implied from the node properties, and if it is set, it will only + // be serialized into the representation if TaggedStyle is used or + // the implicit tag diverges from the provided one. + Tag string + + // Value holds the unescaped and unquoted represenation of the value. + Value string + + // Anchor holds the anchor name for this node, which allows aliases to point to it. + Anchor string + + // Alias holds the node that this alias points to. Only valid when Kind is AliasNode. + Alias *Node + + // Content holds contained nodes for documents, mappings, and sequences. + Content []*Node + + // HeadComment holds any comments in the lines preceding the node and + // not separated by an empty line. + HeadComment string + + // LineComment holds any comments at the end of the line where the node is in. + LineComment string + + // FootComment holds any comments following the node and before empty lines. + FootComment string + + // Line and Column hold the node position in the decoded YAML text. + // These fields are not respected when encoding the node. + Line int + Column int +} + +// IsZero returns whether the node has all of its fields unset. +func (n *Node) IsZero() bool { + return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil && + n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0 +} + + +// LongTag returns the long form of the tag that indicates the data type for +// the node. If the Tag field isn't explicitly defined, one will be computed +// based on the node properties. +func (n *Node) LongTag() string { + return longTag(n.ShortTag()) +} + +// ShortTag returns the short form of the YAML tag that indicates data type for +// the node. If the Tag field isn't explicitly defined, one will be computed +// based on the node properties. +func (n *Node) ShortTag() string { + if n.indicatedString() { + return strTag + } + if n.Tag == "" || n.Tag == "!" { + switch n.Kind { + case MappingNode: + return mapTag + case SequenceNode: + return seqTag + case AliasNode: + if n.Alias != nil { + return n.Alias.ShortTag() + } + case ScalarNode: + tag, _ := resolve("", n.Value) + return tag + case 0: + // Special case to make the zero value convenient. + if n.IsZero() { + return nullTag + } + } + return "" + } + return shortTag(n.Tag) +} + +func (n *Node) indicatedString() bool { + return n.Kind == ScalarNode && + (shortTag(n.Tag) == strTag || + (n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0) +} + +// SetString is a convenience function that sets the node to a string value +// and defines its style in a pleasant way depending on its content. +func (n *Node) SetString(s string) { + n.Kind = ScalarNode + if utf8.ValidString(s) { + n.Value = s + n.Tag = strTag + } else { + n.Value = encodeBase64(s) + n.Tag = binaryTag + } + if strings.Contains(n.Value, "\n") { + n.Style = LiteralStyle + } +} + +// -------------------------------------------------------------------------- +// Maintain a mapping of keys to structure field indexes + +// The code in this section was copied from mgo/bson. + +// structInfo holds details for the serialization of fields of +// a given struct. +type structInfo struct { + FieldsMap map[string]fieldInfo + FieldsList []fieldInfo + + // InlineMap is the number of the field in the struct that + // contains an ,inline map, or -1 if there's none. + InlineMap int + + // InlineUnmarshalers holds indexes to inlined fields that + // contain unmarshaler values. + InlineUnmarshalers [][]int +} + +type fieldInfo struct { + Key string + Num int + OmitEmpty bool + Flow bool + // Id holds the unique field identifier, so we can cheaply + // check for field duplicates without maintaining an extra map. + Id int + + // Inline holds the field index if the field is part of an inlined struct. + Inline []int +} + +var structMap = make(map[reflect.Type]*structInfo) +var fieldMapMutex sync.RWMutex +var unmarshalerType reflect.Type + +func init() { + var v Unmarshaler + unmarshalerType = reflect.ValueOf(&v).Elem().Type() +} + +func getStructInfo(st reflect.Type) (*structInfo, error) { + fieldMapMutex.RLock() + sinfo, found := structMap[st] + fieldMapMutex.RUnlock() + if found { + return sinfo, nil + } + + n := st.NumField() + fieldsMap := make(map[string]fieldInfo) + fieldsList := make([]fieldInfo, 0, n) + inlineMap := -1 + inlineUnmarshalers := [][]int(nil) + for i := 0; i != n; i++ { + field := st.Field(i) + if field.PkgPath != "" && !field.Anonymous { + continue // Private field + } + + info := fieldInfo{Num: i} + + tag := field.Tag.Get("yaml") + if tag == "" && strings.Index(string(field.Tag), ":") < 0 { + tag = string(field.Tag) + } + if tag == "-" { + continue + } + + inline := false + fields := strings.Split(tag, ",") + if len(fields) > 1 { + for _, flag := range fields[1:] { + switch flag { + case "omitempty": + info.OmitEmpty = true + case "flow": + info.Flow = true + case "inline": + inline = true + default: + return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st)) + } + } + tag = fields[0] + } + + if inline { + switch field.Type.Kind() { + case reflect.Map: + if inlineMap >= 0 { + return nil, errors.New("multiple ,inline maps in struct " + st.String()) + } + if field.Type.Key() != reflect.TypeOf("") { + return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String()) + } + inlineMap = info.Num + case reflect.Struct, reflect.Ptr: + ftype := field.Type + for ftype.Kind() == reflect.Ptr { + ftype = ftype.Elem() + } + if ftype.Kind() != reflect.Struct { + return nil, errors.New("option ,inline may only be used on a struct or map field") + } + if reflect.PtrTo(ftype).Implements(unmarshalerType) { + inlineUnmarshalers = append(inlineUnmarshalers, []int{i}) + } else { + sinfo, err := getStructInfo(ftype) + if err != nil { + return nil, err + } + for _, index := range sinfo.InlineUnmarshalers { + inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...)) + } + for _, finfo := range sinfo.FieldsList { + if _, found := fieldsMap[finfo.Key]; found { + msg := "duplicated key '" + finfo.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + if finfo.Inline == nil { + finfo.Inline = []int{i, finfo.Num} + } else { + finfo.Inline = append([]int{i}, finfo.Inline...) + } + finfo.Id = len(fieldsList) + fieldsMap[finfo.Key] = finfo + fieldsList = append(fieldsList, finfo) + } + } + default: + return nil, errors.New("option ,inline may only be used on a struct or map field") + } + continue + } + + if tag != "" { + info.Key = tag + } else { + info.Key = strings.ToLower(field.Name) + } + + if _, found = fieldsMap[info.Key]; found { + msg := "duplicated key '" + info.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + + info.Id = len(fieldsList) + fieldsList = append(fieldsList, info) + fieldsMap[info.Key] = info + } + + sinfo = &structInfo{ + FieldsMap: fieldsMap, + FieldsList: fieldsList, + InlineMap: inlineMap, + InlineUnmarshalers: inlineUnmarshalers, + } + + fieldMapMutex.Lock() + structMap[st] = sinfo + fieldMapMutex.Unlock() + return sinfo, nil +} + +// IsZeroer is used to check whether an object is zero to +// determine whether it should be omitted when marshaling +// with the omitempty flag. One notable implementation +// is time.Time. +type IsZeroer interface { + IsZero() bool +} + +func isZero(v reflect.Value) bool { + kind := v.Kind() + if z, ok := v.Interface().(IsZeroer); ok { + if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { + return true + } + return z.IsZero() + } + switch kind { + case reflect.String: + return len(v.String()) == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + case reflect.Slice: + return v.Len() == 0 + case reflect.Map: + return v.Len() == 0 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Struct: + vt := v.Type() + for i := v.NumField() - 1; i >= 0; i-- { + if vt.Field(i).PkgPath != "" { + continue // Private field + } + if !isZero(v.Field(i)) { + return false + } + } + return true + } + return false +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yamlh.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yamlh.go new file mode 100644 index 00000000000..40c74de4978 --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yamlh.go @@ -0,0 +1,809 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +import ( + "fmt" + "io" +) + +// The version directive data. +type yaml_version_directive_t struct { + major int8 // The major version number. + minor int8 // The minor version number. +} + +// The tag directive data. +type yaml_tag_directive_t struct { + handle []byte // The tag handle. + prefix []byte // The tag prefix. +} + +type yaml_encoding_t int + +// The stream encoding. +const ( + // Let the parser choose the encoding. + yaml_ANY_ENCODING yaml_encoding_t = iota + + yaml_UTF8_ENCODING // The default UTF-8 encoding. + yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. + yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. +) + +type yaml_break_t int + +// Line break types. +const ( + // Let the parser choose the break type. + yaml_ANY_BREAK yaml_break_t = iota + + yaml_CR_BREAK // Use CR for line breaks (Mac style). + yaml_LN_BREAK // Use LN for line breaks (Unix style). + yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). +) + +type yaml_error_type_t int + +// Many bad things could happen with the parser and emitter. +const ( + // No error is produced. + yaml_NO_ERROR yaml_error_type_t = iota + + yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. + yaml_READER_ERROR // Cannot read or decode the input stream. + yaml_SCANNER_ERROR // Cannot scan the input stream. + yaml_PARSER_ERROR // Cannot parse the input stream. + yaml_COMPOSER_ERROR // Cannot compose a YAML document. + yaml_WRITER_ERROR // Cannot write to the output stream. + yaml_EMITTER_ERROR // Cannot emit a YAML stream. +) + +// The pointer position. +type yaml_mark_t struct { + index int // The position index. + line int // The position line. + column int // The position column. +} + +// Node Styles + +type yaml_style_t int8 + +type yaml_scalar_style_t yaml_style_t + +// Scalar styles. +const ( + // Let the emitter choose the style. + yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0 + + yaml_PLAIN_SCALAR_STYLE yaml_scalar_style_t = 1 << iota // The plain scalar style. + yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. + yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. + yaml_LITERAL_SCALAR_STYLE // The literal scalar style. + yaml_FOLDED_SCALAR_STYLE // The folded scalar style. +) + +type yaml_sequence_style_t yaml_style_t + +// Sequence styles. +const ( + // Let the emitter choose the style. + yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota + + yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. + yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. +) + +type yaml_mapping_style_t yaml_style_t + +// Mapping styles. +const ( + // Let the emitter choose the style. + yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota + + yaml_BLOCK_MAPPING_STYLE // The block mapping style. + yaml_FLOW_MAPPING_STYLE // The flow mapping style. +) + +// Tokens + +type yaml_token_type_t int + +// Token types. +const ( + // An empty token. + yaml_NO_TOKEN yaml_token_type_t = iota + + yaml_STREAM_START_TOKEN // A STREAM-START token. + yaml_STREAM_END_TOKEN // A STREAM-END token. + + yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. + yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. + yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. + yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. + + yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. + yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. + yaml_BLOCK_END_TOKEN // A BLOCK-END token. + + yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. + yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. + yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. + yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. + + yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. + yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. + yaml_KEY_TOKEN // A KEY token. + yaml_VALUE_TOKEN // A VALUE token. + + yaml_ALIAS_TOKEN // An ALIAS token. + yaml_ANCHOR_TOKEN // An ANCHOR token. + yaml_TAG_TOKEN // A TAG token. + yaml_SCALAR_TOKEN // A SCALAR token. +) + +func (tt yaml_token_type_t) String() string { + switch tt { + case yaml_NO_TOKEN: + return "yaml_NO_TOKEN" + case yaml_STREAM_START_TOKEN: + return "yaml_STREAM_START_TOKEN" + case yaml_STREAM_END_TOKEN: + return "yaml_STREAM_END_TOKEN" + case yaml_VERSION_DIRECTIVE_TOKEN: + return "yaml_VERSION_DIRECTIVE_TOKEN" + case yaml_TAG_DIRECTIVE_TOKEN: + return "yaml_TAG_DIRECTIVE_TOKEN" + case yaml_DOCUMENT_START_TOKEN: + return "yaml_DOCUMENT_START_TOKEN" + case yaml_DOCUMENT_END_TOKEN: + return "yaml_DOCUMENT_END_TOKEN" + case yaml_BLOCK_SEQUENCE_START_TOKEN: + return "yaml_BLOCK_SEQUENCE_START_TOKEN" + case yaml_BLOCK_MAPPING_START_TOKEN: + return "yaml_BLOCK_MAPPING_START_TOKEN" + case yaml_BLOCK_END_TOKEN: + return "yaml_BLOCK_END_TOKEN" + case yaml_FLOW_SEQUENCE_START_TOKEN: + return "yaml_FLOW_SEQUENCE_START_TOKEN" + case yaml_FLOW_SEQUENCE_END_TOKEN: + return "yaml_FLOW_SEQUENCE_END_TOKEN" + case yaml_FLOW_MAPPING_START_TOKEN: + return "yaml_FLOW_MAPPING_START_TOKEN" + case yaml_FLOW_MAPPING_END_TOKEN: + return "yaml_FLOW_MAPPING_END_TOKEN" + case yaml_BLOCK_ENTRY_TOKEN: + return "yaml_BLOCK_ENTRY_TOKEN" + case yaml_FLOW_ENTRY_TOKEN: + return "yaml_FLOW_ENTRY_TOKEN" + case yaml_KEY_TOKEN: + return "yaml_KEY_TOKEN" + case yaml_VALUE_TOKEN: + return "yaml_VALUE_TOKEN" + case yaml_ALIAS_TOKEN: + return "yaml_ALIAS_TOKEN" + case yaml_ANCHOR_TOKEN: + return "yaml_ANCHOR_TOKEN" + case yaml_TAG_TOKEN: + return "yaml_TAG_TOKEN" + case yaml_SCALAR_TOKEN: + return "yaml_SCALAR_TOKEN" + } + return "" +} + +// The token structure. +type yaml_token_t struct { + // The token type. + typ yaml_token_type_t + + // The start/end of the token. + start_mark, end_mark yaml_mark_t + + // The stream encoding (for yaml_STREAM_START_TOKEN). + encoding yaml_encoding_t + + // The alias/anchor/scalar value or tag/tag directive handle + // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). + value []byte + + // The tag suffix (for yaml_TAG_TOKEN). + suffix []byte + + // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). + prefix []byte + + // The scalar style (for yaml_SCALAR_TOKEN). + style yaml_scalar_style_t + + // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). + major, minor int8 +} + +// Events + +type yaml_event_type_t int8 + +// Event types. +const ( + // An empty event. + yaml_NO_EVENT yaml_event_type_t = iota + + yaml_STREAM_START_EVENT // A STREAM-START event. + yaml_STREAM_END_EVENT // A STREAM-END event. + yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. + yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. + yaml_ALIAS_EVENT // An ALIAS event. + yaml_SCALAR_EVENT // A SCALAR event. + yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. + yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. + yaml_MAPPING_START_EVENT // A MAPPING-START event. + yaml_MAPPING_END_EVENT // A MAPPING-END event. + yaml_TAIL_COMMENT_EVENT +) + +var eventStrings = []string{ + yaml_NO_EVENT: "none", + yaml_STREAM_START_EVENT: "stream start", + yaml_STREAM_END_EVENT: "stream end", + yaml_DOCUMENT_START_EVENT: "document start", + yaml_DOCUMENT_END_EVENT: "document end", + yaml_ALIAS_EVENT: "alias", + yaml_SCALAR_EVENT: "scalar", + yaml_SEQUENCE_START_EVENT: "sequence start", + yaml_SEQUENCE_END_EVENT: "sequence end", + yaml_MAPPING_START_EVENT: "mapping start", + yaml_MAPPING_END_EVENT: "mapping end", + yaml_TAIL_COMMENT_EVENT: "tail comment", +} + +func (e yaml_event_type_t) String() string { + if e < 0 || int(e) >= len(eventStrings) { + return fmt.Sprintf("unknown event %d", e) + } + return eventStrings[e] +} + +// The event structure. +type yaml_event_t struct { + + // The event type. + typ yaml_event_type_t + + // The start and end of the event. + start_mark, end_mark yaml_mark_t + + // The document encoding (for yaml_STREAM_START_EVENT). + encoding yaml_encoding_t + + // The version directive (for yaml_DOCUMENT_START_EVENT). + version_directive *yaml_version_directive_t + + // The list of tag directives (for yaml_DOCUMENT_START_EVENT). + tag_directives []yaml_tag_directive_t + + // The comments + head_comment []byte + line_comment []byte + foot_comment []byte + tail_comment []byte + + // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). + anchor []byte + + // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). + tag []byte + + // The scalar value (for yaml_SCALAR_EVENT). + value []byte + + // Is the document start/end indicator implicit, or the tag optional? + // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). + implicit bool + + // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). + quoted_implicit bool + + // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). + style yaml_style_t +} + +func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } +func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } +func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } + +// Nodes + +const ( + yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. + yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. + yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. + yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. + yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. + yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. + + yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. + yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. + + // Not in original libyaml. + yaml_BINARY_TAG = "tag:yaml.org,2002:binary" + yaml_MERGE_TAG = "tag:yaml.org,2002:merge" + + yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. + yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. + yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. +) + +type yaml_node_type_t int + +// Node types. +const ( + // An empty node. + yaml_NO_NODE yaml_node_type_t = iota + + yaml_SCALAR_NODE // A scalar node. + yaml_SEQUENCE_NODE // A sequence node. + yaml_MAPPING_NODE // A mapping node. +) + +// An element of a sequence node. +type yaml_node_item_t int + +// An element of a mapping node. +type yaml_node_pair_t struct { + key int // The key of the element. + value int // The value of the element. +} + +// The node structure. +type yaml_node_t struct { + typ yaml_node_type_t // The node type. + tag []byte // The node tag. + + // The node data. + + // The scalar parameters (for yaml_SCALAR_NODE). + scalar struct { + value []byte // The scalar value. + length int // The length of the scalar value. + style yaml_scalar_style_t // The scalar style. + } + + // The sequence parameters (for YAML_SEQUENCE_NODE). + sequence struct { + items_data []yaml_node_item_t // The stack of sequence items. + style yaml_sequence_style_t // The sequence style. + } + + // The mapping parameters (for yaml_MAPPING_NODE). + mapping struct { + pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). + pairs_start *yaml_node_pair_t // The beginning of the stack. + pairs_end *yaml_node_pair_t // The end of the stack. + pairs_top *yaml_node_pair_t // The top of the stack. + style yaml_mapping_style_t // The mapping style. + } + + start_mark yaml_mark_t // The beginning of the node. + end_mark yaml_mark_t // The end of the node. + +} + +// The document structure. +type yaml_document_t struct { + + // The document nodes. + nodes []yaml_node_t + + // The version directive. + version_directive *yaml_version_directive_t + + // The list of tag directives. + tag_directives_data []yaml_tag_directive_t + tag_directives_start int // The beginning of the tag directives list. + tag_directives_end int // The end of the tag directives list. + + start_implicit int // Is the document start indicator implicit? + end_implicit int // Is the document end indicator implicit? + + // The start/end of the document. + start_mark, end_mark yaml_mark_t +} + +// The prototype of a read handler. +// +// The read handler is called when the parser needs to read more bytes from the +// source. The handler should write not more than size bytes to the buffer. +// The number of written bytes should be set to the size_read variable. +// +// [in,out] data A pointer to an application data specified by +// yaml_parser_set_input(). +// [out] buffer The buffer to write the data from the source. +// [in] size The size of the buffer. +// [out] size_read The actual number of bytes read from the source. +// +// On success, the handler should return 1. If the handler failed, +// the returned value should be 0. On EOF, the handler should set the +// size_read to 0 and return 1. +type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) + +// This structure holds information about a potential simple key. +type yaml_simple_key_t struct { + possible bool // Is a simple key possible? + required bool // Is a simple key required? + token_number int // The number of the token. + mark yaml_mark_t // The position mark. +} + +// The states of the parser. +type yaml_parser_state_t int + +const ( + yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota + + yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. + yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. + yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. + yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. + yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. + yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. + yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. + yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. + yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. + yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. + yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. + yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. + yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. + yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. + yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. + yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. + yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. + yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. + yaml_PARSE_END_STATE // Expect nothing. +) + +func (ps yaml_parser_state_t) String() string { + switch ps { + case yaml_PARSE_STREAM_START_STATE: + return "yaml_PARSE_STREAM_START_STATE" + case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" + case yaml_PARSE_DOCUMENT_START_STATE: + return "yaml_PARSE_DOCUMENT_START_STATE" + case yaml_PARSE_DOCUMENT_CONTENT_STATE: + return "yaml_PARSE_DOCUMENT_CONTENT_STATE" + case yaml_PARSE_DOCUMENT_END_STATE: + return "yaml_PARSE_DOCUMENT_END_STATE" + case yaml_PARSE_BLOCK_NODE_STATE: + return "yaml_PARSE_BLOCK_NODE_STATE" + case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" + case yaml_PARSE_FLOW_NODE_STATE: + return "yaml_PARSE_FLOW_NODE_STATE" + case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" + case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" + case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: + return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" + case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: + return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" + case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" + case yaml_PARSE_FLOW_MAPPING_KEY_STATE: + return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" + case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: + return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" + case yaml_PARSE_END_STATE: + return "yaml_PARSE_END_STATE" + } + return "" +} + +// This structure holds aliases data. +type yaml_alias_data_t struct { + anchor []byte // The anchor. + index int // The node id. + mark yaml_mark_t // The anchor mark. +} + +// The parser structure. +// +// All members are internal. Manage the structure using the +// yaml_parser_ family of functions. +type yaml_parser_t struct { + + // Error handling + + error yaml_error_type_t // Error type. + + problem string // Error description. + + // The byte about which the problem occurred. + problem_offset int + problem_value int + problem_mark yaml_mark_t + + // The error context. + context string + context_mark yaml_mark_t + + // Reader stuff + + read_handler yaml_read_handler_t // Read handler. + + input_reader io.Reader // File input data. + input []byte // String input data. + input_pos int + + eof bool // EOF flag + + buffer []byte // The working buffer. + buffer_pos int // The current position of the buffer. + + unread int // The number of unread characters in the buffer. + + newlines int // The number of line breaks since last non-break/non-blank character + + raw_buffer []byte // The raw buffer. + raw_buffer_pos int // The current position of the buffer. + + encoding yaml_encoding_t // The input encoding. + + offset int // The offset of the current position (in bytes). + mark yaml_mark_t // The mark of the current position. + + // Comments + + head_comment []byte // The current head comments + line_comment []byte // The current line comments + foot_comment []byte // The current foot comments + tail_comment []byte // Foot comment that happens at the end of a block. + stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc) + + comments []yaml_comment_t // The folded comments for all parsed tokens + comments_head int + + // Scanner stuff + + stream_start_produced bool // Have we started to scan the input stream? + stream_end_produced bool // Have we reached the end of the input stream? + + flow_level int // The number of unclosed '[' and '{' indicators. + + tokens []yaml_token_t // The tokens queue. + tokens_head int // The head of the tokens queue. + tokens_parsed int // The number of tokens fetched from the queue. + token_available bool // Does the tokens queue contain a token ready for dequeueing. + + indent int // The current indentation level. + indents []int // The indentation levels stack. + + simple_key_allowed bool // May a simple key occur at the current position? + simple_keys []yaml_simple_key_t // The stack of simple keys. + simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number + + // Parser stuff + + state yaml_parser_state_t // The current parser state. + states []yaml_parser_state_t // The parser states stack. + marks []yaml_mark_t // The stack of marks. + tag_directives []yaml_tag_directive_t // The list of TAG directives. + + // Dumper stuff + + aliases []yaml_alias_data_t // The alias data. + + document *yaml_document_t // The currently parsed document. +} + +type yaml_comment_t struct { + + scan_mark yaml_mark_t // Position where scanning for comments started + token_mark yaml_mark_t // Position after which tokens will be associated with this comment + start_mark yaml_mark_t // Position of '#' comment mark + end_mark yaml_mark_t // Position where comment terminated + + head []byte + line []byte + foot []byte +} + +// Emitter Definitions + +// The prototype of a write handler. +// +// The write handler is called when the emitter needs to flush the accumulated +// characters to the output. The handler should write @a size bytes of the +// @a buffer to the output. +// +// @param[in,out] data A pointer to an application data specified by +// yaml_emitter_set_output(). +// @param[in] buffer The buffer with bytes to be written. +// @param[in] size The size of the buffer. +// +// @returns On success, the handler should return @c 1. If the handler failed, +// the returned value should be @c 0. +// +type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error + +type yaml_emitter_state_t int + +// The emitter states. +const ( + // Expect STREAM-START. + yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota + + yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. + yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. + yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. + yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. + yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. + yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE // Expect the next item of a flow sequence, with the comma already written out + yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. + yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE // Expect the next key of a flow mapping, with the comma already written out + yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. + yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. + yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. + yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. + yaml_EMIT_END_STATE // Expect nothing. +) + +// The emitter structure. +// +// All members are internal. Manage the structure using the @c yaml_emitter_ +// family of functions. +type yaml_emitter_t struct { + + // Error handling + + error yaml_error_type_t // Error type. + problem string // Error description. + + // Writer stuff + + write_handler yaml_write_handler_t // Write handler. + + output_buffer *[]byte // String output data. + output_writer io.Writer // File output data. + + buffer []byte // The working buffer. + buffer_pos int // The current position of the buffer. + + raw_buffer []byte // The raw buffer. + raw_buffer_pos int // The current position of the buffer. + + encoding yaml_encoding_t // The stream encoding. + + // Emitter stuff + + canonical bool // If the output is in the canonical style? + best_indent int // The number of indentation spaces. + best_width int // The preferred width of the output lines. + unicode bool // Allow unescaped non-ASCII characters? + line_break yaml_break_t // The preferred line break. + + state yaml_emitter_state_t // The current emitter state. + states []yaml_emitter_state_t // The stack of states. + + events []yaml_event_t // The event queue. + events_head int // The head of the event queue. + + indents []int // The stack of indentation levels. + + tag_directives []yaml_tag_directive_t // The list of tag directives. + + indent int // The current indentation level. + + compact_sequence_indent bool // Is '- ' is considered part of the indentation for sequence elements? + + flow_level int // The current flow level. + + root_context bool // Is it the document root context? + sequence_context bool // Is it a sequence context? + mapping_context bool // Is it a mapping context? + simple_key_context bool // Is it a simple mapping key context? + + line int // The current line. + column int // The current column. + whitespace bool // If the last character was a whitespace? + indention bool // If the last character was an indentation character (' ', '-', '?', ':')? + open_ended bool // If an explicit document end is required? + + space_above bool // Is there's an empty line above? + foot_indent int // The indent used to write the foot comment above, or -1 if none. + + // Anchor analysis. + anchor_data struct { + anchor []byte // The anchor value. + alias bool // Is it an alias? + } + + // Tag analysis. + tag_data struct { + handle []byte // The tag handle. + suffix []byte // The tag suffix. + } + + // Scalar analysis. + scalar_data struct { + value []byte // The scalar value. + multiline bool // Does the scalar contain line breaks? + flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? + block_plain_allowed bool // Can the scalar be expressed in the block plain style? + single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? + block_allowed bool // Can the scalar be expressed in the literal or folded styles? + style yaml_scalar_style_t // The output style. + } + + // Comments + head_comment []byte + line_comment []byte + foot_comment []byte + tail_comment []byte + + key_line_comment []byte + + // Dumper stuff + + opened bool // If the stream was already opened? + closed bool // If the stream was already closed? + + // The information associated with the document nodes. + anchors *struct { + references int // The number of references. + anchor int // The anchor id. + serialized bool // If the node has been emitted? + } + + last_anchor_id int // The last assigned anchor id. + + document *yaml_document_t // The currently emitted document. +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yamlprivateh.go b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yamlprivateh.go new file mode 100644 index 00000000000..e88f9c54aec --- /dev/null +++ b/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml/yamlprivateh.go @@ -0,0 +1,198 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// 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. + +package yaml + +const ( + // The size of the input raw buffer. + input_raw_buffer_size = 512 + + // The size of the input buffer. + // It should be possible to decode the whole raw buffer. + input_buffer_size = input_raw_buffer_size * 3 + + // The size of the output buffer. + output_buffer_size = 128 + + // The size of the output raw buffer. + // It should be possible to encode the whole output buffer. + output_raw_buffer_size = (output_buffer_size*2 + 2) + + // The size of other stacks and queues. + initial_stack_size = 16 + initial_queue_size = 16 + initial_string_size = 16 +) + +// Check if the character at the specified position is an alphabetical +// character, a digit, '_', or '-'. +func is_alpha(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' +} + +// Check if the character at the specified position is a digit. +func is_digit(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' +} + +// Get the value of a digit. +func as_digit(b []byte, i int) int { + return int(b[i]) - '0' +} + +// Check if the character at the specified position is a hex-digit. +func is_hex(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' +} + +// Get the value of a hex-digit. +func as_hex(b []byte, i int) int { + bi := b[i] + if bi >= 'A' && bi <= 'F' { + return int(bi) - 'A' + 10 + } + if bi >= 'a' && bi <= 'f' { + return int(bi) - 'a' + 10 + } + return int(bi) - '0' +} + +// Check if the character is ASCII. +func is_ascii(b []byte, i int) bool { + return b[i] <= 0x7F +} + +// Check if the character at the start of the buffer can be printed unescaped. +func is_printable(b []byte, i int) bool { + return ((b[i] == 0x0A) || // . == #x0A + (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E + (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF + (b[i] > 0xC2 && b[i] < 0xED) || + (b[i] == 0xED && b[i+1] < 0xA0) || + (b[i] == 0xEE) || + (b[i] == 0xEF && // #xE000 <= . <= #xFFFD + !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF + !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) +} + +// Check if the character at the specified position is NUL. +func is_z(b []byte, i int) bool { + return b[i] == 0x00 +} + +// Check if the beginning of the buffer is a BOM. +func is_bom(b []byte, i int) bool { + return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF +} + +// Check if the character at the specified position is space. +func is_space(b []byte, i int) bool { + return b[i] == ' ' +} + +// Check if the character at the specified position is tab. +func is_tab(b []byte, i int) bool { + return b[i] == '\t' +} + +// Check if the character at the specified position is blank (space or tab). +func is_blank(b []byte, i int) bool { + //return is_space(b, i) || is_tab(b, i) + return b[i] == ' ' || b[i] == '\t' +} + +// Check if the character at the specified position is a line break. +func is_break(b []byte, i int) bool { + return (b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) +} + +func is_crlf(b []byte, i int) bool { + return b[i] == '\r' && b[i+1] == '\n' +} + +// Check if the character is a line break or NUL. +func is_breakz(b []byte, i int) bool { + //return is_break(b, i) || is_z(b, i) + return ( + // is_break: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + // is_z: + b[i] == 0) +} + +// Check if the character is a line break, space, or NUL. +func is_spacez(b []byte, i int) bool { + //return is_space(b, i) || is_breakz(b, i) + return ( + // is_space: + b[i] == ' ' || + // is_breakz: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + b[i] == 0) +} + +// Check if the character is a line break, space, tab, or NUL. +func is_blankz(b []byte, i int) bool { + //return is_blank(b, i) || is_breakz(b, i) + return ( + // is_blank: + b[i] == ' ' || b[i] == '\t' || + // is_breakz: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + b[i] == 0) +} + +// Determine the width of the character. +func width(b byte) int { + // Don't replace these by a switch without first + // confirming that it is being inlined. + if b&0x80 == 0x00 { + return 1 + } + if b&0xE0 == 0xC0 { + return 2 + } + if b&0xF0 == 0xE0 { + return 3 + } + if b&0xF8 == 0xF0 { + return 4 + } + return 0 + +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/kio/byteio_writer.go b/vendor/sigs.k8s.io/kustomize/kyaml/kio/byteio_writer.go index 84097f10865..a208f52bb73 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/kio/byteio_writer.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/kio/byteio_writer.go @@ -6,13 +6,16 @@ package kio import ( "encoding/json" "io" - + "path/filepath" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/kio/kioutil" "sigs.k8s.io/kustomize/kyaml/yaml" ) -// Writer writes ResourceNodes to bytes. +// ByteWriter writes ResourceNodes to bytes. Generally YAML encoding will be used but in the special +// case of writing a single, bare yaml.RNode that has a kioutil.PathAnnotation indicating that the +// target is a JSON file JSON encoding is used. See shouldJSONEncodeSingleBareNode below for more +// information. type ByteWriter struct { // Writer is where ResourceNodes are encoded. Writer io.Writer @@ -47,16 +50,18 @@ type ByteWriter struct { var _ Writer = ByteWriter{} -func (w ByteWriter) Write(nodes []*yaml.RNode) error { - yaml.DoSerializationHacksOnNodes(nodes) +func (w ByteWriter) Write(inputNodes []*yaml.RNode) error { + // Copy the nodes to prevent writer from mutating the original nodes. + nodes := copyRNodes(inputNodes) if w.Sort { if err := kioutil.SortNodes(nodes); err != nil { return errors.Wrap(err) } } - encoder := yaml.NewEncoder(w.Writer) - defer encoder.Close() + // Even though we use the this value further down we must check this before removing annotations + jsonEncodeSingleBareNode := w.shouldJSONEncodeSingleBareNode(nodes) + for i := range nodes { // clean resources by removing annotations set by the Reader if !w.KeepReaderAnnotations { @@ -81,10 +86,18 @@ func (w ByteWriter) Write(nodes []*yaml.RNode) error { } } + if jsonEncodeSingleBareNode { + encoder := json.NewEncoder(w.Writer) + encoder.SetIndent("", " ") + return errors.Wrap(encoder.Encode(nodes[0])) + } + + encoder := yaml.NewEncoder(w.Writer) + defer encoder.Close() // don't wrap the elements if w.WrappingKind == "" { for i := range nodes { - if err := w.encode(encoder, nodes[i].Document()); err != nil { + if err := encoder.Encode(nodes[i].Document()); err != nil { return err } } @@ -118,23 +131,37 @@ func (w ByteWriter) Write(nodes []*yaml.RNode) error { for i := range nodes { items.Content = append(items.Content, nodes[i].YNode()) } - err := w.encode(encoder, doc) - yaml.UndoSerializationHacksOnNodes(nodes) - return err + return encoder.Encode(doc) } -// encode encodes the input document node to appropriate node format -func (w ByteWriter) encode(encoder *yaml.Encoder, doc *yaml.Node) error { - rNode := &yaml.RNode{} - rNode.SetYNode(doc) - str, err := rNode.String() - if err != nil { - return errors.Wrap(err) +func copyRNodes(in []*yaml.RNode) []*yaml.RNode { + out := make([]*yaml.RNode, len(in)) + for i := range in { + out[i] = in[i].Copy() } - if json.Valid([]byte(str)) { - je := json.NewEncoder(w.Writer) - je.SetIndent("", " ") - return errors.Wrap(je.Encode(rNode)) + return out +} + +// shouldJSONEncodeSingleBareNode determines if nodes contain a single node that should not be +// wrapped and has a JSON file extension, which in turn means that the node should be JSON encoded. +// Note 1: this must be checked before any annotations to avoid losing information about the target +// filename extension. +// Note 2: JSON encoding should only be used for single, unwrapped nodes because multiple unwrapped +// nodes cannot be represented in JSON (no multi doc support). Furthermore, the typical use +// cases for wrapping nodes would likely not include later writing the whole wrapper to a +// .json file, i.e. there is no point risking any edge case information loss e.g. comments +// disappearing, that could come from JSON encoding the whole wrapper just to ensure that +// one (or all nodes) can be read as JSON. +func (w ByteWriter) shouldJSONEncodeSingleBareNode(nodes []*yaml.RNode) bool { + if w.WrappingKind == "" && len(nodes) == 1 { + if path, _, _ := kioutil.GetFileAnnotations(nodes[0]); path != "" { + filename := filepath.Base(path) + for _, glob := range JSONMatch { + if match, _ := filepath.Match(glob, filename); match { + return true + } + } + } } - return encoder.Encode(doc) + return false } diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go b/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go index 27dd0f766d2..26ff8630173 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go @@ -19,17 +19,55 @@ const ( mergeSourceDest = "dest" ) +// ResourceMatcher interface is used to match two resources based on IsSameResource implementation +// This is the way to group same logical resources in upstream, local and origin for merge +// The default way to group them is using GVKNN similar to how kubernetes server identifies resources +// Users of this library might have their own interpretation of grouping similar resources +// for e.g. if consumer adds a name-prefix to local resource, it should not be treated as new resource +// for updates etc. +// Hence, the callers of this library may pass different implementation for IsSameResource +type ResourceMatcher interface { + IsSameResource(node1, node2 *yaml.RNode) bool +} + +// ResourceMergeStrategy is the return type from the Handle function in the +// ResourceHandler interface. It determines which version of a resource should +// be included in the output (if any). +type ResourceMergeStrategy int + +const ( + // Merge means the output to dest should be the 3-way merge of original, + // updated and dest. + Merge ResourceMergeStrategy = iota + // KeepDest means the version of the resource in dest should be the output. + KeepDest + // KeepUpdated means the version of the resource in updated should be the + // output. + KeepUpdated + // KeepOriginal means the version of the resource in original should be the + // output. + KeepOriginal + // Skip means the resource should not be included in the output. + Skip +) + +// ResourceHandler interface is used to determine what should be done for a +// resource once the versions in original, updated and dest has been +// identified based on the ResourceMatcher. This allows users to customize +// what should be the result in dest if a resource has been deleted from +// upstream. +type ResourceHandler interface { + Handle(original, updated, dest *yaml.RNode) (ResourceMergeStrategy, error) +} + // Merge3 performs a 3-way merge on the original, updated, and destination packages. type Merge3 struct { OriginalPath string UpdatedPath string DestPath string MatchFilesGlob []string - - // MergeOnPath will use the relative filepath as part of the merge key. - // This may be necessary if the directory contains multiple copies of - // the same resource, or resources patches. - MergeOnPath bool + Matcher ResourceMatcher + Handler ResourceHandler } func (m Merge3) Merge() error { @@ -67,7 +105,16 @@ func (m Merge3) Merge() error { // Filter combines Resources with the same GVK + N + NS into tuples, and then merges them func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { // index the nodes by their identity - tl := tuples{mergeOnPath: m.MergeOnPath} + matcher := m.Matcher + if matcher == nil { + matcher = &DefaultGVKNNMatcher{MergeOnPath: true} + } + handler := m.Handler + if handler == nil { + handler = &DefaultResourceHandler{} + } + + tl := tuples{matcher: matcher} for i := range nodes { if err := tl.add(nodes[i]); err != nil { return nil, err @@ -78,21 +125,12 @@ func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { var output []*yaml.RNode for i := range tl.list { t := tl.list[i] - switch { - case t.original == nil && t.updated == nil && t.dest != nil: - // added locally -- keep dest - output = append(output, t.dest) - case t.original == nil && t.updated != nil && t.dest == nil: - // added in the update -- add update - output = append(output, t.updated) - case t.original != nil && t.updated == nil: - // deleted in the update - // don't include the resource in the output - case t.original != nil && t.dest == nil: - // deleted locally - // don't include the resource in the output - default: - // dest and updated are non-nil -- merge them + strategy, err := handler.Handle(t.original, t.updated, t.dest) + if err != nil { + return nil, err + } + switch strategy { + case Merge: node, err := t.merge() if err != nil { return nil, err @@ -100,6 +138,14 @@ func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { if node != nil { output = append(output, node) } + case KeepDest: + output = append(output, t.dest) + case KeepUpdated: + output = append(output, t.updated) + case KeepOriginal: + output = append(output, t.original) + case Skip: + // do nothing } } return output, nil @@ -109,13 +155,35 @@ func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { type tuples struct { list []*tuple - // mergeOnPath if set to true will use the resource filepath - // as part of the merge key - mergeOnPath bool + // matcher matches the resources for merge + matcher ResourceMatcher } -// isSameResource returns true if meta1 and meta2 are for the same logic resource -func (ts *tuples) isSameResource(meta1, meta2 yaml.ResourceMeta) bool { +// DefaultGVKNNMatcher holds the default matching of resources implementation based on +// Group, Version, Kind, Name and Namespace of the resource +type DefaultGVKNNMatcher struct { + // MergeOnPath will use the relative filepath as part of the merge key. + // This may be necessary if the directory contains multiple copies of + // the same resource, or resources patches. + MergeOnPath bool +} + +// IsSameResource returns true if metadata of node1 and metadata of node2 belongs to same logical resource +func (dm *DefaultGVKNNMatcher) IsSameResource(node1, node2 *yaml.RNode) bool { + if node1 == nil || node2 == nil { + return false + } + + meta1, err := node1.GetMeta() + if err != nil { + return false + } + + meta2, err := node2.GetMeta() + if err != nil { + return false + } + if meta1.Name != meta2.Name { return false } @@ -128,7 +196,7 @@ func (ts *tuples) isSameResource(meta1, meta2 yaml.ResourceMeta) bool { if meta1.Kind != meta2.Kind { return false } - if ts.mergeOnPath { + if dm.MergeOnPath { // directories may contain multiple copies of a resource with the same // name, namespace, apiVersion and kind -- e.g. kustomize patches, or // multiple environments @@ -143,17 +211,13 @@ func (ts *tuples) isSameResource(meta1, meta2 yaml.ResourceMeta) bool { // add adds a node to the list, combining it with an existing matching Resource if found func (ts *tuples) add(node *yaml.RNode) error { - nodeMeta, err := node.GetMeta() - if err != nil { - return err - } for i := range ts.list { t := ts.list[i] - if ts.isSameResource(t.meta, nodeMeta) { + if ts.matcher.IsSameResource(addedNode(t), node) { return t.add(node) } } - t := &tuple{meta: nodeMeta} + t := &tuple{} if err := t.add(node); err != nil { return err } @@ -161,9 +225,19 @@ func (ts *tuples) add(node *yaml.RNode) error { return nil } +// addedNode returns one on the existing added nodes in the tuple +func addedNode(t *tuple) *yaml.RNode { + if t.updated != nil { + return t.updated + } + if t.original != nil { + return t.original + } + return t.dest +} + // tuple wraps an original, updated, and dest tuple for a given Resource type tuple struct { - meta yaml.ResourceMeta original *yaml.RNode updated *yaml.RNode dest *yaml.RNode @@ -178,17 +252,17 @@ func (t *tuple) add(node *yaml.RNode) error { switch meta.Annotations[mergeSourceAnnotation] { case mergeSourceDest: if t.dest != nil { - return fmt.Errorf("dest source already specified") + return duplicateError("local", meta.Annotations[kioutil.PathAnnotation]) } t.dest = node case mergeSourceOriginal: if t.original != nil { - return fmt.Errorf("original source already specified") + return duplicateError("original upstream", meta.Annotations[kioutil.PathAnnotation]) } t.original = node case mergeSourceUpdated: if t.updated != nil { - return fmt.Errorf("updated source already specified") + return duplicateError("updated upstream", meta.Annotations[kioutil.PathAnnotation]) } t.updated = node default: @@ -201,3 +275,37 @@ func (t *tuple) add(node *yaml.RNode) error { func (t *tuple) merge() (*yaml.RNode, error) { return merge3.Merge(t.dest, t.original, t.updated) } + +// duplicateError returns duplicate resources error +func duplicateError(source, filePath string) error { + return fmt.Errorf(`found duplicate %q resources in file %q, please refer to "update" documentation for the fix`, source, filePath) +} + +// DefaultResourceHandler is the default implementation of the ResourceHandler +// interface. It uses the following rules: +// * Keep dest if resource only exists in dest. +// * Keep updated if resource added in updated. +// * Delete dest if updated has been deleted. +// * Don't add the resource back if removed from dest. +// * Otherwise merge. +type DefaultResourceHandler struct{} + +func (*DefaultResourceHandler) Handle(original, updated, dest *yaml.RNode) (ResourceMergeStrategy, error) { + switch { + case original == nil && updated == nil && dest != nil: + // added locally -- keep dest + return KeepDest, nil + case updated != nil && dest == nil: + // added in the update -- add update + return KeepUpdated, nil + case original != nil && updated == nil: + // deleted in the update + return Skip, nil + case original != nil && dest == nil: + // deleted locally + return Skip, nil + default: + // dest and updated are non-nil -- merge them + return Merge, nil + } +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go b/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go index 9a6ce924bdf..0ba3d838215 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go @@ -4,12 +4,14 @@ package kio import ( + "errors" "os" "path/filepath" "strings" - "github.com/monochromegane/go-gitignore" + gitignore "github.com/monochromegane/go-gitignore" "sigs.k8s.io/kustomize/kyaml/ext" + "sigs.k8s.io/kustomize/kyaml/filesys" ) // ignoreFilesMatcher handles `.krmignore` files, which allows for ignoring @@ -32,6 +34,7 @@ import ( // is set to true type ignoreFilesMatcher struct { matchers []matcher + fs filesys.FileSystemOrOnDisk } // readIgnoreFile checks whether there is a .krmignore file in the path, and @@ -39,9 +42,9 @@ type ignoreFilesMatcher struct { // we just add a matcher that match nothing. func (i *ignoreFilesMatcher) readIgnoreFile(path string) error { i.verifyPath(path) - m, err := gitignore.NewGitIgnore(filepath.Join(path, ext.IgnoreFileName())) + f, err := i.fs.Open(filepath.Join(path, ext.IgnoreFileName())) if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, os.ErrNotExist) { i.matchers = append(i.matchers, matcher{ matcher: gitignore.DummyIgnoreMatcher(false), basePath: path, @@ -50,8 +53,10 @@ func (i *ignoreFilesMatcher) readIgnoreFile(path string) error { } return err } + defer f.Close() + i.matchers = append(i.matchers, matcher{ - matcher: m, + matcher: gitignore.NewGitIgnoreFromReader(path, f), basePath: path, }) return nil diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/kio/pkgio_reader.go b/vendor/sigs.k8s.io/kustomize/kyaml/kio/pkgio_reader.go index 2fb1758e2d4..1dfec3c7737 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/kio/pkgio_reader.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/kio/pkgio_reader.go @@ -71,6 +71,10 @@ type LocalPackageReadWriter struct { NoDeleteFiles bool `yaml:"noDeleteFiles,omitempty"` files sets.String + + // FileSkipFunc is a function which returns true if reader should ignore + // the file + FileSkipFunc LocalPackageSkipFileFunc } func (r *LocalPackageReadWriter) Read() ([]*yaml.RNode, error) { @@ -81,6 +85,7 @@ func (r *LocalPackageReadWriter) Read() ([]*yaml.RNode, error) { ErrorIfNonResources: r.ErrorIfNonResources, SetAnnotations: r.SetAnnotations, PackageFileName: r.PackageFileName, + FileSkipFunc: r.FileSkipFunc, }.Read() if err != nil { return nil, errors.Wrap(err) @@ -133,6 +138,11 @@ func (r *LocalPackageReadWriter) getFiles(nodes []*yaml.RNode) (sets.String, err return val, nil } +// LocalPackageSkipFileFunc is a function which returns true if the file +// in the package should be ignored by reader. +// relPath is an OS specific relative path +type LocalPackageSkipFileFunc func(relPath string) bool + // LocalPackageReader reads ResourceNodes from a local package. type LocalPackageReader struct { Kind string `yaml:"kind,omitempty"` @@ -163,6 +173,10 @@ type LocalPackageReader struct { // SetAnnotations are annotations to set on the Resources as they are read. SetAnnotations map[string]string `yaml:"setAnnotations,omitempty"` + + // FileSkipFunc is a function which returns true if reader should ignore + // the file + FileSkipFunc LocalPackageSkipFileFunc } var _ Reader = LocalPackageReader{} @@ -215,24 +229,24 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) { if info.IsDir() { return r.shouldSkipDir(path, ignoreFilesMatcher) } - if match, err := r.shouldSkipFile(path, ignoreFilesMatcher); err != nil { - return err - } else if !match { - // skip this file - return nil - } // get the relative path to file within the package so we can write the files back out // to another location. - path, err = filepath.Rel(pathRelativeTo, path) + relPath, err := filepath.Rel(pathRelativeTo, path) if err != nil { return errors.WrapPrefixf(err, pathRelativeTo) } + if match, err := r.shouldSkipFile(path, relPath, ignoreFilesMatcher); err != nil { + return err + } else if match { + // skip this file + return nil + } - r.initReaderAnnotations(path, info) - nodes, err := r.readFile(filepath.Join(pathRelativeTo, path), info) + r.initReaderAnnotations(relPath, info) + nodes, err := r.readFile(path, info) if err != nil { - return errors.WrapPrefixf(err, filepath.Join(pathRelativeTo, path)) + return errors.WrapPrefixf(err, path) } operand = append(operand, nodes...) return nil @@ -258,21 +272,25 @@ func (r *LocalPackageReader) readFile(path string, _ os.FileInfo) ([]*yaml.RNode } // shouldSkipFile returns true if the file should be skipped -func (r *LocalPackageReader) shouldSkipFile(path string, matcher *ignoreFilesMatcher) (bool, error) { +func (r *LocalPackageReader) shouldSkipFile(path, relPath string, matcher *ignoreFilesMatcher) (bool, error) { // check if the file is covered by a .krmignore file. if matcher.matchFile(path) { - return false, nil + return true, nil + } + + if r.FileSkipFunc != nil && r.FileSkipFunc(relPath) { + return true, nil } // check if the files are in scope for _, g := range r.MatchFilesGlob { if match, err := filepath.Match(g, filepath.Base(path)); err != nil { - return false, errors.Wrap(err) + return true, errors.Wrap(err) } else if match { - return true, nil + return false, nil } } - return false, nil + return true, nil } // initReaderAnnotations adds the LocalPackageReader Annotations to r.SetAnnotations diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile b/vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile index f5cd8dc6770..945f1aa5261 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile +++ b/vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile @@ -1,7 +1,10 @@ # Copyright 2020 The Kubernetes Authors. # SPDX-License-Identifier: Apache-2.0 -MYGOBIN := $(shell go env GOPATH)/bin +MYGOBIN = $(shell go env GOBIN) +ifeq ($(MYGOBIN),) +MYGOBIN = $(shell go env GOPATH)/bin +endif API_VERSION := "v1.19.1" .PHONY: all diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go b/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go index cfe18e469cd..5e34195f618 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go @@ -11,7 +11,7 @@ import ( "reflect" "strings" - "github.com/go-openapi/spec" + "k8s.io/kube-openapi/pkg/validation/spec" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi" "sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi" @@ -44,10 +44,9 @@ type openapiData struct { // Kubernetes schema as part of the global schema noUseBuiltInSchema bool - // currentOpenAPIVersion stores the version if the kubernetes openapi data - // that is currently stored as the schema, so that we only reparse the - // schema when necessary (to speed up performance) - currentOpenAPIVersion string + // schemaInit stores whether or not we've parsed the schema already, + // so that we only reparse the when necessary (to speed up performance) + schemaInit bool } // ResourceSchema wraps the OpenAPI Schema. @@ -274,6 +273,15 @@ func IsNamespaceScoped(typeMeta yaml.TypeMeta) (bool, bool) { return isNamespaceScoped, found } +// IsCertainlyClusterScoped returns true for Node, Namespace, etc. and +// false for Pod, Deployment, etc. and kinds that aren't recognized in the +// openapi data. See: +// https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces +func IsCertainlyClusterScoped(typeMeta yaml.TypeMeta) bool { + nsScoped, found := IsNamespaceScoped(typeMeta) + return found && !nsScoped +} + // SuppressBuiltInSchemaUse can be called to prevent using the built-in Kubernetes // schema as part of the global schema. // Must be called before the schema is used. @@ -477,27 +485,28 @@ func GetSchemaVersion() string { // initSchema parses the json schema func initSchema() { + if globalSchema.schemaInit { + return + } + globalSchema.schemaInit = true + if customSchema != nil { - ResetOpenAPI() err := parse(customSchema) if err != nil { panic("invalid schema file") } - if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil { + if err = parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil { // this should never happen panic(err) } return } - currentVersion := kubernetesOpenAPIVersion - if currentVersion == "" { - currentVersion = kubernetesOpenAPIDefaultVersion - } - if globalSchema.currentOpenAPIVersion != currentVersion { - parseBuiltinSchema(currentVersion) + if kubernetesOpenAPIVersion == "" { + parseBuiltinSchema(kubernetesOpenAPIDefaultVersion) + } else { + parseBuiltinSchema(kubernetesOpenAPIVersion) } - globalSchema.currentOpenAPIVersion = currentVersion } // parseBuiltinSchema calls parse to parse the json schemas diff --git a/vendor/sigs.k8s.io/kustomize/api/resid/gvk.go b/vendor/sigs.k8s.io/kustomize/kyaml/resid/gvk.go similarity index 80% rename from vendor/sigs.k8s.io/kustomize/api/resid/gvk.go rename to vendor/sigs.k8s.io/kustomize/kyaml/resid/gvk.go index 70f7107386a..21dad78d333 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resid/gvk.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/resid/gvk.go @@ -16,13 +16,26 @@ type Gvk struct { Group string `json:"group,omitempty" yaml:"group,omitempty"` Version string `json:"version,omitempty" yaml:"version,omitempty"` Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + // isClusterScoped is true if the object is known, per the openapi + // data in use, to be cluster scoped, and false otherwise. + isClusterScoped bool +} + +func NewGvk(g, v, k string) Gvk { + result := Gvk{Group: g, Version: v, Kind: k} + result.isClusterScoped = + openapi.IsCertainlyClusterScoped(result.AsTypeMeta()) + return result +} + +func GvkFromNode(r *yaml.RNode) Gvk { + g, v := ParseGroupVersion(r.GetApiVersion()) + return NewGvk(g, v, r.GetKind()) } // FromKind makes a Gvk with only the kind specified. func FromKind(k string) Gvk { - return Gvk{ - Kind: k, - } + return NewGvk("", "", k) } // ParseGroupVersion parses a KRM metadata apiVersion field. @@ -36,6 +49,14 @@ func ParseGroupVersion(apiVersion string) (group, version string) { // GvkFromString makes a Gvk from the output of Gvk.String(). func GvkFromString(s string) Gvk { values := strings.Split(s, fieldSep) + if len(values) != 3 { + // ...then the string didn't come from Gvk.String(). + return Gvk{ + Group: noGroup, + Version: noVersion, + Kind: noKind, + } + } g := values[0] if g == noGroup { g = "" @@ -48,11 +69,7 @@ func GvkFromString(s string) Gvk { if k == noKind { k = "" } - return Gvk{ - Group: g, - Version: v, - Kind: k, - } + return NewGvk(g, v, k) } // Values that are brief but meaningful in logs. @@ -82,10 +99,13 @@ func (x Gvk) String() string { // ApiVersion returns the combination of Group and Version func (x Gvk) ApiVersion() string { - if x.Group == "" { - return x.Version + var sb strings.Builder + if x.Group != "" { + sb.WriteString(x.Group) + sb.WriteString("/") } - return x.Group + "/" + x.Version + sb.WriteString(x.Version) + return sb.String() } // StringWoEmptyField returns a string representation of the GVK. Non-exist @@ -199,23 +219,16 @@ func (x Gvk) IsSelected(selector *Gvk) bool { return true } -// toKyamlTypeMeta returns a yaml.TypeMeta from x's information. -func (x Gvk) toKyamlTypeMeta() yaml.TypeMeta { - var apiVersion strings.Builder - if x.Group != "" { - apiVersion.WriteString(x.Group) - apiVersion.WriteString("/") - } - apiVersion.WriteString(x.Version) +// AsTypeMeta returns a yaml.TypeMeta from x's information. +func (x Gvk) AsTypeMeta() yaml.TypeMeta { return yaml.TypeMeta{ - APIVersion: apiVersion.String(), + APIVersion: x.ApiVersion(), Kind: x.Kind, } } -// IsNamespaceableKind returns true if x is a namespaceable Gvk -// Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace -func (x Gvk) IsNamespaceableKind() bool { - isNamespaceScoped, found := openapi.IsNamespaceScoped(x.toKyamlTypeMeta()) - return !found || isNamespaceScoped +// IsClusterScoped returns true if the Gvk is certainly cluster scoped +// with respect to the available openapi data. +func (x Gvk) IsClusterScoped() bool { + return x.isClusterScoped } diff --git a/vendor/sigs.k8s.io/kustomize/api/resid/resid.go b/vendor/sigs.k8s.io/kustomize/kyaml/resid/resid.go similarity index 83% rename from vendor/sigs.k8s.io/kustomize/api/resid/resid.go rename to vendor/sigs.k8s.io/kustomize/kyaml/resid/resid.go index 28310e8f373..1700531a2f7 100644 --- a/vendor/sigs.k8s.io/kustomize/api/resid/resid.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/resid/resid.go @@ -12,13 +12,10 @@ type ResId struct { // Gvk of the resource. Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` - // Name of the resource before transformation. + // Name of the resource. Name string `json:"name,omitempty" yaml:"name,omitempty"` - // Namespace the resource belongs to. - // An untransformed resource has no namespace. - // A fully transformed resource has the namespace - // from the top most overlay. + // Namespace the resource belongs to, if it can belong to a namespace. Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` } @@ -30,12 +27,12 @@ func NewResIdWithNamespace(k Gvk, n, ns string) ResId { // NewResId creates new ResId. func NewResId(k Gvk, n string) ResId { - return ResId{Gvk: k, Name: n} + return NewResIdWithNamespace(k, n, "") } // NewResIdKindOnly creates a new ResId. func NewResIdKindOnly(k string, n string) ResId { - return ResId{Gvk: FromKind(k), Name: n} + return NewResId(FromKind(k), n) } const ( @@ -90,6 +87,13 @@ func (id ResId) GvknEquals(o ResId) bool { return id.Name == o.Name && id.Gvk.Equals(o.Gvk) } +// IsSelectedBy returns true if self is selected by the argument. +func (id ResId) IsSelectedBy(selector ResId) bool { + return (selector.Name == "" || selector.Name == id.Name) && + (selector.Namespace == "" || selector.IsNsEquals(id)) && + id.Gvk.IsSelected(&selector.Gvk) +} + // Equals returns true if the other id matches // namespace/Group/Version/Kind/name. func (id ResId) Equals(o ResId) bool { @@ -106,7 +110,7 @@ func (id ResId) IsNsEquals(o ResId) bool { // ResId and the Namespace is either not set or set // to DefaultNamespace. func (id ResId) IsInDefaultNs() bool { - return id.IsNamespaceableKind() && id.isPutativelyDefaultNs() + return !id.IsClusterScoped() && id.isPutativelyDefaultNs() } func (id ResId) isPutativelyDefaultNs() bool { @@ -117,7 +121,7 @@ func (id ResId) isPutativelyDefaultNs() bool { // namespace for use in reporting and equality tests. func (id ResId) EffectiveNamespace() string { // The order of these checks matters. - if !id.IsNamespaceableKind() { + if id.IsClusterScoped() { return TotallyNotANamespace } if id.isPutativelyDefaultNs() { diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go b/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go index 5f5481797bc..bfe1ac3f2fa 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go @@ -496,7 +496,6 @@ func (r *RunFns) ffp(spec runtimeutil.FunctionSpec, api *yaml.RNode, currentUser } p = filepath.ToSlash(filepath.Join(r.Path, filepath.Dir(p), spec.Starlark.Path)) } - fmt.Println(p) sf := &starlark.Filter{Name: spec.Starlark.Name, Path: p, URL: spec.Starlark.URL} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go index ee0d5cbb172..05cafae0d8d 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go @@ -4,11 +4,21 @@ package yaml import ( + "bytes" "io" - "gopkg.in/yaml.v3" + "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml" ) +const CompactSequenceStyle = "compact" +const WideSequenceStyle = "wide" + +const DefaultIndent = 2 +const DefaultSequenceStyle = CompactSequenceStyle + +var sequenceIndentationStyle = DefaultSequenceStyle +var indent = DefaultIndent + // Expose the yaml.v3 functions so this package can be used as a replacement type Decoder = yaml.Decoder @@ -21,12 +31,22 @@ type Style = yaml.Style type TypeError = yaml.TypeError type Unmarshaler = yaml.Unmarshaler -var Marshal = yaml.Marshal +var Marshal = func(in interface{}) ([]byte, error) { + var buf bytes.Buffer + err := NewEncoder(&buf).Encode(in) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} var Unmarshal = yaml.Unmarshal var NewDecoder = yaml.NewDecoder var NewEncoder = func(w io.Writer) *yaml.Encoder { e := yaml.NewEncoder(w) - e.SetIndent(2) + e.SetIndent(indent) + if sequenceIndentationStyle == CompactSequenceStyle { + e.CompactSeqIndent() + } return e } diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go index e2cd811ce1d..a471140000e 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go @@ -7,9 +7,9 @@ import ( "reflect" "strings" - "github.com/go-openapi/spec" y1_1 "gopkg.in/yaml.v2" - y1_2 "gopkg.in/yaml.v3" + "k8s.io/kube-openapi/pkg/validation/spec" + y1_2 "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml" ) // typeToTag maps OpenAPI schema types to yaml 1.2 tags @@ -45,6 +45,14 @@ func FormatNonStringStyle(node *Node, schema spec.Schema) { default: return } + + // if the node tag is null, make sure we don't add any non-null tags + // https://github.com/GoogleContainerTools/kpt/issues/2321 + if node.Tag == NodeTagNull { + // must NOT quote null values + node.Style = 0 + return + } if tag, found := typeToTag[t]; found { // make sure the right tag is set node.Tag = tag diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go index ab01b98159a..5289997dd11 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go @@ -10,8 +10,8 @@ import ( "strings" "github.com/davecgh/go-spew/spew" - "gopkg.in/yaml.v3" "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml" ) // Append creates an ElementAppender diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go index 73c5ae6a65a..2999eddd5de 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go @@ -27,6 +27,7 @@ import ( "strings" "log" + "sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection" "sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets" "sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation" diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go index d9e5dfaf610..2ae8c1665e5 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go @@ -4,8 +4,8 @@ package yaml import ( - "gopkg.in/yaml.v3" "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml" ) // AnnotationClearer removes an annotation at metadata.annotations. diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go index 22e5d326efa..f7e3f230c18 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go @@ -8,11 +8,12 @@ import ( "fmt" "io/ioutil" "log" + "regexp" "strconv" "strings" - "gopkg.in/yaml.v3" "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels" ) @@ -336,16 +337,98 @@ func (rn *RNode) SetYNode(node *yaml.Node) { *rn.value = *node } -// GetNamespace gets the metadata namespace field. -func (rn *RNode) GetNamespace() (string, error) { - meta, err := rn.GetMeta() - if err != nil { - return "", err +// GetKind returns the kind, if it exists, else empty string. +func (rn *RNode) GetKind() string { + if node := rn.getMapFieldValue(KindField); node != nil { + return node.Value + } + return "" +} + +// SetKind sets the kind. +func (rn *RNode) SetKind(k string) { + rn.SetMapField(NewScalarRNode(k), KindField) +} + +// GetApiVersion returns the apiversion, if it exists, else empty string. +func (rn *RNode) GetApiVersion() string { + if node := rn.getMapFieldValue(APIVersionField); node != nil { + return node.Value + } + return "" +} + +// SetApiVersion sets the apiVersion. +func (rn *RNode) SetApiVersion(av string) { + rn.SetMapField(NewScalarRNode(av), APIVersionField) +} + +// getMapFieldValue returns the value (*yaml.Node) of a mapping field. +// The value might be nil. Also, the function returns nil, not an error, +// if this node is not a mapping node, or if this node does not have the +// given field, so this function cannot be used to make distinctions +// between these cases. +func (rn *RNode) getMapFieldValue(field string) *yaml.Node { + for i := 0; i < len(rn.Content()); i = IncrementFieldIndex(i) { + if rn.Content()[i].Value == field { + return rn.Content()[i+1] + } + } + return nil +} + +// GetName returns the name, or empty string if +// field not found. The setter is more restrictive. +func (rn *RNode) GetName() string { + return rn.getMetaStringField(NameField) +} + +// getMetaStringField returns the value of a string field in metadata. +func (rn *RNode) getMetaStringField(fName string) string { + md := rn.getMetaData() + if md == nil { + return "" + } + f := md.Field(fName) + if f.IsNilOrEmpty() { + return "" + } + return GetValue(f.Value) +} + +// getMetaData returns the RNode holding the value of the metadata field. +// Return nil if field not found (no error). +func (rn *RNode) getMetaData() *RNode { + if IsMissingOrNull(rn) { + return nil } - return meta.Namespace, nil + var n *RNode + if rn.YNode().Kind == DocumentNode { + // get the content if this is the document node + n = NewRNode(rn.Content()[0]) + } else { + n = rn + } + mf := n.Field(MetadataField) + if mf.IsNilOrEmpty() { + return nil + } + return mf.Value +} + +// SetName sets the metadata name field. +func (rn *RNode) SetName(name string) error { + return rn.SetMapField(NewScalarRNode(name), MetadataField, NameField) +} + +// GetNamespace gets the metadata namespace field, or empty string if +// field not found. The setter is more restrictive. +func (rn *RNode) GetNamespace() string { + return rn.getMetaStringField(NamespaceField) } -// SetNamespace tries to set the metadata namespace field. +// SetNamespace tries to set the metadata namespace field. If the argument +// is empty, the field is dropped. func (rn *RNode) SetNamespace(ns string) error { meta, err := rn.Pipe(Lookup(MetadataField)) if err != nil { @@ -362,12 +445,14 @@ func (rn *RNode) SetNamespace(ns string) error { } // GetAnnotations gets the metadata annotations field. -func (rn *RNode) GetAnnotations() (map[string]string, error) { - meta, err := rn.GetMeta() - if err != nil { - return nil, err +// If the field is missing, returns an empty map. +// Use another method to check for missing metadata. +func (rn *RNode) GetAnnotations() map[string]string { + meta := rn.getMetaData() + if meta == nil { + return make(map[string]string) } - return meta.Annotations, nil + return rn.getMapFromMeta(meta, AnnotationsField) } // SetAnnotations tries to set the metadata annotations field. @@ -376,12 +461,26 @@ func (rn *RNode) SetAnnotations(m map[string]string) error { } // GetLabels gets the metadata labels field. -func (rn *RNode) GetLabels() (map[string]string, error) { - meta, err := rn.GetMeta() - if err != nil { - return nil, err +// If the field is missing, returns an empty map. +// Use another method to check for missing metadata. +func (rn *RNode) GetLabels() map[string]string { + meta := rn.getMetaData() + if meta == nil { + return make(map[string]string) } - return meta.Labels, nil + return rn.getMapFromMeta(meta, LabelsField) +} + +// getMapFromMeta returns map, sometimes empty, from metadata. +func (rn *RNode) getMapFromMeta(meta *RNode, fName string) map[string]string { + result := make(map[string]string) + if f := meta.Field(fName); !f.IsNilOrEmpty() { + _ = f.Value.VisitFields(func(node *MapNode) error { + result[GetValue(node.Key)] = GetValue(node.Value) + return nil + }) + } + return result } // SetLabels sets the metadata labels field. @@ -391,7 +490,7 @@ func (rn *RNode) SetLabels(m map[string]string) error { // This established proper quoting on string values, and sorts by key. func (rn *RNode) setMapInMetadata(m map[string]string, field string) error { - meta, err := rn.Pipe(Lookup(MetadataField)) + meta, err := rn.Pipe(LookupCreate(MappingNode, MetadataField)) if err != nil { return err } @@ -447,6 +546,32 @@ func (rn *RNode) GetBinaryDataMap() map[string]string { return result } +// GetValidatedDataMap retrieves the data map and returns an error if the data +// map contains entries which are not included in the expectedKeys set. +func (rn *RNode) GetValidatedDataMap(expectedKeys []string) (map[string]string, error) { + dataMap := rn.GetDataMap() + err := rn.validateDataMap(dataMap, expectedKeys) + return dataMap, err +} + +func (rn *RNode) validateDataMap(dataMap map[string]string, expectedKeys []string) error { + if dataMap == nil { + return fmt.Errorf("The datamap is unassigned") + } + for key := range dataMap { + found := false + for _, expected := range expectedKeys { + if expected == key { + found = true + } + } + if !found { + return fmt.Errorf("an unexpected key (%v) was found", key) + } + } + return nil +} + func (rn *RNode) SetDataMap(m map[string]string) { if rn == nil { log.Fatal("cannot set data map on nil Rnode") @@ -752,37 +877,28 @@ func (rn *RNode) GetValidatedMetadata() (ResourceMeta, error) { return m, nil } -// MatchesAnnotationSelector implements ifc.Kunstructured. +// MatchesAnnotationSelector returns true on a selector match to annotations. func (rn *RNode) MatchesAnnotationSelector(selector string) (bool, error) { s, err := labels.Parse(selector) if err != nil { return false, err } - slice, err := rn.GetAnnotations() - if err != nil { - return false, err - } - return s.Matches(labels.Set(slice)), nil + return s.Matches(labels.Set(rn.GetAnnotations())), nil } -// MatchesLabelSelector implements ifc.Kunstructured. +// MatchesLabelSelector returns true on a selector match to labels. func (rn *RNode) MatchesLabelSelector(selector string) (bool, error) { s, err := labels.Parse(selector) if err != nil { return false, err } - slice, err := rn.GetLabels() - if err != nil { - return false, err - } - return s.Matches(labels.Set(slice)), nil + return s.Matches(labels.Set(rn.GetLabels())), nil } // HasNilEntryInList returns true if the RNode contains a list which has // a nil item, along with the path to the missing item. -// TODO(broken): This was copied from -// api/k8sdeps/kunstruct/factory.go//checkListItemNil -// and doesn't do what it claims to do (see TODO in unit test and pr 1513). +// TODO(broken): This doesn't do what it claims to do. +// (see TODO in unit test and pr 1513). func (rn *RNode) HasNilEntryInList() (bool, string) { return hasNilEntryInList(rn.value) } @@ -859,3 +975,123 @@ func checkKey(key string, elems []*Node) bool { } return count == len(elems) } + +// Deprecated: use pipes instead. +// GetSlice returns the contents of the slice field at the given path. +func (rn *RNode) GetSlice(path string) ([]interface{}, error) { + value, err := rn.GetFieldValue(path) + if err != nil { + return nil, err + } + if sliceValue, ok := value.([]interface{}); ok { + return sliceValue, nil + } + return nil, fmt.Errorf("node %s is not a slice", path) +} + +// Deprecated: use pipes instead. +// GetString returns the contents of the string field at the given path. +func (rn *RNode) GetString(path string) (string, error) { + value, err := rn.GetFieldValue(path) + if err != nil { + return "", err + } + if v, ok := value.(string); ok { + return v, nil + } + return "", fmt.Errorf("node %s is not a string: %v", path, value) +} + +// Deprecated: use slash paths instead. +// GetFieldValue finds period delimited fields. +// TODO: When doing kustomize var replacement, which is likely a +// a primary use of this function and the reason it returns interface{} +// rather than string, we do conversion from Nodes to Go types and back +// to nodes. We should figure out how to do replacement using raw nodes, +// assuming we keep the var feature in kustomize. +// The other end of this is: refvar.go:updateNodeValue. +func (rn *RNode) GetFieldValue(path string) (interface{}, error) { + fields := convertSliceIndex(strings.Split(path, ".")) + rn, err := rn.Pipe(Lookup(fields...)) + if err != nil { + return nil, err + } + if rn == nil { + return nil, NoFieldError{path} + } + yn := rn.YNode() + + // If this is an alias node, resolve it + if yn.Kind == yaml.AliasNode { + yn = yn.Alias + } + + // Return value as map for DocumentNode and MappingNode kinds + if yn.Kind == yaml.DocumentNode || yn.Kind == yaml.MappingNode { + var result map[string]interface{} + if err := yn.Decode(&result); err != nil { + return nil, err + } + return result, err + } + + // Return value as slice for SequenceNode kind + if yn.Kind == yaml.SequenceNode { + var result []interface{} + if err := yn.Decode(&result); err != nil { + return nil, err + } + return result, nil + } + if yn.Kind != yaml.ScalarNode { + return nil, fmt.Errorf("expected ScalarNode, got Kind=%d", yn.Kind) + } + + switch yn.Tag { + case NodeTagString: + return yn.Value, nil + case NodeTagInt: + return strconv.Atoi(yn.Value) + case NodeTagFloat: + return strconv.ParseFloat(yn.Value, 64) + case NodeTagBool: + return strconv.ParseBool(yn.Value) + default: + // Possibly this should be an error or log. + return yn.Value, nil + } +} + +// convertSliceIndex traverses the items in `fields` and find +// if there is a slice index in the item and change it to a +// valid Lookup field path. For example, 'ports[0]' will be +// converted to 'ports' and '0'. +func convertSliceIndex(fields []string) []string { + var res []string + for _, s := range fields { + if !strings.HasSuffix(s, "]") { + res = append(res, s) + continue + } + re := regexp.MustCompile(`^(.*)\[(\d+)\]$`) + groups := re.FindStringSubmatch(s) + if len(groups) == 0 { + // no match, add to result + res = append(res, s) + continue + } + if groups[1] != "" { + res = append(res, groups[1]) + } + res = append(res, groups[2]) + } + return res +} + +type NoFieldError struct { + Field string +} + +func (e NoFieldError) Error() string { + return fmt.Sprintf("no field named '%s'", e.Field) +} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go deleted file mode 100644 index 92510c5185d..00000000000 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package yaml - -import "gopkg.in/yaml.v3" - -func DoSerializationHacksOnNodes(nodes []*RNode) { - for _, node := range nodes { - DoSerializationHacks(node.YNode()) - } -} - -// DoSerializationHacks addresses a bug in yaml V3 upstream, it parses the yaml node, -// and rearranges the head comments of the children of sequence node. -// Refer to https://github.com/go-yaml/yaml/issues/587 for more details -func DoSerializationHacks(node *yaml.Node) { - switch node.Kind { - case DocumentNode: - for _, node := range node.Content { - DoSerializationHacks(node) - } - - case MappingNode: - for _, node := range node.Content { - DoSerializationHacks(node) - } - - case SequenceNode: - for _, node := range node.Content { - // for each child mapping node, transfer the head comment of it's - // first child scalar node to the head comment of itself - // This is necessary to address serialization issue - // https://github.com/go-yaml/yaml/issues/587 in go-yaml.v3 - // Remove this hack when the issue has been resolved - if len(node.Content) > 0 && node.Content[0].Kind == ScalarNode { - node.HeadComment = node.Content[0].HeadComment - node.Content[0].HeadComment = "" - } - } - } -} - -func UndoSerializationHacksOnNodes(nodes []*RNode) { - for _, node := range nodes { - UndoSerializationHacks(node.YNode()) - } -} - -// UndoSerializationHacks reverts the changes made by DoSerializationHacks -// Refer to https://github.com/go-yaml/yaml/issues/587 for more details -func UndoSerializationHacks(node *yaml.Node) { - switch node.Kind { - case DocumentNode: - for _, node := range node.Content { - DoSerializationHacks(node) - } - - case MappingNode: - for _, node := range node.Content { - DoSerializationHacks(node) - } - - case SequenceNode: - for _, node := range node.Content { - // revert the changes made in DoSerializationHacks - // This is necessary to address serialization issue - // https://github.com/go-yaml/yaml/issues/587 in go-yaml.v3 - // Remove this hack when the issue has been resolved - if len(node.Content) > 0 && node.Content[0].Kind == ScalarNode { - node.Content[0].HeadComment = node.HeadComment - node.HeadComment = "" - } - } - } -} diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go index 2c424e50806..c4e06a57849 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go @@ -7,8 +7,8 @@ import ( "bytes" "strings" - "gopkg.in/yaml.v3" "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml" "sigs.k8s.io/kustomize/kyaml/sets" ) @@ -213,7 +213,10 @@ func String(node *yaml.Node, opts ...string) (string, error) { b := &bytes.Buffer{} e := NewEncoder(b) err := e.Encode(node) - e.Close() + errClose := e.Close() + if err == nil { + err = errClose + } val := b.String() if optsSet.Has(Trim) { val = strings.TrimSpace(val) diff --git a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/walk/associative_sequence.go b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/walk/associative_sequence.go index 3b6222a9a4b..7657ebc0fac 100644 --- a/vendor/sigs.k8s.io/kustomize/kyaml/yaml/walk/associative_sequence.go +++ b/vendor/sigs.k8s.io/kustomize/kyaml/yaml/walk/associative_sequence.go @@ -53,14 +53,27 @@ func appendListNode(dst, src *yaml.RNode, keys []string) (*yaml.RNode, error) { v = append(v, valueNode.YNode().Value) } + // When there are multiple keys, ElementSetter appends the node to dst + // even if the output is already in dst. We remove the node from dst to + // prevent duplicates. + if len(keys) > 1 { + _, err = dst.Pipe(yaml.ElementSetter{ + Keys: keys, + Values: v, + }) + if err != nil { + return nil, err + } + } + // We use the key and value from elem to find the corresponding element in dst. // Then we will use ElementSetter to replace the element with elem. If we cannot + // find the item, the element will be appended. _, err = dst.Pipe(yaml.ElementSetter{ Element: elem, Keys: keys, Values: v, }) - if err != nil { return nil, err } @@ -97,6 +110,47 @@ func validateKeys(valuesList [][]string, values []string, keys []string) ([]stri return validKeys, validValues } +// mergeValues merges values together - e.g. if two containerPorts +// have the same port and targetPort but one has an empty protocol +// and the other doesn't, they are treated as the same containerPort +func mergeValues(valuesList [][]string) [][]string { + for i, values1 := range valuesList { + for j, values2 := range valuesList { + if matched, values := match(values1, values2); matched { + valuesList[i] = values + valuesList[j] = values + } + } + } + return valuesList +} + +// two values match if they have at least one common element and +// corresponding elements only differ if one is an empty string +func match(values1 []string, values2 []string) (bool, []string) { + if len(values1) != len(values2) { + return false, nil + } + var commonElement bool + var res []string + for i := range values1 { + if values1[i] == values2[i] { + commonElement = true + res = append(res, values1[i]) + continue + } + if values1[i] != "" && values2[i] != "" { + return false, nil + } + if values1[i] != "" { + res = append(res, values1[i]) + } else { + res = append(res, values2[i]) + } + } + return commonElement, res +} + // setAssociativeSequenceElements recursively set the elements in the list func (l *Walker) setAssociativeSequenceElements(valuesList [][]string, keys []string, dest *yaml.RNode) (*yaml.RNode, error) { // itemsToBeAdded contains the items that will be added to dest @@ -105,6 +159,9 @@ func (l *Walker) setAssociativeSequenceElements(valuesList [][]string, keys []st if l.Schema != nil { schema = l.Schema.Elements() } + if len(keys) > 1 { + valuesList = mergeValues(valuesList) + } // each element in valuesList is a list of values corresponding to the keys // for example, for the following yaml: @@ -114,12 +171,14 @@ func (l *Walker) setAssociativeSequenceElements(valuesList [][]string, keys []st // protocol: TCP // `keys` would be [containerPort, protocol] // and `valuesList` would be [ [8080, UDP], [8080, TCP] ] + var validKeys []string + var validValues []string for _, values := range valuesList { if len(values) == 0 { continue } - validKeys, validValues := validateKeys(valuesList, values, keys) + validKeys, validValues = validateKeys(valuesList, values, keys) val, err := Walker{ VisitKeysAsScalars: l.VisitKeysAsScalars, InferAssociativeLists: l.InferAssociativeLists, @@ -144,7 +203,7 @@ func (l *Walker) setAssociativeSequenceElements(valuesList [][]string, keys []st return nil, err } exit = true - } else if val.Field(key) == nil { + } else if val.Field(key) == nil && validValues[i] != "" { // make sure the key is set on the field _, err = val.Pipe(yaml.SetField(key, yaml.NewScalarRNode(validValues[i]))) if err != nil { @@ -162,7 +221,7 @@ func (l *Walker) setAssociativeSequenceElements(valuesList [][]string, keys []st _, err = itemsToBeAdded.Pipe(yaml.ElementSetter{ Element: val.YNode(), Keys: validKeys, - Values: values, + Values: validValues, }) if err != nil { return nil, err @@ -171,7 +230,6 @@ func (l *Walker) setAssociativeSequenceElements(valuesList [][]string, keys []st var err error if len(valuesList) > 0 { - validKeys, _ := validateKeys(valuesList, valuesList[0], keys) if l.MergeOptions.ListIncreaseDirection == yaml.MergeOptionsListPrepend { // items from patches are needed to be prepended. so we append the // dest to itemsToBeAdded @@ -314,6 +372,7 @@ func (l Walker) elementPrimitiveValues() [][]string { // fieldValue returns a slice containing each source's value for fieldName func (l Walker) elementValueList(keys []string, values []string) []*yaml.RNode { + keys, values = validateKeys([][]string{values}, values, keys) var fields []*yaml.RNode for i := range l.Sources { if l.Sources[i] == nil {