func addAttribution(crd *apiext.CustomResourceDefinition) {
	if crd.ObjectMeta.Annotations == nil {
		crd.ObjectMeta.Annotations = map[string]string{}
	}
	crd.ObjectMeta.Annotations["controller-gen.kubebuilder.io/version"] = version.Version()
}
addAttribution adds attribution info to indicate controller-gen tool was used
to generate this CRD definition along with the version info.
package crd
import (
	"fmt"
	"go/ast"
	"go/types"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers"
	"sigs.k8s.io/controller-tools/pkg/genall"
	"sigs.k8s.io/controller-tools/pkg/loader"
	"sigs.k8s.io/controller-tools/pkg/markers"
	"sigs.k8s.io/controller-tools/pkg/version"
)
const v1 = "v1"
const defaultVersion = v1
type Generator struct {
	AllowDangerousTypes *bool `marker:",optional"`
	MaxDescLen *int `marker:",optional"`
	CRDVersions []string `marker:"crdVersions,optional"`
	GenerateEmbeddedObjectMeta *bool `marker:",optional"`
}
func (Generator) CheckFilter() loader.NodeFilter {
	return filterTypesForCRDs
}
func (Generator) RegisterMarkers(into *markers.Registry) error {
	return crdmarkers.Register(into)
}
func (g Generator) Generate(ctx *genall.GenerationContext) error {
	parser := &Parser{
		Collector: ctx.Collector,
		Checker:   ctx.Checker,
		AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
		GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true,
	}
	AddKnownTypes(parser)
	for _, root := range ctx.Roots {
		parser.NeedPackage(root)
	}
	metav1Pkg := FindMetav1(ctx.Roots)
	if metav1Pkg == nil {
		return nil
	}
	kubeKinds := FindKubeKinds(parser, metav1Pkg)
	if len(kubeKinds) == 0 {
		return nil
	}
	crdVersions := g.CRDVersions
	if len(crdVersions) == 0 {
		crdVersions = []string{defaultVersion}
	}
	for groupKind := range kubeKinds {
		parser.NeedCRDFor(groupKind, g.MaxDescLen)
		crdRaw := parser.CustomResourceDefinitions[groupKind]
		addAttribution(&crdRaw)
		FixTopLevelMetadata(crdRaw)
		versionedCRDs := make([]interface{}, len(crdVersions))
		for i, ver := range crdVersions {
			conv, err := AsVersion(crdRaw, schema.GroupVersion{Group: apiext.SchemeGroupVersion.Group, Version: ver})
			if err != nil {
				return err
			}
			versionedCRDs[i] = conv
		}
		for i, crd := range versionedCRDs {
			removeDescriptionFromMetadata(crd.(*apiext.CustomResourceDefinition))
			var fileName string
			if i == 0 {
				fileName = fmt.Sprintf("%s_%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural)
			} else {
				fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i])
			}
			if err := ctx.WriteYAML(fileName, crd); err != nil {
				return err
			}
		}
	}
	return nil
}
func removeDescriptionFromMetadata(crd *apiext.CustomResourceDefinition) {
	for _, versionSpec := range crd.Spec.Versions {
		if versionSpec.Schema != nil {
			removeDescriptionFromMetadataProps(versionSpec.Schema.OpenAPIV3Schema)
		}
	}
}
func removeDescriptionFromMetadataProps(v *apiext.JSONSchemaProps) {
	if m, ok := v.Properties["metadata"]; ok {
		meta := &m
		if meta.Description != "" {
			meta.Description = ""
			v.Properties["metadata"] = m
		}
	}
}
func FixTopLevelMetadata(crd apiext.CustomResourceDefinition) {
	for _, v := range crd.Spec.Versions {
		if v.Schema != nil && v.Schema.OpenAPIV3Schema != nil && v.Schema.OpenAPIV3Schema.Properties != nil {
			schemaProperties := v.Schema.OpenAPIV3Schema.Properties
			if _, ok := schemaProperties["metadata"]; ok {
				schemaProperties["metadata"] = apiext.JSONSchemaProps{Type: "object"}
			}
		}
	}
}