add service mesh metrics remove unused circle yaml fix travis misconfiguration fix travis misconfiguration fix travis misconfiguration
288 lines
8.5 KiB
Go
288 lines
8.5 KiB
Go
/*
|
|
Copyright 2018 The Kubernetes 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 parse
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
"k8s.io/gengo/types"
|
|
"sigs.k8s.io/controller-tools/pkg/internal/codegen"
|
|
)
|
|
|
|
type genUnversionedType struct {
|
|
Type *types.Type
|
|
Resource *codegen.APIResource
|
|
}
|
|
|
|
func (b *APIs) parseAPIs() {
|
|
apis := &codegen.APIs{
|
|
Domain: b.Domain,
|
|
Package: b.APIsPkg,
|
|
Groups: map[string]*codegen.APIGroup{},
|
|
Rules: b.Rules,
|
|
Informers: b.Informers,
|
|
}
|
|
|
|
for group, versionMap := range b.ByGroupVersionKind {
|
|
apiGroup := &codegen.APIGroup{
|
|
Group: group,
|
|
GroupTitle: strings.Title(group),
|
|
Domain: b.Domain,
|
|
Versions: map[string]*codegen.APIVersion{},
|
|
UnversionedResources: map[string]*codegen.APIResource{},
|
|
}
|
|
|
|
for version, kindMap := range versionMap {
|
|
apiVersion := &codegen.APIVersion{
|
|
Domain: b.Domain,
|
|
Group: group,
|
|
Version: version,
|
|
Resources: map[string]*codegen.APIResource{},
|
|
}
|
|
for kind, resource := range kindMap {
|
|
apiResource := &codegen.APIResource{
|
|
Domain: resource.Domain,
|
|
Version: resource.Version,
|
|
Group: resource.Group,
|
|
Resource: resource.Resource,
|
|
Type: resource.Type,
|
|
REST: resource.REST,
|
|
Kind: resource.Kind,
|
|
Subresources: resource.Subresources,
|
|
StatusStrategy: resource.StatusStrategy,
|
|
Strategy: resource.Strategy,
|
|
NonNamespaced: resource.NonNamespaced,
|
|
ShortName: resource.ShortName,
|
|
}
|
|
parseDoc(resource, apiResource)
|
|
apiVersion.Resources[kind] = apiResource
|
|
// Set the package for the api version
|
|
apiVersion.Pkg = b.context.Universe[resource.Type.Name.Package]
|
|
// Set the package for the api group
|
|
apiGroup.Pkg = b.context.Universe[filepath.Dir(resource.Type.Name.Package)]
|
|
if apiGroup.Pkg != nil {
|
|
apiGroup.PkgPath = apiGroup.Pkg.Path
|
|
}
|
|
|
|
apiGroup.UnversionedResources[kind] = apiResource
|
|
}
|
|
|
|
apiGroup.Versions[version] = apiVersion
|
|
}
|
|
b.parseStructs(apiGroup)
|
|
apis.Groups[group] = apiGroup
|
|
}
|
|
apis.Pkg = b.context.Universe[b.APIsPkg]
|
|
b.APIs = apis
|
|
}
|
|
|
|
func (b *APIs) parseStructs(apigroup *codegen.APIGroup) {
|
|
remaining := []genUnversionedType{}
|
|
for _, version := range apigroup.Versions {
|
|
for _, resource := range version.Resources {
|
|
remaining = append(remaining, genUnversionedType{resource.Type, resource})
|
|
}
|
|
}
|
|
for _, version := range b.SubByGroupVersionKind[apigroup.Group] {
|
|
for _, kind := range version {
|
|
remaining = append(remaining, genUnversionedType{kind, nil})
|
|
}
|
|
}
|
|
|
|
done := sets.String{}
|
|
for len(remaining) > 0 {
|
|
// Pop the next element from the list
|
|
next := remaining[0]
|
|
remaining[0] = remaining[len(remaining)-1]
|
|
remaining = remaining[:len(remaining)-1]
|
|
|
|
// Already processed this type. Skip it
|
|
if done.Has(next.Type.Name.Name) {
|
|
continue
|
|
}
|
|
done.Insert(next.Type.Name.Name)
|
|
|
|
// Generate the struct and append to the list
|
|
result, additionalTypes := parseType(next.Type)
|
|
|
|
// This is a resource, so generate the client
|
|
if b.genClient(next.Type) {
|
|
result.GenClient = true
|
|
result.GenDeepCopy = true
|
|
}
|
|
|
|
if next.Resource != nil {
|
|
result.NonNamespaced = IsNonNamespaced(next.Type)
|
|
}
|
|
|
|
if b.genDeepCopy(next.Type) {
|
|
result.GenDeepCopy = true
|
|
}
|
|
apigroup.Structs = append(apigroup.Structs, result)
|
|
|
|
// Add the newly discovered subtypes
|
|
for _, at := range additionalTypes {
|
|
remaining = append(remaining, genUnversionedType{at, nil})
|
|
}
|
|
}
|
|
}
|
|
|
|
// parseType parses the type into a Struct, and returns a list of types that
|
|
// need to be parsed
|
|
func parseType(t *types.Type) (*codegen.Struct, []*types.Type) {
|
|
remaining := []*types.Type{}
|
|
|
|
s := &codegen.Struct{
|
|
Name: t.Name.Name,
|
|
GenClient: false,
|
|
GenUnversioned: true, // Generate unversioned structs by default
|
|
}
|
|
|
|
for _, c := range t.CommentLines {
|
|
if strings.Contains(c, "+genregister:unversioned=false") {
|
|
// Don't generate the unversioned struct
|
|
s.GenUnversioned = false
|
|
}
|
|
}
|
|
|
|
for _, member := range t.Members {
|
|
uType := member.Type.Name.Name
|
|
memberName := member.Name
|
|
uImport := ""
|
|
|
|
// Use the element type for Pointers, Maps and Slices
|
|
mSubType := member.Type
|
|
hasElem := false
|
|
for mSubType.Elem != nil {
|
|
mSubType = mSubType.Elem
|
|
hasElem = true
|
|
}
|
|
if hasElem {
|
|
// Strip the package from the field type
|
|
uType = strings.Replace(member.Type.String(), mSubType.Name.Package+".", "", 1)
|
|
}
|
|
|
|
base := filepath.Base(member.Type.String())
|
|
samepkg := t.Name.Package == mSubType.Name.Package
|
|
|
|
// If not in the same package, calculate the import pkg
|
|
if !samepkg {
|
|
parts := strings.Split(base, ".")
|
|
if len(parts) > 1 {
|
|
// Don't generate unversioned types for core types, just use the versioned types
|
|
if strings.HasPrefix(mSubType.Name.Package, "k8s.io/api/") {
|
|
// Import the package under an alias so it doesn't conflict with other groups
|
|
// having the same version
|
|
importAlias := path.Base(path.Dir(mSubType.Name.Package)) + path.Base(mSubType.Name.Package)
|
|
uImport = fmt.Sprintf("%s \"%s\"", importAlias, mSubType.Name.Package)
|
|
if hasElem {
|
|
// Replace the full package with the alias when referring to the type
|
|
uType = strings.Replace(member.Type.String(), mSubType.Name.Package, importAlias, 1)
|
|
} else {
|
|
// Replace the full package with the alias when referring to the type
|
|
uType = fmt.Sprintf("%s.%s", importAlias, parts[1])
|
|
}
|
|
} else {
|
|
switch member.Type.Name.Package {
|
|
case "k8s.io/apimachinery/pkg/apis/meta/v1":
|
|
// Use versioned types for meta/v1
|
|
uImport = fmt.Sprintf("%s \"%s\"", "metav1", "k8s.io/apimachinery/pkg/apis/meta/v1")
|
|
uType = "metav1." + parts[1]
|
|
default:
|
|
// Use unversioned types for everything else
|
|
t := member.Type
|
|
|
|
if t.Elem != nil {
|
|
// handle Pointers, Maps, Slices
|
|
|
|
// We need to parse the package from the Type String
|
|
t = t.Elem
|
|
str := member.Type.String()
|
|
startPkg := strings.LastIndexAny(str, "*]")
|
|
endPkg := strings.LastIndexAny(str, ".")
|
|
pkg := str[startPkg+1 : endPkg]
|
|
name := str[endPkg+1:]
|
|
prefix := str[:startPkg+1]
|
|
|
|
uImportBase := path.Base(pkg)
|
|
uImportName := path.Base(path.Dir(pkg)) + uImportBase
|
|
uImport = fmt.Sprintf("%s \"%s\"", uImportName, pkg)
|
|
|
|
uType = prefix + uImportName + "." + name
|
|
} else {
|
|
// handle non- Pointer, Maps, Slices
|
|
pkg := t.Name.Package
|
|
name := t.Name.Name
|
|
|
|
// Come up with the alias the package is imported under
|
|
// Concatenate with directory package to reduce naming collisions
|
|
uImportBase := path.Base(pkg)
|
|
uImportName := path.Base(path.Dir(pkg)) + uImportBase
|
|
|
|
// Create the import statement
|
|
uImport = fmt.Sprintf("%s \"%s\"", uImportName, pkg)
|
|
|
|
// Create the field type name - should be <pkgalias>.<TypeName>
|
|
uType = uImportName + "." + name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if member.Embedded {
|
|
memberName = ""
|
|
}
|
|
|
|
s.Fields = append(s.Fields, &codegen.Field{
|
|
Name: memberName,
|
|
VersionedPackage: member.Type.Name.Package,
|
|
UnversionedImport: uImport,
|
|
UnversionedType: uType,
|
|
})
|
|
|
|
// Add this member Type for processing if it isn't a primitive and
|
|
// is part of the same API group
|
|
if !mSubType.IsPrimitive() && GetGroup(mSubType) == GetGroup(t) {
|
|
remaining = append(remaining, mSubType)
|
|
}
|
|
}
|
|
return s, remaining
|
|
}
|
|
|
|
func (b *APIs) genClient(c *types.Type) bool {
|
|
comments := Comments(c.CommentLines)
|
|
resource := comments.getTag("resource", ":") + comments.getTag("kubebuilder:resource", ":")
|
|
return len(resource) > 0
|
|
}
|
|
|
|
func (b *APIs) genDeepCopy(c *types.Type) bool {
|
|
comments := Comments(c.CommentLines)
|
|
return comments.hasTag("subresource-request")
|
|
}
|
|
|
|
func parseDoc(resource, apiResource *codegen.APIResource) {
|
|
if HasDocAnnotation(resource.Type) {
|
|
resource.DocAnnotation = getDocAnnotation(resource.Type, "warning", "note")
|
|
apiResource.DocAnnotation = resource.DocAnnotation
|
|
}
|
|
}
|