1. update clientset, deepcopy using code-generator
2. add a dummy file tools.go to force "go mod vendor" to see code-generator as dependencies 3. add a script to update CRD 4. add a README to document CRD updating steps run go mod tidy update README
This commit is contained in:
924
vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
generated
vendored
Normal file
924
vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,924 @@
|
||||
/*
|
||||
Copyright 2015 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 generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/examples/set-gen/sets"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// CustomArgs is used tby the go2idl framework to pass args specific to this
|
||||
// generator.
|
||||
type CustomArgs struct {
|
||||
BoundingDirs []string // Only deal with types rooted under these dirs.
|
||||
}
|
||||
|
||||
// This is the comment tag that carries parameters for deep-copy generation.
|
||||
const (
|
||||
tagEnabledName = "k8s:deepcopy-gen"
|
||||
interfacesTagName = tagEnabledName + ":interfaces"
|
||||
interfacesNonPointerTagName = tagEnabledName + ":nonpointer-interfaces" // attach the DeepCopy<Interface> methods to the
|
||||
)
|
||||
|
||||
// Known values for the comment tag.
|
||||
const tagValuePackage = "package"
|
||||
|
||||
// enabledTagValue holds parameters from a tagName tag.
|
||||
type enabledTagValue struct {
|
||||
value string
|
||||
register bool
|
||||
}
|
||||
|
||||
func extractEnabledTypeTag(t *types.Type) *enabledTagValue {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
return extractEnabledTag(comments)
|
||||
}
|
||||
|
||||
func extractEnabledTag(comments []string) *enabledTagValue {
|
||||
tagVals := types.ExtractCommentTags("+", comments)[tagEnabledName]
|
||||
if tagVals == nil {
|
||||
// No match for the tag.
|
||||
return nil
|
||||
}
|
||||
// If there are multiple values, abort.
|
||||
if len(tagVals) > 1 {
|
||||
klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagEnabledName, tagVals)
|
||||
}
|
||||
|
||||
// If we got here we are returning something.
|
||||
tag := &enabledTagValue{}
|
||||
|
||||
// Get the primary value.
|
||||
parts := strings.Split(tagVals[0], ",")
|
||||
if len(parts) >= 1 {
|
||||
tag.value = parts[0]
|
||||
}
|
||||
|
||||
// Parse extra arguments.
|
||||
parts = parts[1:]
|
||||
for i := range parts {
|
||||
kv := strings.SplitN(parts[i], "=", 2)
|
||||
k := kv[0]
|
||||
v := ""
|
||||
if len(kv) == 2 {
|
||||
v = kv[1]
|
||||
}
|
||||
switch k {
|
||||
case "register":
|
||||
if v != "false" {
|
||||
tag.register = true
|
||||
}
|
||||
default:
|
||||
klog.Fatalf("Unsupported %s param: %q", tagEnabledName, parts[i])
|
||||
}
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// TODO: This is created only to reduce number of changes in a single PR.
|
||||
// Remove it and use PublicNamer instead.
|
||||
func deepCopyNamer() *namer.NameStrategy {
|
||||
return &namer.NameStrategy{
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return strings.Join(in, "_")
|
||||
},
|
||||
PrependPackageNames: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": deepCopyNamer(),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "public"
|
||||
}
|
||||
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
|
||||
inputs := sets.NewString(context.Inputs...)
|
||||
packages := generator.Packages{}
|
||||
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
||||
|
||||
boundingDirs := []string{}
|
||||
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
|
||||
if customArgs.BoundingDirs == nil {
|
||||
customArgs.BoundingDirs = context.Inputs
|
||||
}
|
||||
for i := range customArgs.BoundingDirs {
|
||||
// Strip any trailing slashes - they are not exactly "correct" but
|
||||
// this is friendlier.
|
||||
boundingDirs = append(boundingDirs, strings.TrimRight(customArgs.BoundingDirs[i], "/"))
|
||||
}
|
||||
}
|
||||
|
||||
for i := range inputs {
|
||||
klog.V(5).Infof("Considering pkg %q", i)
|
||||
pkg := context.Universe[i]
|
||||
if pkg == nil {
|
||||
// If the input had no Go files, for example.
|
||||
continue
|
||||
}
|
||||
|
||||
ptag := extractEnabledTag(pkg.Comments)
|
||||
ptagValue := ""
|
||||
ptagRegister := false
|
||||
if ptag != nil {
|
||||
ptagValue = ptag.value
|
||||
if ptagValue != tagValuePackage {
|
||||
klog.Fatalf("Package %v: unsupported %s value: %q", i, tagEnabledName, ptagValue)
|
||||
}
|
||||
ptagRegister = ptag.register
|
||||
klog.V(5).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
|
||||
} else {
|
||||
klog.V(5).Infof(" no tag")
|
||||
}
|
||||
|
||||
// If the pkg-scoped tag says to generate, we can skip scanning types.
|
||||
pkgNeedsGeneration := (ptagValue == tagValuePackage)
|
||||
if !pkgNeedsGeneration {
|
||||
// If the pkg-scoped tag did not exist, scan all types for one that
|
||||
// explicitly wants generation.
|
||||
for _, t := range pkg.Types {
|
||||
klog.V(5).Infof(" considering type %q", t.Name.String())
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "true" {
|
||||
klog.V(5).Infof(" tag=true")
|
||||
if !copyableType(t) {
|
||||
klog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
|
||||
}
|
||||
pkgNeedsGeneration = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pkgNeedsGeneration {
|
||||
klog.V(3).Infof("Package %q needs generation", i)
|
||||
path := pkg.Path
|
||||
// if the source path is within a /vendor/ directory (for example,
|
||||
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
|
||||
// generation to output to the proper relative path (under vendor).
|
||||
// Otherwise, the generator will create the file in the wrong location
|
||||
// in the output directory.
|
||||
// TODO: build a more fundamental concept in gengo for dealing with modifications
|
||||
// to vendored packages.
|
||||
if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
|
||||
expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
|
||||
if strings.Contains(expandedPath, "/vendor/") {
|
||||
path = expandedPath
|
||||
}
|
||||
}
|
||||
packages = append(packages,
|
||||
&generator.DefaultPackage{
|
||||
PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0],
|
||||
PackagePath: path,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
NewGenDeepCopy(arguments.OutputFileBaseName, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister),
|
||||
}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
return t.Name.Package == pkg.Path
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
// genDeepCopy produces a file with autogenerated deep-copy functions.
|
||||
type genDeepCopy struct {
|
||||
generator.DefaultGen
|
||||
targetPackage string
|
||||
boundingDirs []string
|
||||
allTypes bool
|
||||
registerTypes bool
|
||||
imports namer.ImportTracker
|
||||
typesForInit []*types.Type
|
||||
}
|
||||
|
||||
func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator {
|
||||
return &genDeepCopy{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
targetPackage: targetPackage,
|
||||
boundingDirs: boundingDirs,
|
||||
allTypes: allTypes,
|
||||
registerTypes: registerTypes,
|
||||
imports: generator.NewImportTracker(),
|
||||
typesForInit: make([]*types.Type, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems {
|
||||
// Have the raw namer for this file track what it imports.
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool {
|
||||
// Filter out types not being processed or not copyable within the package.
|
||||
enabled := g.allTypes
|
||||
if !enabled {
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "true" {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
if !enabled {
|
||||
return false
|
||||
}
|
||||
if !copyableType(t) {
|
||||
klog.V(2).Infof("Type %v is not copyable", t)
|
||||
return false
|
||||
}
|
||||
klog.V(4).Infof("Type %v is copyable", t)
|
||||
g.typesForInit = append(g.typesForInit, t)
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) copyableAndInBounds(t *types.Type) bool {
|
||||
if !copyableType(t) {
|
||||
return false
|
||||
}
|
||||
// Only packages within the restricted range can be processed.
|
||||
if !isRootedUnder(t.Name.Package, g.boundingDirs) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// deepCopyMethod returns the signature of a DeepCopy() method, nil or an error
|
||||
// if the type does not match. This allows more efficient deep copy
|
||||
// implementations to be defined by the type's author. The correct signature
|
||||
// for a type T is:
|
||||
// func (t T) DeepCopy() T
|
||||
// or:
|
||||
// func (t *T) DeepCopy() *T
|
||||
func deepCopyMethod(t *types.Type) (*types.Signature, error) {
|
||||
f, found := t.Methods["DeepCopy"]
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
if len(f.Signature.Parameters) != 0 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no parameters", t)
|
||||
}
|
||||
if len(f.Signature.Results) != 1 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one result", t)
|
||||
}
|
||||
|
||||
ptrResult := f.Signature.Results[0].Kind == types.Pointer && f.Signature.Results[0].Elem.Name == t.Name
|
||||
nonPtrResult := f.Signature.Results[0].Name == t.Name
|
||||
|
||||
if !ptrResult && !nonPtrResult {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected to return %s or *%s", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
||||
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
||||
|
||||
if ptrRcvr && !ptrResult {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a *%s result for a *%s receiver", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
if nonPtrRcvr && !nonPtrResult {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a %s result for a %s receiver", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
return f.Signature, nil
|
||||
}
|
||||
|
||||
// deepCopyMethodOrDie returns the signatrue of a DeepCopy method, nil or calls klog.Fatalf
|
||||
// if the type does not match.
|
||||
func deepCopyMethodOrDie(t *types.Type) *types.Signature {
|
||||
ret, err := deepCopyMethod(t)
|
||||
if err != nil {
|
||||
klog.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// deepCopyIntoMethod returns the signature of a DeepCopyInto() method, nil or an error
|
||||
// if the type is wrong. DeepCopyInto allows more efficient deep copy
|
||||
// implementations to be defined by the type's author. The correct signature
|
||||
// for a type T is:
|
||||
// func (t T) DeepCopyInto(t *T)
|
||||
// or:
|
||||
// func (t *T) DeepCopyInto(t *T)
|
||||
func deepCopyIntoMethod(t *types.Type) (*types.Signature, error) {
|
||||
f, found := t.Methods["DeepCopyInto"]
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
if len(f.Signature.Parameters) != 1 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one parameter", t)
|
||||
}
|
||||
if len(f.Signature.Results) != 0 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no result type", t)
|
||||
}
|
||||
|
||||
ptrParam := f.Signature.Parameters[0].Kind == types.Pointer && f.Signature.Parameters[0].Elem.Name == t.Name
|
||||
|
||||
if !ptrParam {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected parameter of type *%s", t, t.Name.Name)
|
||||
}
|
||||
|
||||
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
||||
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
||||
|
||||
if !ptrRcvr && !nonPtrRcvr {
|
||||
// this should never happen
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a receiver of type %s or *%s", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
return f.Signature, nil
|
||||
}
|
||||
|
||||
// deepCopyIntoMethodOrDie returns the signature of a DeepCopyInto() method, nil or calls klog.Fatalf
|
||||
// if the type is wrong.
|
||||
func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature {
|
||||
ret, err := deepCopyIntoMethod(t)
|
||||
if err != nil {
|
||||
klog.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func isRootedUnder(pkg string, roots []string) bool {
|
||||
// Add trailing / to avoid false matches, e.g. foo/bar vs foo/barn. This
|
||||
// assumes that bounding dirs do not have trailing slashes.
|
||||
pkg = pkg + "/"
|
||||
for _, root := range roots {
|
||||
if strings.HasPrefix(pkg, root+"/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func copyableType(t *types.Type) bool {
|
||||
// If the type opts out of copy-generation, stop.
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "false" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter out private types.
|
||||
if namer.IsPrivateGoName(t.Name.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if t.Kind == types.Alias {
|
||||
// if the underlying built-in is not deepcopy-able, deepcopy is opt-in through definition of custom methods.
|
||||
// Note that aliases of builtins, maps, slices can have deepcopy methods.
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
return true
|
||||
} else {
|
||||
return t.Underlying.Kind != types.Builtin || copyableType(t.Underlying)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Kind != types.Struct {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func underlyingType(t *types.Type) *types.Type {
|
||||
for t.Kind == types.Alias {
|
||||
t = t.Underlying
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.targetPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) {
|
||||
importLines := []string{}
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
if g.isOtherPackage(singleImport) {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func argsFromType(ts ...*types.Type) generator.Args {
|
||||
a := generator.Args{
|
||||
"type": ts[0],
|
||||
}
|
||||
for i, t := range ts {
|
||||
a[fmt.Sprintf("type%d", i+1)] = t
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) needsGeneration(t *types.Type) bool {
|
||||
tag := extractEnabledTypeTag(t)
|
||||
tv := ""
|
||||
if tag != nil {
|
||||
tv = tag.value
|
||||
if tv != "true" && tv != "false" {
|
||||
klog.Fatalf("Type %v: unsupported %s value: %q", t, tagEnabledName, tag.value)
|
||||
}
|
||||
}
|
||||
if g.allTypes && tv == "false" {
|
||||
// The whole package is being generated, but this type has opted out.
|
||||
klog.V(5).Infof("Not generating for type %v because type opted out", t)
|
||||
return false
|
||||
}
|
||||
if !g.allTypes && tv != "true" {
|
||||
// The whole package is NOT being generated, and this type has NOT opted in.
|
||||
klog.V(5).Infof("Not generating for type %v because type did not opt in", t)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func extractInterfacesTag(t *types.Type) []string {
|
||||
var result []string
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
values := types.ExtractCommentTags("+", comments)[interfacesTagName]
|
||||
for _, v := range values {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
}
|
||||
intfs := strings.Split(v, ",")
|
||||
for _, intf := range intfs {
|
||||
if intf == "" {
|
||||
continue
|
||||
}
|
||||
result = append(result, intf)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func extractNonPointerInterfaces(t *types.Type) (bool, error) {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
values := types.ExtractCommentTags("+", comments)[interfacesNonPointerTagName]
|
||||
if len(values) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
result := values[0] == "true"
|
||||
for _, v := range values {
|
||||
if v == "true" != result {
|
||||
return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) {
|
||||
if t.Kind != types.Struct {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
intfs := extractInterfacesTag(t)
|
||||
|
||||
var ts []*types.Type
|
||||
for _, intf := range intfs {
|
||||
t := types.ParseFullyQualifiedName(intf)
|
||||
c.AddDir(t.Package)
|
||||
intfT := c.Universe.Type(t)
|
||||
if intfT == nil {
|
||||
return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT)
|
||||
}
|
||||
if intfT.Kind != types.Interface {
|
||||
return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind)
|
||||
}
|
||||
g.imports.AddType(intfT)
|
||||
ts = append(ts, intfT)
|
||||
}
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// deepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver.
|
||||
func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) {
|
||||
ts, err := g.deepCopyableInterfacesInner(c, t)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
set := map[string]*types.Type{}
|
||||
for _, t := range ts {
|
||||
set[t.String()] = t
|
||||
}
|
||||
|
||||
result := []*types.Type{}
|
||||
for _, t := range set {
|
||||
result = append(result, t)
|
||||
}
|
||||
|
||||
TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation
|
||||
|
||||
nonPointerReceiver, err := extractNonPointerInterfaces(t)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return result, nonPointerReceiver, nil
|
||||
}
|
||||
|
||||
type TypeSlice []*types.Type
|
||||
|
||||
func (s TypeSlice) Len() int { return len(s) }
|
||||
func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() }
|
||||
func (s TypeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s TypeSlice) Sort() { sort.Sort(s) }
|
||||
|
||||
func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
if !g.needsGeneration(t) {
|
||||
return nil
|
||||
}
|
||||
klog.V(5).Infof("Generating deepcopy function for type %v", t)
|
||||
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
args := argsFromType(t)
|
||||
|
||||
if deepCopyIntoMethodOrDie(t) == nil {
|
||||
sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args)
|
||||
if isReference(t) {
|
||||
sw.Do("func (in $.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
||||
sw.Do("{in:=&in\n", nil)
|
||||
} else {
|
||||
sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
||||
}
|
||||
if deepCopyMethodOrDie(t) != nil {
|
||||
if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer {
|
||||
sw.Do("clone := in.DeepCopy()\n", nil)
|
||||
sw.Do("*out = *clone\n", nil)
|
||||
} else {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
}
|
||||
sw.Do("return\n", nil)
|
||||
} else {
|
||||
g.generateFor(t, sw)
|
||||
sw.Do("return\n", nil)
|
||||
}
|
||||
if isReference(t) {
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
if deepCopyMethodOrDie(t) == nil {
|
||||
sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args)
|
||||
if isReference(t) {
|
||||
sw.Do("func (in $.type|raw$) DeepCopy() $.type|raw$ {\n", args)
|
||||
} else {
|
||||
sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
|
||||
}
|
||||
sw.Do("if in == nil { return nil }\n", nil)
|
||||
sw.Do("out := new($.type|raw$)\n", args)
|
||||
sw.Do("in.DeepCopyInto(out)\n", nil)
|
||||
if isReference(t) {
|
||||
sw.Do("return *out\n", nil)
|
||||
} else {
|
||||
sw.Do("return out\n", nil)
|
||||
}
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
intfs, nonPointerReceiver, err := g.deepCopyableInterfaces(c, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, intf := range intfs {
|
||||
sw.Do(fmt.Sprintf("// DeepCopy%s is an autogenerated deepcopy function, copying the receiver, creating a new $.type2|raw$.\n", intf.Name.Name), argsFromType(t, intf))
|
||||
if nonPointerReceiver {
|
||||
sw.Do(fmt.Sprintf("func (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
|
||||
sw.Do("return *in.DeepCopy()", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
} else {
|
||||
sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
|
||||
sw.Do("if c := in.DeepCopy(); c != nil {\n", nil)
|
||||
sw.Do("return c\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("return nil\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
// isReference return true for pointer, maps, slices and aliases of those.
|
||||
func isReference(t *types.Type) bool {
|
||||
if t.Kind == types.Pointer || t.Kind == types.Map || t.Kind == types.Slice {
|
||||
return true
|
||||
}
|
||||
return t.Kind == types.Alias && isReference(underlyingType(t))
|
||||
}
|
||||
|
||||
// we use the system of shadowing 'in' and 'out' so that the same code is valid
|
||||
// at any nesting level. This makes the autogenerator easy to understand, and
|
||||
// the compiler shouldn't care.
|
||||
func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
|
||||
// derive inner types if t is an alias. We call the do* methods below with the alias type.
|
||||
// basic rule: generate according to inner type, but construct objects with the alias type.
|
||||
ut := underlyingType(t)
|
||||
|
||||
var f func(*types.Type, *generator.SnippetWriter)
|
||||
switch ut.Kind {
|
||||
case types.Builtin:
|
||||
f = g.doBuiltin
|
||||
case types.Map:
|
||||
f = g.doMap
|
||||
case types.Slice:
|
||||
f = g.doSlice
|
||||
case types.Struct:
|
||||
f = g.doStruct
|
||||
case types.Pointer:
|
||||
f = g.doPointer
|
||||
case types.Interface:
|
||||
// interfaces are handled in-line in the other cases
|
||||
klog.Fatalf("Hit an interface type %v. This should never happen.", t)
|
||||
case types.Alias:
|
||||
// can never happen because we branch on the underlying type which is never an alias
|
||||
klog.Fatalf("Hit an alias type %v. This should never happen.", t)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v.", t)
|
||||
}
|
||||
f(t, sw)
|
||||
}
|
||||
|
||||
// doBuiltin generates code for a builtin or an alias to a builtin. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
sw.Do("*out = *in\n", nil)
|
||||
}
|
||||
|
||||
// doMap generates code for a map or an alias to a map. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
uet := underlyingType(ut.Elem)
|
||||
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if !ut.Key.IsAssignable() {
|
||||
klog.Fatalf("Hit an unsupported type %v for: %v", uet, t)
|
||||
}
|
||||
|
||||
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
||||
sw.Do("for key, val := range *in {\n", nil)
|
||||
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
|
||||
switch {
|
||||
case dc != nil || dci != nil:
|
||||
// Note: a DeepCopy exists because it is added if DeepCopyInto is manually defined
|
||||
leftPointer := ut.Elem.Kind == types.Pointer
|
||||
rightPointer := !isReference(ut.Elem)
|
||||
if dc != nil {
|
||||
rightPointer = dc.Results[0].Kind == types.Pointer
|
||||
}
|
||||
if leftPointer == rightPointer {
|
||||
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
|
||||
} else if leftPointer {
|
||||
sw.Do("x := val.DeepCopy()\n", nil)
|
||||
sw.Do("(*out)[key] = &x\n", nil)
|
||||
} else {
|
||||
sw.Do("(*out)[key] = *val.DeepCopy()\n", nil)
|
||||
}
|
||||
case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast
|
||||
sw.Do("(*out)[key] = val\n", nil)
|
||||
case uet.IsAssignable():
|
||||
sw.Do("(*out)[key] = val\n", nil)
|
||||
case uet.Kind == types.Interface:
|
||||
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
|
||||
if uet.Name.Name == "interface{}" {
|
||||
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
|
||||
}
|
||||
sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil)
|
||||
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
||||
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
||||
// parser does not give us the underlying interface name. So we cannot do any better.
|
||||
sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", uet.Name.Name), nil)
|
||||
sw.Do("}\n", nil)
|
||||
case uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer:
|
||||
sw.Do("var outVal $.|raw$\n", uet)
|
||||
sw.Do("if val == nil { (*out)[key] = nil } else {\n", nil)
|
||||
sw.Do("in, out := &val, &outVal\n", uet)
|
||||
g.generateFor(ut.Elem, sw)
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("(*out)[key] = outVal\n", nil)
|
||||
case uet.Kind == types.Struct:
|
||||
sw.Do("(*out)[key] = *val.DeepCopy()\n", uet)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
|
||||
// doSlice generates code for a slice or an alias to a slice. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
uet := underlyingType(ut.Elem)
|
||||
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
||||
if deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
|
||||
sw.Do("for i := range *in {\n", nil)
|
||||
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
|
||||
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
} else if uet.Kind == types.Builtin || uet.IsAssignable() {
|
||||
sw.Do("copy(*out, *in)\n", nil)
|
||||
} else {
|
||||
sw.Do("for i := range *in {\n", nil)
|
||||
if uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer || deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
|
||||
sw.Do("if (*in)[i] != nil {\n", nil)
|
||||
sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil)
|
||||
g.generateFor(ut.Elem, sw)
|
||||
sw.Do("}\n", nil)
|
||||
} else if uet.Kind == types.Interface {
|
||||
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
|
||||
if uet.Name.Name == "interface{}" {
|
||||
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
|
||||
}
|
||||
sw.Do("if (*in)[i] != nil {\n", nil)
|
||||
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
||||
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
||||
// parser does not give us the underlying interface name. So we cannot do any better.
|
||||
sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", uet.Name.Name), nil)
|
||||
sw.Do("}\n", nil)
|
||||
} else if uet.Kind == types.Struct {
|
||||
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
|
||||
} else {
|
||||
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
// doStruct generates code for a struct or an alias to a struct. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Simple copy covers a lot of cases.
|
||||
sw.Do("*out = *in\n", nil)
|
||||
|
||||
// Now fix-up fields as needed.
|
||||
for _, m := range ut.Members {
|
||||
ft := m.Type
|
||||
uft := underlyingType(ft)
|
||||
|
||||
args := generator.Args{
|
||||
"type": ft,
|
||||
"kind": ft.Kind,
|
||||
"name": m.Name,
|
||||
}
|
||||
dc, dci := deepCopyMethodOrDie(ft), deepCopyIntoMethodOrDie(ft)
|
||||
switch {
|
||||
case dc != nil || dci != nil:
|
||||
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
|
||||
leftPointer := ft.Kind == types.Pointer
|
||||
rightPointer := !isReference(ft)
|
||||
if dc != nil {
|
||||
rightPointer = dc.Results[0].Kind == types.Pointer
|
||||
}
|
||||
if leftPointer == rightPointer {
|
||||
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
|
||||
} else if leftPointer {
|
||||
sw.Do("x := in.$.name$.DeepCopy()\n", args)
|
||||
sw.Do("out.$.name$ = = &x\n", args)
|
||||
} else {
|
||||
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
|
||||
}
|
||||
case uft.Kind == types.Builtin:
|
||||
// the initial *out = *in was enough
|
||||
case uft.Kind == types.Map, uft.Kind == types.Slice, uft.Kind == types.Pointer:
|
||||
// Fixup non-nil reference-semantic types.
|
||||
sw.Do("if in.$.name$ != nil {\n", args)
|
||||
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
|
||||
g.generateFor(ft, sw)
|
||||
sw.Do("}\n", nil)
|
||||
case uft.Kind == types.Struct:
|
||||
if ft.IsAssignable() {
|
||||
sw.Do("out.$.name$ = in.$.name$\n", args)
|
||||
} else {
|
||||
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
|
||||
}
|
||||
case uft.Kind == types.Interface:
|
||||
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
|
||||
if uft.Name.Name == "interface{}" {
|
||||
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uft.Name.Name)
|
||||
}
|
||||
sw.Do("if in.$.name$ != nil {\n", args)
|
||||
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
||||
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
||||
// parser does not give us the underlying interface name. So we cannot do any better.
|
||||
sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", uft.Name.Name), args)
|
||||
sw.Do("}\n", nil)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v for %v, from %v", uft, ft, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doPointer generates code for a pointer or an alias to a pointer. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
uet := underlyingType(ut.Elem)
|
||||
|
||||
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
|
||||
switch {
|
||||
case dc != nil || dci != nil:
|
||||
rightPointer := !isReference(ut.Elem)
|
||||
if dc != nil {
|
||||
rightPointer = dc.Results[0].Kind == types.Pointer
|
||||
}
|
||||
if rightPointer {
|
||||
sw.Do("*out = (*in).DeepCopy()\n", nil)
|
||||
} else {
|
||||
sw.Do("x := (*in).DeepCopy()\n", nil)
|
||||
sw.Do("*out = &x\n", nil)
|
||||
}
|
||||
case uet.IsAssignable():
|
||||
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
||||
sw.Do("**out = **in", nil)
|
||||
case uet.Kind == types.Map, uet.Kind == types.Slice, uet.Kind == types.Pointer:
|
||||
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
||||
sw.Do("if **in != nil {\n", nil)
|
||||
sw.Do("in, out := *in, *out\n", nil)
|
||||
g.generateFor(uet, sw)
|
||||
sw.Do("}\n", nil)
|
||||
case uet.Kind == types.Struct:
|
||||
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
||||
sw.Do("(*in).DeepCopyInto(*out)\n", nil)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
|
||||
}
|
||||
}
|
828
vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
generated
vendored
Normal file
828
vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
generated
vendored
Normal file
@@ -0,0 +1,828 @@
|
||||
/*
|
||||
Copyright 2016 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 generators
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// CustomArgs is used tby the go2idl framework to pass args specific to this
|
||||
// generator.
|
||||
type CustomArgs struct {
|
||||
ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions.
|
||||
}
|
||||
|
||||
// These are the comment tags that carry parameters for defaulter generation.
|
||||
const tagName = "k8s:defaulter-gen"
|
||||
const intputTagName = "k8s:defaulter-gen-input"
|
||||
|
||||
func extractTag(comments []string) []string {
|
||||
return types.ExtractCommentTags("+", comments)[tagName]
|
||||
}
|
||||
|
||||
func extractInputTag(comments []string) []string {
|
||||
return types.ExtractCommentTags("+", comments)[intputTagName]
|
||||
}
|
||||
|
||||
func checkTag(comments []string, require ...string) bool {
|
||||
values := types.ExtractCommentTags("+", comments)[tagName]
|
||||
if len(require) == 0 {
|
||||
return len(values) == 1 && values[0] == ""
|
||||
}
|
||||
return reflect.DeepEqual(values, require)
|
||||
}
|
||||
|
||||
func defaultFnNamer() *namer.NameStrategy {
|
||||
return &namer.NameStrategy{
|
||||
Prefix: "SetDefaults_",
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return pre + strings.Join(in, "_") + post
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func objectDefaultFnNamer() *namer.NameStrategy {
|
||||
return &namer.NameStrategy{
|
||||
Prefix: "SetObjectDefaults_",
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return pre + strings.Join(in, "_") + post
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": namer.NewPublicNamer(1),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
"defaultfn": defaultFnNamer(),
|
||||
"objectdefaultfn": objectDefaultFnNamer(),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "public"
|
||||
}
|
||||
|
||||
// defaults holds the declared defaulting functions for a given type (all defaulting functions
|
||||
// are expected to be func(1))
|
||||
type defaults struct {
|
||||
// object is the defaulter function for a top level type (typically one with TypeMeta) that
|
||||
// invokes all child defaulters. May be nil if the object defaulter has not yet been generated.
|
||||
object *types.Type
|
||||
// base is a defaulter function defined for a type SetDefaults_Pod which does not invoke all
|
||||
// child defaults - the base defaulter alone is insufficient to default a type
|
||||
base *types.Type
|
||||
// additional is zero or more defaulter functions of the form SetDefaults_Pod_XXXX that can be
|
||||
// included in the Object defaulter.
|
||||
additional []*types.Type
|
||||
}
|
||||
|
||||
// All of the types in conversions map are of type "DeclarationOf" with
|
||||
// the underlying type being "Func".
|
||||
type defaulterFuncMap map[*types.Type]defaults
|
||||
|
||||
// Returns all manually-defined defaulting functions in the package.
|
||||
func getManualDefaultingFunctions(context *generator.Context, pkg *types.Package, manualMap defaulterFuncMap) {
|
||||
buffer := &bytes.Buffer{}
|
||||
sw := generator.NewSnippetWriter(buffer, context, "$", "$")
|
||||
|
||||
for _, f := range pkg.Functions {
|
||||
if f.Underlying == nil || f.Underlying.Kind != types.Func {
|
||||
klog.Errorf("Malformed function: %#v", f)
|
||||
continue
|
||||
}
|
||||
if f.Underlying.Signature == nil {
|
||||
klog.Errorf("Function without signature: %#v", f)
|
||||
continue
|
||||
}
|
||||
signature := f.Underlying.Signature
|
||||
// Check whether the function is defaulting function.
|
||||
// Note that all of them have signature:
|
||||
// object: func SetObjectDefaults_inType(*inType)
|
||||
// base: func SetDefaults_inType(*inType)
|
||||
// additional: func SetDefaults_inType_Qualifier(*inType)
|
||||
if signature.Receiver != nil {
|
||||
continue
|
||||
}
|
||||
if len(signature.Parameters) != 1 {
|
||||
continue
|
||||
}
|
||||
if len(signature.Results) != 0 {
|
||||
continue
|
||||
}
|
||||
inType := signature.Parameters[0]
|
||||
if inType.Kind != types.Pointer {
|
||||
continue
|
||||
}
|
||||
// Check if this is the primary defaulter.
|
||||
args := defaultingArgsFromType(inType.Elem)
|
||||
sw.Do("$.inType|defaultfn$", args)
|
||||
switch {
|
||||
case f.Name.Name == buffer.String():
|
||||
key := inType.Elem
|
||||
// We might scan the same package twice, and that's OK.
|
||||
v, ok := manualMap[key]
|
||||
if ok && v.base != nil && v.base.Name.Package != pkg.Path {
|
||||
panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key))
|
||||
}
|
||||
v.base = f
|
||||
manualMap[key] = v
|
||||
klog.V(6).Infof("found base defaulter function for %s from %s", key.Name, f.Name)
|
||||
// Is one of the additional defaulters - a top level defaulter on a type that is
|
||||
// also invoked.
|
||||
case strings.HasPrefix(f.Name.Name, buffer.String()+"_"):
|
||||
key := inType.Elem
|
||||
v, ok := manualMap[key]
|
||||
if ok {
|
||||
exists := false
|
||||
for _, existing := range v.additional {
|
||||
if existing.Name == f.Name {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
}
|
||||
v.additional = append(v.additional, f)
|
||||
manualMap[key] = v
|
||||
klog.V(6).Infof("found additional defaulter function for %s from %s", key.Name, f.Name)
|
||||
}
|
||||
buffer.Reset()
|
||||
sw.Do("$.inType|objectdefaultfn$", args)
|
||||
if f.Name.Name == buffer.String() {
|
||||
key := inType.Elem
|
||||
// We might scan the same package twice, and that's OK.
|
||||
v, ok := manualMap[key]
|
||||
if ok && v.base != nil && v.base.Name.Package != pkg.Path {
|
||||
panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key))
|
||||
}
|
||||
v.object = f
|
||||
manualMap[key] = v
|
||||
klog.V(6).Infof("found object defaulter function for %s from %s", key.Name, f.Name)
|
||||
}
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
|
||||
packages := generator.Packages{}
|
||||
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
||||
|
||||
// Accumulate pre-existing default functions.
|
||||
// TODO: This is too ad-hoc. We need a better way.
|
||||
existingDefaulters := defaulterFuncMap{}
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
sw := generator.NewSnippetWriter(buffer, context, "$", "$")
|
||||
|
||||
// We are generating defaults only for packages that are explicitly
|
||||
// passed as InputDir.
|
||||
for _, i := range context.Inputs {
|
||||
klog.V(5).Infof("considering pkg %q", i)
|
||||
pkg := context.Universe[i]
|
||||
if pkg == nil {
|
||||
// If the input had no Go files, for example.
|
||||
continue
|
||||
}
|
||||
// typesPkg is where the types that needs defaulter are defined.
|
||||
// Sometimes it is different from pkg. For example, kubernetes core/v1
|
||||
// types are defined in vendor/k8s.io/api/core/v1, while pkg is at
|
||||
// pkg/api/v1.
|
||||
typesPkg := pkg
|
||||
|
||||
// Add defaulting functions.
|
||||
getManualDefaultingFunctions(context, pkg, existingDefaulters)
|
||||
|
||||
var peerPkgs []string
|
||||
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
|
||||
for _, pkg := range customArgs.ExtraPeerDirs {
|
||||
if i := strings.Index(pkg, "/vendor/"); i != -1 {
|
||||
pkg = pkg[i+len("/vendor/"):]
|
||||
}
|
||||
peerPkgs = append(peerPkgs, pkg)
|
||||
}
|
||||
}
|
||||
// Make sure our peer-packages are added and fully parsed.
|
||||
for _, pp := range peerPkgs {
|
||||
context.AddDir(pp)
|
||||
getManualDefaultingFunctions(context, context.Universe[pp], existingDefaulters)
|
||||
}
|
||||
|
||||
typesWith := extractTag(pkg.Comments)
|
||||
shouldCreateObjectDefaulterFn := func(t *types.Type) bool {
|
||||
if defaults, ok := existingDefaulters[t]; ok && defaults.object != nil {
|
||||
// A default generator is defined
|
||||
klog.V(5).Infof(" an object defaulter already exists as %s", defaults.base.Name)
|
||||
return false
|
||||
}
|
||||
// opt-out
|
||||
if checkTag(t.SecondClosestCommentLines, "false") {
|
||||
return false
|
||||
}
|
||||
// opt-in
|
||||
if checkTag(t.SecondClosestCommentLines, "true") {
|
||||
return true
|
||||
}
|
||||
// For every k8s:defaulter-gen tag at the package level, interpret the value as a
|
||||
// field name (like TypeMeta, ListMeta, ObjectMeta) and trigger defaulter generation
|
||||
// for any type with any of the matching field names. Provides a more useful package
|
||||
// level defaulting than global (because we only need defaulters on a subset of objects -
|
||||
// usually those with TypeMeta).
|
||||
if t.Kind == types.Struct && len(typesWith) > 0 {
|
||||
for _, field := range t.Members {
|
||||
for _, s := range typesWith {
|
||||
if field.Name == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// if the types are not in the same package where the defaulter functions to be generated
|
||||
inputTags := extractInputTag(pkg.Comments)
|
||||
if len(inputTags) > 1 {
|
||||
panic(fmt.Sprintf("there could only be one input tag, got %#v", inputTags))
|
||||
}
|
||||
if len(inputTags) == 1 {
|
||||
var err error
|
||||
typesPkg, err = context.AddDirectory(filepath.Join(pkg.Path, inputTags[0]))
|
||||
if err != nil {
|
||||
klog.Fatalf("cannot import package %s", inputTags[0])
|
||||
}
|
||||
// update context.Order to the latest context.Universe
|
||||
orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)}
|
||||
context.Order = orderer.OrderUniverse(context.Universe)
|
||||
}
|
||||
|
||||
newDefaulters := defaulterFuncMap{}
|
||||
for _, t := range typesPkg.Types {
|
||||
if !shouldCreateObjectDefaulterFn(t) {
|
||||
continue
|
||||
}
|
||||
if namer.IsPrivateGoName(t.Name.Name) {
|
||||
// We won't be able to convert to a private type.
|
||||
klog.V(5).Infof(" found a type %v, but it is a private name", t)
|
||||
continue
|
||||
}
|
||||
|
||||
// create a synthetic type we can use during generation
|
||||
newDefaulters[t] = defaults{}
|
||||
}
|
||||
|
||||
// only generate defaulters for objects that actually have defined defaulters
|
||||
// prevents empty defaulters from being registered
|
||||
for {
|
||||
promoted := 0
|
||||
for t, d := range newDefaulters {
|
||||
if d.object != nil {
|
||||
continue
|
||||
}
|
||||
if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil {
|
||||
args := defaultingArgsFromType(t)
|
||||
sw.Do("$.inType|objectdefaultfn$", args)
|
||||
newDefaulters[t] = defaults{
|
||||
object: &types.Type{
|
||||
Name: types.Name{
|
||||
Package: pkg.Path,
|
||||
Name: buffer.String(),
|
||||
},
|
||||
Kind: types.Func,
|
||||
},
|
||||
}
|
||||
buffer.Reset()
|
||||
promoted++
|
||||
}
|
||||
}
|
||||
if promoted != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// prune any types that were not used
|
||||
for t, d := range newDefaulters {
|
||||
if d.object == nil {
|
||||
klog.V(6).Infof("did not generate defaulter for %s because no child defaulters were registered", t.Name)
|
||||
delete(newDefaulters, t)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if len(newDefaulters) == 0 {
|
||||
klog.V(5).Infof("no defaulters in package %s", pkg.Name)
|
||||
}
|
||||
|
||||
path := pkg.Path
|
||||
// if the source path is within a /vendor/ directory (for example,
|
||||
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
|
||||
// generation to output to the proper relative path (under vendor).
|
||||
// Otherwise, the generator will create the file in the wrong location
|
||||
// in the output directory.
|
||||
// TODO: build a more fundamental concept in gengo for dealing with modifications
|
||||
// to vendored packages.
|
||||
if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
|
||||
expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
|
||||
if strings.Contains(expandedPath, "/vendor/") {
|
||||
path = expandedPath
|
||||
}
|
||||
}
|
||||
|
||||
packages = append(packages,
|
||||
&generator.DefaultPackage{
|
||||
PackageName: filepath.Base(pkg.Path),
|
||||
PackagePath: path,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
NewGenDefaulter(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, existingDefaulters, newDefaulters, peerPkgs),
|
||||
}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
return t.Name.Package == typesPkg.Path
|
||||
},
|
||||
})
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
// callTreeForType contains fields necessary to build a tree for types.
|
||||
type callTreeForType struct {
|
||||
existingDefaulters defaulterFuncMap
|
||||
newDefaulters defaulterFuncMap
|
||||
currentlyBuildingTypes map[*types.Type]bool
|
||||
}
|
||||
|
||||
func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType {
|
||||
return &callTreeForType{
|
||||
existingDefaulters: existingDefaulters,
|
||||
newDefaulters: newDefaulters,
|
||||
currentlyBuildingTypes: make(map[*types.Type]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem,
|
||||
// slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree
|
||||
// can be used to generate a Go function that invokes each nested function on the appropriate type. The return
|
||||
// value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be
|
||||
// invoked on structs today). When root is true this function will not use a newDefaulter. existingDefaulters should
|
||||
// contain all defaulting functions by type defined in code - newDefaulters should contain all object defaulters
|
||||
// that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil,
|
||||
// this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for
|
||||
// list types that call empty defaulters.
|
||||
func (c *callTreeForType) build(t *types.Type, root bool) *callNode {
|
||||
parent := &callNode{}
|
||||
|
||||
if root {
|
||||
// the root node is always a pointer
|
||||
parent.elem = true
|
||||
}
|
||||
|
||||
defaults, _ := c.existingDefaulters[t]
|
||||
newDefaults, generated := c.newDefaulters[t]
|
||||
switch {
|
||||
case !root && generated && newDefaults.object != nil:
|
||||
parent.call = append(parent.call, newDefaults.object)
|
||||
// if we will be generating the defaulter, it by definition is a covering
|
||||
// defaulter, so we halt recursion
|
||||
klog.V(6).Infof("the defaulter %s will be generated as an object defaulter", t.Name)
|
||||
return parent
|
||||
|
||||
case defaults.object != nil:
|
||||
// object defaulters are always covering
|
||||
parent.call = append(parent.call, defaults.object)
|
||||
return parent
|
||||
|
||||
case defaults.base != nil:
|
||||
parent.call = append(parent.call, defaults.base)
|
||||
// if the base function indicates it "covers" (it already includes defaulters)
|
||||
// we can halt recursion
|
||||
if checkTag(defaults.base.CommentLines, "covers") {
|
||||
klog.V(6).Infof("the defaulter %s indicates it covers all sub generators", t.Name)
|
||||
return parent
|
||||
}
|
||||
}
|
||||
|
||||
// base has been added already, now add any additional defaulters defined for this object
|
||||
parent.call = append(parent.call, defaults.additional...)
|
||||
|
||||
// if the type already exists, don't build the tree for it and don't generate anything.
|
||||
// This is used to avoid recursion for nested recursive types.
|
||||
if c.currentlyBuildingTypes[t] {
|
||||
return nil
|
||||
}
|
||||
// if type doesn't exist, mark it as existing
|
||||
c.currentlyBuildingTypes[t] = true
|
||||
|
||||
defer func() {
|
||||
// The type will now acts as a parent, not a nested recursive type.
|
||||
// We can now build the tree for it safely.
|
||||
c.currentlyBuildingTypes[t] = false
|
||||
}()
|
||||
|
||||
switch t.Kind {
|
||||
case types.Pointer:
|
||||
if child := c.build(t.Elem, false); child != nil {
|
||||
child.elem = true
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
case types.Slice, types.Array:
|
||||
if child := c.build(t.Elem, false); child != nil {
|
||||
child.index = true
|
||||
if t.Elem.Kind == types.Pointer {
|
||||
child.elem = true
|
||||
}
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
case types.Map:
|
||||
if child := c.build(t.Elem, false); child != nil {
|
||||
child.key = true
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
case types.Struct:
|
||||
for _, field := range t.Members {
|
||||
name := field.Name
|
||||
if len(name) == 0 {
|
||||
if field.Type.Kind == types.Pointer {
|
||||
name = field.Type.Elem.Name.Name
|
||||
} else {
|
||||
name = field.Type.Name.Name
|
||||
}
|
||||
}
|
||||
if child := c.build(field.Type, false); child != nil {
|
||||
child.field = name
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
}
|
||||
case types.Alias:
|
||||
if child := c.build(t.Underlying, false); child != nil {
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
}
|
||||
if len(parent.children) == 0 && len(parent.call) == 0 {
|
||||
//klog.V(6).Infof("decided type %s needs no generation", t.Name)
|
||||
return nil
|
||||
}
|
||||
return parent
|
||||
}
|
||||
|
||||
const (
|
||||
runtimePackagePath = "k8s.io/apimachinery/pkg/runtime"
|
||||
conversionPackagePath = "k8s.io/apimachinery/pkg/conversion"
|
||||
)
|
||||
|
||||
// genDefaulter produces a file with a autogenerated conversions.
|
||||
type genDefaulter struct {
|
||||
generator.DefaultGen
|
||||
typesPackage string
|
||||
outputPackage string
|
||||
peerPackages []string
|
||||
newDefaulters defaulterFuncMap
|
||||
existingDefaulters defaulterFuncMap
|
||||
imports namer.ImportTracker
|
||||
typesForInit []*types.Type
|
||||
}
|
||||
|
||||
func NewGenDefaulter(sanitizedName, typesPackage, outputPackage string, existingDefaulters, newDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator {
|
||||
return &genDefaulter{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
typesPackage: typesPackage,
|
||||
outputPackage: outputPackage,
|
||||
peerPackages: peerPkgs,
|
||||
newDefaulters: newDefaulters,
|
||||
existingDefaulters: existingDefaulters,
|
||||
imports: generator.NewImportTracker(),
|
||||
typesForInit: make([]*types.Type, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Namers(c *generator.Context) namer.NameSystems {
|
||||
// Have the raw namer for this file track what it imports.
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDefaulter) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.outputPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Filter(c *generator.Context, t *types.Type) bool {
|
||||
defaults, ok := g.newDefaulters[t]
|
||||
if !ok || defaults.object == nil {
|
||||
return false
|
||||
}
|
||||
g.typesForInit = append(g.typesForInit, t)
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Imports(c *generator.Context) (imports []string) {
|
||||
var importLines []string
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
if g.isOtherPackage(singleImport) {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Init(c *generator.Context, w io.Writer) error {
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
|
||||
scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"})
|
||||
schemePtr := &types.Type{
|
||||
Kind: types.Pointer,
|
||||
Elem: scheme,
|
||||
}
|
||||
sw.Do("// RegisterDefaults adds defaulters functions to the given scheme.\n", nil)
|
||||
sw.Do("// Public to allow building arbitrary schemes.\n", nil)
|
||||
sw.Do("// All generated defaulters are covering - they call all nested defaulters.\n", nil)
|
||||
sw.Do("func RegisterDefaults(scheme $.|raw$) error {\n", schemePtr)
|
||||
for _, t := range g.typesForInit {
|
||||
args := defaultingArgsFromType(t)
|
||||
sw.Do("scheme.AddTypeDefaultingFunc(&$.inType|raw${}, func(obj interface{}) { $.inType|objectdefaultfn$(obj.(*$.inType|raw$)) })\n", args)
|
||||
}
|
||||
sw.Do("return nil\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
if _, ok := g.newDefaulters[t]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
klog.V(5).Infof("generating for type %v", t)
|
||||
|
||||
callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true)
|
||||
if callTree == nil {
|
||||
klog.V(5).Infof(" no defaulters defined")
|
||||
return nil
|
||||
}
|
||||
i := 0
|
||||
callTree.VisitInOrder(func(ancestors []*callNode, current *callNode) {
|
||||
if len(current.call) == 0 {
|
||||
return
|
||||
}
|
||||
path := callPath(append(ancestors, current))
|
||||
klog.V(5).Infof(" %d: %s", i, path)
|
||||
i++
|
||||
})
|
||||
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
g.generateDefaulter(t, callTree, sw)
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func defaultingArgsFromType(inType *types.Type) generator.Args {
|
||||
return generator.Args{
|
||||
"inType": inType,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDefaulter) generateDefaulter(inType *types.Type, callTree *callNode, sw *generator.SnippetWriter) {
|
||||
sw.Do("func $.inType|objectdefaultfn$(in *$.inType|raw$) {\n", defaultingArgsFromType(inType))
|
||||
callTree.WriteMethod("in", 0, nil, sw)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
// callNode represents an entry in a tree of Go type accessors - the path from the root to a leaf represents
|
||||
// how in Go code an access would be performed. For example, if a defaulting function exists on a container
|
||||
// lifecycle hook, to invoke that defaulter correctly would require this Go code:
|
||||
//
|
||||
// for i := range pod.Spec.Containers {
|
||||
// o := &pod.Spec.Containers[i]
|
||||
// if o.LifecycleHook != nil {
|
||||
// SetDefaults_LifecycleHook(o.LifecycleHook)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// That would be represented by a call tree like:
|
||||
//
|
||||
// callNode
|
||||
// field: "Spec"
|
||||
// children:
|
||||
// - field: "Containers"
|
||||
// children:
|
||||
// - index: true
|
||||
// children:
|
||||
// - field: "LifecycleHook"
|
||||
// elem: true
|
||||
// call:
|
||||
// - SetDefaults_LifecycleHook
|
||||
//
|
||||
// which we can traverse to build that Go struct (you must call the field Spec, then Containers, then range over
|
||||
// that field, then check whether the LifecycleHook field is nil, before calling SetDefaults_LifecycleHook on
|
||||
// the pointer to that field).
|
||||
type callNode struct {
|
||||
// field is the name of the Go member to access
|
||||
field string
|
||||
// key is true if this is a map and we must range over the key and values
|
||||
key bool
|
||||
// index is true if this is a slice and we must range over the slice values
|
||||
index bool
|
||||
// elem is true if the previous elements refer to a pointer (typically just field)
|
||||
elem bool
|
||||
|
||||
// call is all of the functions that must be invoked on this particular node, in order
|
||||
call []*types.Type
|
||||
// children is the child call nodes that must also be traversed
|
||||
children []callNode
|
||||
}
|
||||
|
||||
// CallNodeVisitorFunc is a function for visiting a call tree. ancestors is the list of all parents
|
||||
// of this node to the root of the tree - will be empty at the root.
|
||||
type CallNodeVisitorFunc func(ancestors []*callNode, node *callNode)
|
||||
|
||||
func (n *callNode) VisitInOrder(fn CallNodeVisitorFunc) {
|
||||
n.visitInOrder(nil, fn)
|
||||
}
|
||||
|
||||
func (n *callNode) visitInOrder(ancestors []*callNode, fn CallNodeVisitorFunc) {
|
||||
fn(ancestors, n)
|
||||
ancestors = append(ancestors, n)
|
||||
for i := range n.children {
|
||||
n.children[i].visitInOrder(ancestors, fn)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
indexVariables = "ijklmnop"
|
||||
localVariables = "abcdefgh"
|
||||
)
|
||||
|
||||
// varsForDepth creates temporary variables guaranteed to be unique within lexical Go scopes
|
||||
// of this depth in a function. It uses canonical Go loop variables for the first 7 levels
|
||||
// and then resorts to uglier prefixes.
|
||||
func varsForDepth(depth int) (index, local string) {
|
||||
if depth > len(indexVariables) {
|
||||
index = fmt.Sprintf("i%d", depth)
|
||||
} else {
|
||||
index = indexVariables[depth : depth+1]
|
||||
}
|
||||
if depth > len(localVariables) {
|
||||
local = fmt.Sprintf("local%d", depth)
|
||||
} else {
|
||||
local = localVariables[depth : depth+1]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// writeCalls generates a list of function calls based on the calls field for the provided variable
|
||||
// name and pointer.
|
||||
func (n *callNode) writeCalls(varName string, isVarPointer bool, sw *generator.SnippetWriter) {
|
||||
accessor := varName
|
||||
if !isVarPointer {
|
||||
accessor = "&" + accessor
|
||||
}
|
||||
for _, fn := range n.call {
|
||||
sw.Do("$.fn|raw$($.var$)\n", generator.Args{
|
||||
"fn": fn,
|
||||
"var": accessor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WriteMethod performs an in-order traversal of the calltree, generating loops and if blocks as necessary
|
||||
// to correctly turn the call tree into a method body that invokes all calls on all child nodes of the call tree.
|
||||
// Depth is used to generate local variables at the proper depth.
|
||||
func (n *callNode) WriteMethod(varName string, depth int, ancestors []*callNode, sw *generator.SnippetWriter) {
|
||||
// if len(n.call) > 0 {
|
||||
// sw.Do(fmt.Sprintf("// %s\n", callPath(append(ancestors, n)).String()), nil)
|
||||
// }
|
||||
|
||||
if len(n.field) > 0 {
|
||||
varName = varName + "." + n.field
|
||||
}
|
||||
|
||||
index, local := varsForDepth(depth)
|
||||
vars := generator.Args{
|
||||
"index": index,
|
||||
"local": local,
|
||||
"var": varName,
|
||||
}
|
||||
|
||||
isPointer := n.elem && !n.index
|
||||
if isPointer && len(ancestors) > 0 {
|
||||
sw.Do("if $.var$ != nil {\n", vars)
|
||||
}
|
||||
|
||||
switch {
|
||||
case n.index:
|
||||
sw.Do("for $.index$ := range $.var$ {\n", vars)
|
||||
if n.elem {
|
||||
sw.Do("$.local$ := $.var$[$.index$]\n", vars)
|
||||
} else {
|
||||
sw.Do("$.local$ := &$.var$[$.index$]\n", vars)
|
||||
}
|
||||
|
||||
n.writeCalls(local, true, sw)
|
||||
for i := range n.children {
|
||||
n.children[i].WriteMethod(local, depth+1, append(ancestors, n), sw)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
case n.key:
|
||||
default:
|
||||
n.writeCalls(varName, isPointer, sw)
|
||||
for i := range n.children {
|
||||
n.children[i].WriteMethod(varName, depth, append(ancestors, n), sw)
|
||||
}
|
||||
}
|
||||
|
||||
if isPointer && len(ancestors) > 0 {
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
type callPath []*callNode
|
||||
|
||||
// String prints a representation of a callPath that roughly approximates what a Go accessor
|
||||
// would look like. Used for debugging only.
|
||||
func (path callPath) String() string {
|
||||
if len(path) == 0 {
|
||||
return "<none>"
|
||||
}
|
||||
var parts []string
|
||||
for _, p := range path {
|
||||
last := len(parts) - 1
|
||||
switch {
|
||||
case p.elem:
|
||||
if len(parts) > 0 {
|
||||
parts[last] = "*" + parts[last]
|
||||
} else {
|
||||
parts = append(parts, "*")
|
||||
}
|
||||
case p.index:
|
||||
if len(parts) > 0 {
|
||||
parts[last] = parts[last] + "[i]"
|
||||
} else {
|
||||
parts = append(parts, "[i]")
|
||||
}
|
||||
case p.key:
|
||||
if len(parts) > 0 {
|
||||
parts[last] = parts[last] + "[key]"
|
||||
} else {
|
||||
parts = append(parts, "[key]")
|
||||
}
|
||||
default:
|
||||
if len(p.field) > 0 {
|
||||
parts = append(parts, p.field)
|
||||
} else {
|
||||
parts = append(parts, "<root>")
|
||||
}
|
||||
}
|
||||
}
|
||||
var calls []string
|
||||
for _, fn := range path[len(path)-1].call {
|
||||
calls = append(calls, fn.Name.String())
|
||||
}
|
||||
if len(calls) == 0 {
|
||||
calls = append(calls, "<none>")
|
||||
}
|
||||
|
||||
return strings.Join(parts, ".") + " calls " + strings.Join(calls, ", ")
|
||||
}
|
290
vendor/k8s.io/gengo/examples/import-boss/generators/import_restrict.go
generated
vendored
Normal file
290
vendor/k8s.io/gengo/examples/import-boss/generators/import_restrict.go
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
Copyright 2016 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 generators has the generators for the import-boss utility.
|
||||
package generators
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const (
|
||||
importBossFileType = "import-boss"
|
||||
)
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "raw"
|
||||
}
|
||||
|
||||
// Packages makes the import-boss package definition.
|
||||
func Packages(c *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
pkgs := generator.Packages{}
|
||||
c.FileTypes = map[string]generator.FileType{
|
||||
importBossFileType: importRuleFile{},
|
||||
}
|
||||
|
||||
for _, p := range c.Universe {
|
||||
if !arguments.InputIncludes(p) {
|
||||
// Don't run on e.g. third party dependencies.
|
||||
continue
|
||||
}
|
||||
savedPackage := p
|
||||
pkgs = append(pkgs, &generator.DefaultPackage{
|
||||
PackageName: p.Name,
|
||||
PackagePath: p.Path,
|
||||
// GeneratorFunc returns a list of generators. Each generator makes a
|
||||
// single file.
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{&importRules{
|
||||
myPackage: savedPackage,
|
||||
}}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
return false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// A single import restriction rule.
|
||||
type Rule struct {
|
||||
// All import paths that match this regexp...
|
||||
SelectorRegexp string
|
||||
// ... must have one of these prefixes ...
|
||||
AllowedPrefixes []string
|
||||
// ... and must not have one of these prefixes.
|
||||
ForbiddenPrefixes []string
|
||||
}
|
||||
|
||||
type fileFormat struct {
|
||||
CurrentImports []string
|
||||
|
||||
Rules []Rule
|
||||
}
|
||||
|
||||
func readFile(path string) (*fileFormat, error) {
|
||||
currentBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't read %v: %v", path, err)
|
||||
}
|
||||
|
||||
var current fileFormat
|
||||
err = json.Unmarshal(currentBytes, ¤t)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't unmarshal %v: %v", path, err)
|
||||
}
|
||||
return ¤t, nil
|
||||
}
|
||||
|
||||
func writeFile(path string, ff *fileFormat) error {
|
||||
raw, err := json.MarshalIndent(ff, "", "\t")
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't format data for file %v.\n%#v", path, ff)
|
||||
}
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't open %v for writing: %v", path, err)
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.Write(raw)
|
||||
return err
|
||||
}
|
||||
|
||||
// This does the actual checking, since it knows the literal destination file.
|
||||
type importRuleFile struct{}
|
||||
|
||||
func (importRuleFile) AssembleFile(f *generator.File, path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: make a flag to enable this, or expose this information in some other way.
|
||||
func (importRuleFile) listEntireImportTree(f *generator.File, path string) error {
|
||||
// If the file exists, populate its current imports. This is mostly to help
|
||||
// humans figure out what they need to fix.
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
// Ignore packages which haven't opted in by adding an .import-restrictions file.
|
||||
return nil
|
||||
}
|
||||
|
||||
current, err := readFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
current.CurrentImports = []string{}
|
||||
for v := range f.Imports {
|
||||
current.CurrentImports = append(current.CurrentImports, v)
|
||||
}
|
||||
sort.Strings(current.CurrentImports)
|
||||
|
||||
return writeFile(path, current)
|
||||
}
|
||||
|
||||
// removeLastDir removes the last directory, but leaves the file name
|
||||
// unchanged. It returns the new path and the removed directory. So:
|
||||
// "a/b/c/file" -> ("a/b/file", "c")
|
||||
func removeLastDir(path string) (newPath, removedDir string) {
|
||||
dir, file := filepath.Split(path)
|
||||
dir = strings.TrimSuffix(dir, string(filepath.Separator))
|
||||
return filepath.Join(filepath.Dir(dir), file), filepath.Base(dir)
|
||||
}
|
||||
|
||||
// Keep going up a directory until we find an .import-restrictions file.
|
||||
func recursiveRead(path string) (*fileFormat, string, error) {
|
||||
for {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
ff, err := readFile(path)
|
||||
return ff, path, err
|
||||
}
|
||||
|
||||
nextPath, removedDir := removeLastDir(path)
|
||||
if nextPath == path || removedDir == "src" {
|
||||
break
|
||||
}
|
||||
path = nextPath
|
||||
}
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
func (importRuleFile) VerifyFile(f *generator.File, path string) error {
|
||||
rules, actualPath, err := recursiveRead(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding rules file: %v", err)
|
||||
}
|
||||
|
||||
if rules == nil {
|
||||
// No restrictions on this directory.
|
||||
return nil
|
||||
}
|
||||
|
||||
forbiddenImports := map[string]string{}
|
||||
allowedMismatchedImports := []string{}
|
||||
for _, r := range rules.Rules {
|
||||
re, err := regexp.Compile(r.SelectorRegexp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("regexp `%s` in file %q doesn't compile: %v", r.SelectorRegexp, actualPath, err)
|
||||
}
|
||||
for v := range f.Imports {
|
||||
klog.V(4).Infof("Checking %v matches %v: %v\n", r.SelectorRegexp, v, re.MatchString(v))
|
||||
if !re.MatchString(v) {
|
||||
continue
|
||||
}
|
||||
for _, forbidden := range r.ForbiddenPrefixes {
|
||||
klog.V(4).Infof("Checking %v against %v\n", v, forbidden)
|
||||
if strings.HasPrefix(v, forbidden) {
|
||||
forbiddenImports[v] = forbidden
|
||||
}
|
||||
}
|
||||
found := false
|
||||
for _, allowed := range r.AllowedPrefixes {
|
||||
klog.V(4).Infof("Checking %v against %v\n", v, allowed)
|
||||
if strings.HasPrefix(v, allowed) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
allowedMismatchedImports = append(allowedMismatchedImports, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(forbiddenImports) > 0 || len(allowedMismatchedImports) > 0 {
|
||||
var errorBuilder strings.Builder
|
||||
for i, f := range forbiddenImports {
|
||||
fmt.Fprintf(&errorBuilder, "import %v has forbidden prefix %v\n", i, f)
|
||||
}
|
||||
if len(allowedMismatchedImports) > 0 {
|
||||
sort.Sort(sort.StringSlice(allowedMismatchedImports))
|
||||
fmt.Fprintf(&errorBuilder, "the following imports did not match any allowed prefix:\n")
|
||||
for _, i := range allowedMismatchedImports {
|
||||
fmt.Fprintf(&errorBuilder, " %v\n", i)
|
||||
}
|
||||
}
|
||||
return errors.New(errorBuilder.String())
|
||||
}
|
||||
if len(rules.Rules) > 0 {
|
||||
klog.V(2).Infof("%v passes rules found in %v\n", path, actualPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// importRules produces a file with a set for a single type.
|
||||
type importRules struct {
|
||||
myPackage *types.Package
|
||||
imports namer.ImportTracker
|
||||
}
|
||||
|
||||
var (
|
||||
_ = generator.Generator(&importRules{})
|
||||
_ = generator.FileType(importRuleFile{})
|
||||
)
|
||||
|
||||
func (r *importRules) Name() string { return "import rules" }
|
||||
func (r *importRules) Filter(*generator.Context, *types.Type) bool { return false }
|
||||
func (r *importRules) Namers(*generator.Context) namer.NameSystems { return nil }
|
||||
func (r *importRules) PackageVars(*generator.Context) []string { return []string{} }
|
||||
func (r *importRules) PackageConsts(*generator.Context) []string { return []string{} }
|
||||
func (r *importRules) GenerateType(*generator.Context, *types.Type, io.Writer) error { return nil }
|
||||
func (r *importRules) Filename() string { return ".import-restrictions" }
|
||||
func (r *importRules) FileType() string { return importBossFileType }
|
||||
func (r *importRules) Init(c *generator.Context, w io.Writer) error { return nil }
|
||||
func (r *importRules) Finalize(*generator.Context, io.Writer) error { return nil }
|
||||
|
||||
func dfsImports(dest *[]string, seen map[string]bool, p *types.Package) {
|
||||
for _, p2 := range p.Imports {
|
||||
if seen[p2.Path] {
|
||||
continue
|
||||
}
|
||||
seen[p2.Path] = true
|
||||
dfsImports(dest, seen, p2)
|
||||
*dest = append(*dest, p2.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importRules) Imports(*generator.Context) []string {
|
||||
all := []string{}
|
||||
dfsImports(&all, map[string]bool{}, r.myPackage)
|
||||
return all
|
||||
}
|
362
vendor/k8s.io/gengo/examples/set-gen/generators/sets.go
generated
vendored
Normal file
362
vendor/k8s.io/gengo/examples/set-gen/generators/sets.go
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
Copyright 2015 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 generators has the generators for the set-gen utility.
|
||||
package generators
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": namer.NewPublicNamer(0),
|
||||
"private": namer.NewPrivateNamer(0),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "public"
|
||||
}
|
||||
|
||||
// Packages makes the sets package definition.
|
||||
func Packages(_ *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
|
||||
return generator.Packages{&generator.DefaultPackage{
|
||||
PackageName: "sets",
|
||||
PackagePath: arguments.OutputPackagePath,
|
||||
HeaderText: boilerplate,
|
||||
PackageDocumentation: []byte(
|
||||
`// Package sets has auto-generated set types.
|
||||
`),
|
||||
// GeneratorFunc returns a list of generators. Each generator makes a
|
||||
// single file.
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
generators = []generator.Generator{
|
||||
// Always generate a "doc.go" file.
|
||||
generator.DefaultGen{OptionalName: "doc"},
|
||||
// Make a separate file for the Empty type, since it's shared by every type.
|
||||
generator.DefaultGen{
|
||||
OptionalName: "empty",
|
||||
OptionalBody: []byte(emptyTypeDecl),
|
||||
},
|
||||
}
|
||||
// Since we want a file per type that we generate a set for, we
|
||||
// have to provide a function for this.
|
||||
for _, t := range c.Order {
|
||||
generators = append(generators, &genSet{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
// Use the privatized version of the
|
||||
// type name as the file name.
|
||||
//
|
||||
// TODO: make a namer that converts
|
||||
// camelCase to '-' separation for file
|
||||
// names?
|
||||
OptionalName: c.Namers["private"].Name(t),
|
||||
},
|
||||
outputPackage: arguments.OutputPackagePath,
|
||||
typeToMatch: t,
|
||||
imports: generator.NewImportTracker(),
|
||||
})
|
||||
}
|
||||
return generators
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
// It would be reasonable to filter by the type's package here.
|
||||
// It might be necessary if your input directory has a big
|
||||
// import graph.
|
||||
switch t.Kind {
|
||||
case types.Map, types.Slice, types.Pointer:
|
||||
// These types can't be keys in a map.
|
||||
return false
|
||||
case types.Builtin:
|
||||
return true
|
||||
case types.Struct:
|
||||
// Only some structs can be keys in a map. This is triggered by the line
|
||||
// // +genset
|
||||
// or
|
||||
// // +genset=true
|
||||
return extractBoolTagOrDie("genset", t.CommentLines) == true
|
||||
}
|
||||
return false
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// genSet produces a file with a set for a single type.
|
||||
type genSet struct {
|
||||
generator.DefaultGen
|
||||
outputPackage string
|
||||
typeToMatch *types.Type
|
||||
imports namer.ImportTracker
|
||||
}
|
||||
|
||||
// Filter ignores all but one type because we're making a single file per type.
|
||||
func (g *genSet) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch }
|
||||
|
||||
func (g *genSet) Namers(c *generator.Context) namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genSet) Imports(c *generator.Context) (imports []string) {
|
||||
return append(g.imports.ImportLines(), "reflect", "sort")
|
||||
}
|
||||
|
||||
// args constructs arguments for templates. Usage:
|
||||
// g.args(t, "key1", value1, "key2", value2, ...)
|
||||
//
|
||||
// 't' is loaded with the key 'type'.
|
||||
//
|
||||
// We could use t directly as the argument, but doing it this way makes it easy
|
||||
// to mix in additional parameters. This feature is not used in this set
|
||||
// generator, but is present as an example.
|
||||
func (g *genSet) args(t *types.Type, kv ...interface{}) interface{} {
|
||||
m := map[interface{}]interface{}{"type": t}
|
||||
for i := 0; i < len(kv)/2; i++ {
|
||||
m[kv[i*2]] = kv[i*2+1]
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// GenerateType makes the body of a file implementing a set for type t.
|
||||
func (g *genSet) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
sw.Do(setCode, g.args(t))
|
||||
sw.Do("func less$.type|public$(lhs, rhs $.type|raw$) bool {\n", g.args(t))
|
||||
g.lessBody(sw, t)
|
||||
sw.Do("}\n", g.args(t))
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func (g *genSet) lessBody(sw *generator.SnippetWriter, t *types.Type) {
|
||||
// TODO: make this recursive, handle pointers and multiple nested structs...
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
for _, m := range types.FlattenMembers(t.Members) {
|
||||
sw.Do("if lhs.$.Name$ < rhs.$.Name$ { return true }\n", m)
|
||||
sw.Do("if lhs.$.Name$ > rhs.$.Name$ { return false }\n", m)
|
||||
}
|
||||
sw.Do("return false\n", nil)
|
||||
default:
|
||||
sw.Do("return lhs < rhs\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
// written to the "empty.go" file.
|
||||
var emptyTypeDecl = `
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
||||
`
|
||||
|
||||
// Written for every type. If you've never used text/template before:
|
||||
// $.type$ refers to the source type; |public means to
|
||||
// call the function giving the public name, |raw the raw type name.
|
||||
var setCode = `// sets.$.type|public$ is a set of $.type|raw$s, implemented via map[$.type|raw$]struct{} for minimal memory consumption.
|
||||
type $.type|public$ map[$.type|raw$]Empty
|
||||
|
||||
// New$.type|public$ creates a $.type|public$ from a list of values.
|
||||
func New$.type|public$(items ...$.type|raw$) $.type|public$ {
|
||||
ss := $.type|public${}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// $.type|public$KeySet creates a $.type|public$ from a keys of a map[$.type|raw$](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func $.type|public$KeySet(theMap interface{}) $.type|public$ {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := $.type|public${}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().($.type|raw$))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s $.type|public$) Insert(items ...$.type|raw$) $.type|public$ {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s $.type|public$) Delete(items ...$.type|raw$) $.type|public$ {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s $.type|public$) Has(item $.type|raw$) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s $.type|public$) HasAll(items ...$.type|raw$) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s $.type|public$) HasAny(items ...$.type|raw$) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s $.type|public$) Difference(s2 $.type|public$) $.type|public$ {
|
||||
result := New$.type|public$()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 $.type|public$) Union(s2 $.type|public$) $.type|public$ {
|
||||
result := New$.type|public$()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 $.type|public$) Intersection(s2 $.type|public$) $.type|public$ {
|
||||
var walk, other $.type|public$
|
||||
result := New$.type|public$()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 $.type|public$) IsSuperset(s2 $.type|public$) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 $.type|public$) Equal(s2 $.type|public$) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOf$.type|public$ []$.type|raw$
|
||||
|
||||
func (s sortableSliceOf$.type|public$) Len() int { return len(s) }
|
||||
func (s sortableSliceOf$.type|public$) Less(i, j int) bool { return less$.type|public$(s[i], s[j]) }
|
||||
func (s sortableSliceOf$.type|public$) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted $.type|raw$ slice.
|
||||
func (s $.type|public$) List() []$.type|raw$ {
|
||||
res := make(sortableSliceOf$.type|public$, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []$.type|raw$(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s $.type|public$) UnsortedList() []$.type|raw$ {
|
||||
res :=make([]$.type|raw$, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s $.type|public$) PopAny() ($.type|raw$, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue $.type|raw$
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s $.type|public$) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
`
|
33
vendor/k8s.io/gengo/examples/set-gen/generators/tags.go
generated
vendored
Normal file
33
vendor/k8s.io/gengo/examples/set-gen/generators/tags.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2016 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 generators
|
||||
|
||||
import (
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if
|
||||
// it exists, the value is boolean. If the tag did not exist, it returns
|
||||
// false.
|
||||
func extractBoolTagOrDie(key string, lines []string) bool {
|
||||
val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines)
|
||||
if err != nil {
|
||||
klog.Fatalf(err.Error())
|
||||
}
|
||||
return val
|
||||
}
|
205
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go
generated
vendored
Normal file
205
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.Byte is a set of bytes, implemented via map[byte]struct{} for minimal memory consumption.
|
||||
type Byte map[byte]Empty
|
||||
|
||||
// NewByte creates a Byte from a list of values.
|
||||
func NewByte(items ...byte) Byte {
|
||||
ss := Byte{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// ByteKeySet creates a Byte from a keys of a map[byte](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func ByteKeySet(theMap interface{}) Byte {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := Byte{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(byte))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s Byte) Insert(items ...byte) Byte {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Byte) Delete(items ...byte) Byte {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s Byte) Has(item byte) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s Byte) HasAll(items ...byte) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s Byte) HasAny(items ...byte) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s Byte) Difference(s2 Byte) Byte {
|
||||
result := NewByte()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Byte) Union(s2 Byte) Byte {
|
||||
result := NewByte()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 Byte) Intersection(s2 Byte) Byte {
|
||||
var walk, other Byte
|
||||
result := NewByte()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 Byte) IsSuperset(s2 Byte) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 Byte) Equal(s2 Byte) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfByte []byte
|
||||
|
||||
func (s sortableSliceOfByte) Len() int { return len(s) }
|
||||
func (s sortableSliceOfByte) Less(i, j int) bool { return lessByte(s[i], s[j]) }
|
||||
func (s sortableSliceOfByte) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted byte slice.
|
||||
func (s Byte) List() []byte {
|
||||
res := make(sortableSliceOfByte, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []byte(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s Byte) UnsortedList() []byte {
|
||||
res := make([]byte, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s Byte) PopAny() (byte, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue byte
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s Byte) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessByte(lhs, rhs byte) bool {
|
||||
return lhs < rhs
|
||||
}
|
20
vendor/k8s.io/gengo/examples/set-gen/sets/doc.go
generated
vendored
Normal file
20
vendor/k8s.io/gengo/examples/set-gen/sets/doc.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
// Package sets has auto-generated set types.
|
||||
package sets
|
23
vendor/k8s.io/gengo/examples/set-gen/sets/empty.go
generated
vendored
Normal file
23
vendor/k8s.io/gengo/examples/set-gen/sets/empty.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
205
vendor/k8s.io/gengo/examples/set-gen/sets/int.go
generated
vendored
Normal file
205
vendor/k8s.io/gengo/examples/set-gen/sets/int.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.Int is a set of ints, implemented via map[int]struct{} for minimal memory consumption.
|
||||
type Int map[int]Empty
|
||||
|
||||
// NewInt creates a Int from a list of values.
|
||||
func NewInt(items ...int) Int {
|
||||
ss := Int{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// IntKeySet creates a Int from a keys of a map[int](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func IntKeySet(theMap interface{}) Int {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := Int{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(int))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s Int) Insert(items ...int) Int {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Int) Delete(items ...int) Int {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s Int) Has(item int) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s Int) HasAll(items ...int) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s Int) HasAny(items ...int) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s Int) Difference(s2 Int) Int {
|
||||
result := NewInt()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int) Union(s2 Int) Int {
|
||||
result := NewInt()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 Int) Intersection(s2 Int) Int {
|
||||
var walk, other Int
|
||||
result := NewInt()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 Int) IsSuperset(s2 Int) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 Int) Equal(s2 Int) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfInt []int
|
||||
|
||||
func (s sortableSliceOfInt) Len() int { return len(s) }
|
||||
func (s sortableSliceOfInt) Less(i, j int) bool { return lessInt(s[i], s[j]) }
|
||||
func (s sortableSliceOfInt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted int slice.
|
||||
func (s Int) List() []int {
|
||||
res := make(sortableSliceOfInt, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []int(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s Int) UnsortedList() []int {
|
||||
res := make([]int, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s Int) PopAny() (int, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue int
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s Int) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessInt(lhs, rhs int) bool {
|
||||
return lhs < rhs
|
||||
}
|
205
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go
generated
vendored
Normal file
205
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.Int64 is a set of int64s, implemented via map[int64]struct{} for minimal memory consumption.
|
||||
type Int64 map[int64]Empty
|
||||
|
||||
// NewInt64 creates a Int64 from a list of values.
|
||||
func NewInt64(items ...int64) Int64 {
|
||||
ss := Int64{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// Int64KeySet creates a Int64 from a keys of a map[int64](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func Int64KeySet(theMap interface{}) Int64 {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := Int64{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(int64))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s Int64) Insert(items ...int64) Int64 {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Int64) Delete(items ...int64) Int64 {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s Int64) Has(item int64) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s Int64) HasAll(items ...int64) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s Int64) HasAny(items ...int64) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s Int64) Difference(s2 Int64) Int64 {
|
||||
result := NewInt64()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int64) Union(s2 Int64) Int64 {
|
||||
result := NewInt64()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 Int64) Intersection(s2 Int64) Int64 {
|
||||
var walk, other Int64
|
||||
result := NewInt64()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 Int64) IsSuperset(s2 Int64) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 Int64) Equal(s2 Int64) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfInt64 []int64
|
||||
|
||||
func (s sortableSliceOfInt64) Len() int { return len(s) }
|
||||
func (s sortableSliceOfInt64) Less(i, j int) bool { return lessInt64(s[i], s[j]) }
|
||||
func (s sortableSliceOfInt64) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted int64 slice.
|
||||
func (s Int64) List() []int64 {
|
||||
res := make(sortableSliceOfInt64, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []int64(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s Int64) UnsortedList() []int64 {
|
||||
res := make([]int64, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s Int64) PopAny() (int64, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue int64
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s Int64) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessInt64(lhs, rhs int64) bool {
|
||||
return lhs < rhs
|
||||
}
|
205
vendor/k8s.io/gengo/examples/set-gen/sets/string.go
generated
vendored
Normal file
205
vendor/k8s.io/gengo/examples/set-gen/sets/string.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||
type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := String{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func StringKeySet(theMap interface{}) String {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := String{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(string))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s String) Insert(items ...string) String {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) String {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s String) Has(item string) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s String) HasAll(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s String) HasAny(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 String) Intersection(s2 String) String {
|
||||
var walk, other String
|
||||
result := NewString()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 String) IsSuperset(s2 String) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 String) Equal(s2 String) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfString []string
|
||||
|
||||
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s String) List() []string {
|
||||
res := make(sortableSliceOfString, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []string(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s String) UnsortedList() []string {
|
||||
res := make([]string, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s String) PopAny() (string, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue string
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessString(lhs, rhs string) bool {
|
||||
return lhs < rhs
|
||||
}
|
Reference in New Issue
Block a user