Add generated file

This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
xing-yang
2018-07-12 10:55:15 -07:00
parent 36b1de0341
commit e213d1890d
17729 changed files with 5090889 additions and 0 deletions

1
vendor/k8s.io/gengo/examples/deepcopy-gen/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
deepcopy-gen

16
vendor/k8s.io/gengo/examples/deepcopy-gen/Makefile generated vendored Normal file
View File

@@ -0,0 +1,16 @@
TOOL=deepcopy-gen
test:
@if ! git diff --quiet HEAD; then \
echo "FAIL: git client is not clean"; \
false; \
fi
@go build -o /tmp/$(TOOL)
@PKGS=$$(go list ./output_tests/... | paste -sd' ' -); \
/tmp/$(TOOL) --logtostderr --v=4 -i $$(echo $$PKGS | sed 's/ /,/g') -O zz_generated
@if ! git diff --quiet HEAD; then \
echo "FAIL: output files changed"; \
git diff; \
false; \
fi

View File

@@ -0,0 +1,905 @@
/*
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"
"github.com/golang/glog"
)
// 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 (
tagName = "k8s:deepcopy-gen"
interfacesTagName = tagName + ":interfaces"
interfacesNonPointerTagName = tagName + ":nonpointer-interfaces" // attach the DeepCopy<Interface> methods to the
)
// Known values for the comment tag.
const tagValuePackage = "package"
// tagValue holds parameters from a tagName tag.
type tagValue struct {
value string
register bool
}
func extractTag(comments []string) *tagValue {
tagVals := types.ExtractCommentTags("+", comments)[tagName]
if tagVals == nil {
// No match for the tag.
return nil
}
// If there are multiple values, abort.
if len(tagVals) > 1 {
glog.Fatalf("Found %d %s tags: %q", len(tagVals), tagName, tagVals)
}
// If we got here we are returning something.
tag := &tagValue{}
// 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:
glog.Fatalf("Unsupported %s param: %q", tagName, 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 {
glog.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 {
glog.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 := extractTag(pkg.Comments)
ptagValue := ""
ptagRegister := false
if ptag != nil {
ptagValue = ptag.value
if ptagValue != tagValuePackage {
glog.Fatalf("Package %v: unsupported %s value: %q", i, tagName, ptagValue)
}
ptagRegister = ptag.register
glog.V(5).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
} else {
glog.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 {
glog.V(5).Infof(" considering type %q", t.Name.String())
ttag := extractTag(t.CommentLines)
if ttag != nil && ttag.value == "true" {
glog.V(5).Infof(" tag=true")
if !copyableType(t) {
glog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
}
pkgNeedsGeneration = true
break
}
}
}
if pkgNeedsGeneration {
glog.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 := extractTag(t.CommentLines)
if ttag != nil && ttag.value == "true" {
enabled = true
}
}
if !enabled {
return false
}
if !copyableType(t) {
glog.V(2).Infof("Type %v is not copyable", t)
return false
}
glog.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 glog.Fatalf
// if the type does not match.
func deepCopyMethodOrDie(t *types.Type) *types.Signature {
ret, err := deepCopyMethod(t)
if err != nil {
glog.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 glog.Fatalf
// if the type is wrong.
func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature {
ret, err := deepCopyIntoMethod(t)
if err != nil {
glog.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 := extractTag(t.CommentLines)
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 := extractTag(t.CommentLines)
tv := ""
if tag != nil {
tv = tag.value
if tv != "true" && tv != "false" {
glog.Fatalf("Type %v: unsupported %s value: %q", t, tagName, tag.value)
}
}
if g.allTypes && tv == "false" {
// The whole package is being generated, but this type has opted out.
glog.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.
glog.V(5).Infof("Not generating for type %v because type did not opt in", t)
return false
}
return true
}
func extractInterfacesTag(comments []string) []string {
var result []string
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(comments []string) (bool, error) {
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(append(t.SecondClosestCommentLines, t.CommentLines...))
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(append(t.SecondClosestCommentLines, t.CommentLines...))
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
}
glog.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
glog.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
glog.Fatalf("Hit an alias type %v. This should never happen.", t)
default:
glog.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() {
glog.Fatalf("Hit an unsupported type %v.", uet)
}
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:
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:
glog.Fatalf("Hit an unsupported type %v.", uet)
}
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 {
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 {
glog.Fatalf("Hit an unsupported type %v.", uet)
}
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:
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:
glog.Fatalf("Hit an unsupported type %v.", uft)
}
}
}
// 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:
glog.Fatalf("Hit an unsupported type %v.", uet)
}
}

View File

@@ -0,0 +1,713 @@
/*
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 (
"reflect"
"testing"
"k8s.io/gengo/types"
)
func Test_isRootedUnder(t *testing.T) {
testCases := []struct {
path string
roots []string
expect bool
}{
{
path: "/foo/bar",
roots: nil,
expect: false,
},
{
path: "/foo/bar",
roots: []string{},
expect: false,
},
{
path: "/foo/bar",
roots: []string{
"/bad",
},
expect: false,
},
{
path: "/foo/bar",
roots: []string{
"/foo",
},
expect: true,
},
{
path: "/foo/bar",
roots: []string{
"/bad",
"/foo",
},
expect: true,
},
{
path: "/foo/bar/qux/zorb",
roots: []string{
"/foo/bar/qux",
},
expect: true,
},
{
path: "/foo/bar",
roots: []string{
"/foo/bar",
},
expect: true,
},
{
path: "/foo/barn",
roots: []string{
"/foo/bar",
},
expect: false,
},
{
path: "/foo/bar",
roots: []string{
"/foo/barn",
},
expect: false,
},
{
path: "/foo/bar",
roots: []string{
"",
},
expect: true,
},
}
for i, tc := range testCases {
r := isRootedUnder(tc.path, tc.roots)
if r != tc.expect {
t.Errorf("case[%d]: expected %t, got %t for %q in %q", i, tc.expect, r, tc.path, tc.roots)
}
}
}
func Test_deepCopyMethod(t *testing.T) {
testCases := []struct {
typ types.Type
expect bool
error bool
}{
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
// No DeepCopy method.
Methods: map[string]*types.Type{},
},
expect: false,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// No DeepCopy method.
"method": {
Name: types.Name{Package: "pkgname", Name: "func()"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{},
},
},
},
},
expect: false,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (no result).
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func()"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (wrong result).
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func() int"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{
{
Name: types.Name{Name: "int"},
Kind: types.Builtin,
},
},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature with pointer receiver, but non-pointer result.
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{
{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
},
},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature with non-pointer receiver, but pointer result.
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
Parameters: []*types.Type{},
Results: []*types.Type{
{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Correct signature with non-pointer receiver.
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
Parameters: []*types.Type{},
Results: []*types.Type{
{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
},
},
},
},
},
},
expect: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Correct signature with pointer receiver.
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{
{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
},
},
},
},
},
expect: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (has params).
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func(int) pkgname.typename"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{
{
Name: types.Name{Name: "int"},
Kind: types.Builtin,
},
},
Results: []*types.Type{
{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
},
},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (extra results).
"DeepCopy": {
Name: types.Name{Package: "pkgname", Name: "func() (pkgname.typename, int)"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{
{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
},
{
Name: types.Name{Name: "int"},
Kind: types.Builtin,
},
},
},
},
},
},
expect: false,
error: true,
},
}
for i, tc := range testCases {
r, err := deepCopyMethod(&tc.typ)
if tc.error && err == nil {
t.Errorf("case[%d]: expected an error, got none", i)
} else if !tc.error && err != nil {
t.Errorf("case[%d]: expected no error, got: %v", i, err)
} else if !tc.error && (r != nil) != tc.expect {
t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r)
}
}
}
func Test_deepCopyIntoMethod(t *testing.T) {
testCases := []struct {
typ types.Type
expect bool
error bool
}{
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
// No DeepCopyInto method.
Methods: map[string]*types.Type{},
},
expect: false,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// No DeepCopyInto method.
"method": {
Name: types.Name{Package: "pkgname", Name: "func()"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{},
},
},
},
},
expect: false,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (no parameter).
"DeepCopyInto": {
Name: types.Name{Package: "pkgname", Name: "func()"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{},
Results: []*types.Type{},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (unexpected result).
"DeepCopyInto": {
Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename) int"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{
{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
},
Results: []*types.Type{
{
Name: types.Name{Name: "int"},
Kind: types.Builtin,
},
},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (non-pointer parameter, pointer receiver).
"DeepCopyInto": {
Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{
{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Results: []*types.Type{},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Wrong signature (non-pointer parameter, non-pointer receiver).
"DeepCopyInto": {
Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
Parameters: []*types.Type{
{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Results: []*types.Type{},
},
},
},
},
expect: false,
error: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Correct signature with non-pointer receiver.
"DeepCopyInto": {
Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
Parameters: []*types.Type{
{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
},
Results: []*types.Type{},
},
},
},
},
expect: true,
},
{
typ: types.Type{
Name: types.Name{Package: "pkgname", Name: "typename"},
Kind: types.Builtin,
Methods: map[string]*types.Type{
// Correct signature with pointer receiver.
"DeepCopyInto": {
Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"},
Kind: types.Func,
Signature: &types.Signature{
Receiver: &types.Type{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
Parameters: []*types.Type{
{
Kind: types.Pointer,
Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
},
},
Results: []*types.Type{},
},
},
},
},
expect: true,
},
}
for i, tc := range testCases {
r, err := deepCopyIntoMethod(&tc.typ)
if tc.error && err == nil {
t.Errorf("case[%d]: expected an error, got none", i)
} else if !tc.error && err != nil {
t.Errorf("case[%d]: expected no error, got: %v", i, err)
} else if !tc.error && (r != nil) != tc.expect {
t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r)
}
}
}
func Test_extractTagParams(t *testing.T) {
testCases := []struct {
comments []string
expect *tagValue
}{
{
comments: []string{
"Human comment",
},
expect: nil,
},
{
comments: []string{
"Human comment",
"+k8s:deepcopy-gen",
},
expect: &tagValue{
value: "",
register: false,
},
},
{
comments: []string{
"Human comment",
"+k8s:deepcopy-gen=package",
},
expect: &tagValue{
value: "package",
register: false,
},
},
{
comments: []string{
"Human comment",
"+k8s:deepcopy-gen=package,register",
},
expect: &tagValue{
value: "package",
register: true,
},
},
{
comments: []string{
"Human comment",
"+k8s:deepcopy-gen=package,register=true",
},
expect: &tagValue{
value: "package",
register: true,
},
},
{
comments: []string{
"Human comment",
"+k8s:deepcopy-gen=package,register=false",
},
expect: &tagValue{
value: "package",
register: false,
},
},
}
for i, tc := range testCases {
r := extractTag(tc.comments)
if r == nil && tc.expect != nil {
t.Errorf("case[%d]: expected non-nil", i)
}
if r != nil && tc.expect == nil {
t.Errorf("case[%d]: expected nil, got %v", i, *r)
}
if r != nil && *r != *tc.expect {
t.Errorf("case[%d]: expected %v, got %v", i, *tc.expect, *r)
}
}
}
func Test_extractInterfacesTag(t *testing.T) {
testCases := []struct {
comments []string
expect []string
}{
{
comments: []string{},
expect: nil,
},
{
comments: []string{
"+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object",
},
expect: []string{
"k8s.io/kubernetes/runtime.Object",
},
},
{
comments: []string{
"+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object",
"+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List",
},
expect: []string{
"k8s.io/kubernetes/runtime.Object",
"k8s.io/kubernetes/runtime.List",
},
},
{
comments: []string{
"+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object",
"+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object",
},
expect: []string{
"k8s.io/kubernetes/runtime.Object",
"k8s.io/kubernetes/runtime.Object",
},
},
}
for i, tc := range testCases {
r := extractInterfacesTag(tc.comments)
if r == nil && tc.expect != nil {
t.Errorf("case[%d]: expected non-nil", i)
}
if r != nil && tc.expect == nil {
t.Errorf("case[%d]: expected nil, got %v", i, r)
}
if r != nil && !reflect.DeepEqual(r, tc.expect) {
t.Errorf("case[%d]: expected %v, got %v", i, tc.expect, r)
}
}
}

88
vendor/k8s.io/gengo/examples/deepcopy-gen/main.go generated vendored Normal file
View File

@@ -0,0 +1,88 @@
/*
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.
*/
// deepcopy-gen is a tool for auto-generating DeepCopy functions.
//
// Given a list of input directories, it will generate DeepCopy and DeepCopyInto
// methods that efficiently perform a full deep-copy of each type. If these
// already exist (are predefined by the developer), they are used instead of
// generating new ones.
//
// If interfaces are referenced in types, it is expected that corresponding
// DeepCopyInterfaceName methods exist, e.g. DeepCopyObject for runtime.Object.
// These can be predefined by the developer or generated through tags, see below.
// They must be added to the interfaces themselves manually, e.g.
// type Object interface {
// ...
// DeepCopyObject() Object
// }
//
// All generation is governed by comment tags in the source. Any package may
// request DeepCopy generation by including a comment in the file-comments of
// one file, of the form:
// // +k8s:deepcopy-gen=package
//
// DeepCopy functions can be generated for individual types, rather than the
// entire package by specifying a comment on the type definion of the form:
// // +k8s:deepcopy-gen=true
//
// When generating for a whole package, individual types may opt out of
// DeepCopy generation by specifying a comment on the type definition of the form:
// // +k8s:deepcopy-gen=false
//
// Additional DeepCopyInterfaceName methods can be generated by sepcifying a
// comment on the type definition of the form:
// // +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object,k8s.io/kubernetes/runtime.List
// This leads to the generation of DeepCopyObject and DeepCopyList with the given
// interfaces as return types. We say that the tagged type implements deepcopy for the
// interfaces.
//
// The deepcopy funcs for interfaces using "+k8s:deepcopy-gen:interfaces" use the pointer
// of the type as receiver. For those special cases where the non-pointer object should
// implement the interface, this can be done with:
// // +k8s:deepcopy-gen:nonpointer-interfaces=true
package main
import (
"k8s.io/gengo/args"
"k8s.io/gengo/examples/deepcopy-gen/generators"
"github.com/golang/glog"
"github.com/spf13/pflag"
)
func main() {
arguments := args.Default()
// Override defaults.
arguments.OutputFileBaseName = "deepcopy_generated"
// Custom args.
customArgs := &generators.CustomArgs{}
pflag.CommandLine.StringSliceVar(&customArgs.BoundingDirs, "bounding-dirs", customArgs.BoundingDirs,
"Comma-separated list of import paths which bound the types for which deep-copies will be generated.")
arguments.CustomArgs = customArgs
// Run it.
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
glog.V(2).Info("Completed successfully.")
}

View File

@@ -0,0 +1,89 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package aliases
// Note: the following AliasInterface and AliasAliasInterface +k8s:deepcopy-gen:interfaces tags
// are necessary because Golang flattens interface alias in the type system. I.e. an alias J of
// an interface I is actually equivalent to I. So support deepcopies of those aliases, we have
// to implement all aliases of that interface.
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/aliases.Interface
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/aliases.AliasInterface
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/aliases.AliasAliasInterface
type Foo struct {
X int
}
type Interface interface {
DeepCopyInterface() Interface
DeepCopyAliasInterface() AliasInterface
DeepCopyAliasAliasInterface() AliasAliasInterface
}
type Builtin int
type Slice []int
type Pointer *int
type PointerAlias *Builtin
type Struct Foo
type Map map[string]int
type FooAlias Foo
type FooSlice []Foo
type FooPointer *Foo
type FooMap map[string]Foo
type AliasBuiltin Builtin
type AliasSlice Slice
type AliasPointer Pointer
type AliasStruct Struct
type AliasMap Map
type AliasInterface Interface
type AliasAliasInterface AliasInterface
type AliasInterfaceMap map[string]AliasInterface
type AliasInterfaceSlice []AliasInterface
// Aliases
type Ttest struct {
Builtin Builtin
Slice Slice
Pointer Pointer
PointerAlias PointerAlias
Struct Struct
Map Map
SliceSlice []Slice
MapSlice map[string]Slice
FooAlias FooAlias
FooSlice FooSlice
FooPointer FooPointer
FooMap FooMap
AliasBuiltin AliasBuiltin
AliasSlice AliasSlice
AliasPointer AliasPointer
AliasStruct AliasStruct
AliasMap AliasMap
AliasInterface AliasInterface
AliasAliasInterface AliasAliasInterface
AliasInterfaceMap AliasInterfaceMap
AliasInterfaceSlice AliasInterfaceSlice
}

View File

@@ -0,0 +1,412 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package aliases
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in AliasInterfaceMap) DeepCopyInto(out *AliasInterfaceMap) {
{
in := &in
*out = make(AliasInterfaceMap, len(*in))
for key, val := range *in {
if val == nil {
(*out)[key] = nil
} else {
(*out)[key] = val.DeepCopyAliasInterface()
}
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterfaceMap.
func (in AliasInterfaceMap) DeepCopy() AliasInterfaceMap {
if in == nil {
return nil
}
out := new(AliasInterfaceMap)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in AliasInterfaceSlice) DeepCopyInto(out *AliasInterfaceSlice) {
{
in := &in
*out = make(AliasInterfaceSlice, len(*in))
for i := range *in {
if (*in)[i] != nil {
(*out)[i] = (*in)[i].DeepCopyAliasInterface()
}
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterfaceSlice.
func (in AliasInterfaceSlice) DeepCopy() AliasInterfaceSlice {
if in == nil {
return nil
}
out := new(AliasInterfaceSlice)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in AliasMap) DeepCopyInto(out *AliasMap) {
{
in := &in
*out = make(AliasMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasMap.
func (in AliasMap) DeepCopy() AliasMap {
if in == nil {
return nil
}
out := new(AliasMap)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in AliasSlice) DeepCopyInto(out *AliasSlice) {
{
in := &in
*out = make(AliasSlice, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasSlice.
func (in AliasSlice) DeepCopy() AliasSlice {
if in == nil {
return nil
}
out := new(AliasSlice)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AliasStruct) DeepCopyInto(out *AliasStruct) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasStruct.
func (in *AliasStruct) DeepCopy() *AliasStruct {
if in == nil {
return nil
}
out := new(AliasStruct)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Foo) DeepCopyInto(out *Foo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Foo.
func (in *Foo) DeepCopy() *Foo {
if in == nil {
return nil
}
out := new(Foo)
in.DeepCopyInto(out)
return out
}
// DeepCopyAliasAliasInterface is an autogenerated deepcopy function, copying the receiver, creating a new AliasAliasInterface.
func (in *Foo) DeepCopyAliasAliasInterface() AliasAliasInterface {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyAliasInterface is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterface.
func (in *Foo) DeepCopyAliasInterface() AliasInterface {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Interface.
func (in *Foo) DeepCopyInterface() Interface {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FooAlias) DeepCopyInto(out *FooAlias) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooAlias.
func (in *FooAlias) DeepCopy() *FooAlias {
if in == nil {
return nil
}
out := new(FooAlias)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in FooMap) DeepCopyInto(out *FooMap) {
{
in := &in
*out = make(FooMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooMap.
func (in FooMap) DeepCopy() FooMap {
if in == nil {
return nil
}
out := new(FooMap)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in FooSlice) DeepCopyInto(out *FooSlice) {
{
in := &in
*out = make(FooSlice, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooSlice.
func (in FooSlice) DeepCopy() FooSlice {
if in == nil {
return nil
}
out := new(FooSlice)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Map) DeepCopyInto(out *Map) {
{
in := &in
*out = make(Map, len(*in))
for key, val := range *in {
(*out)[key] = val
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Map.
func (in Map) DeepCopy() Map {
if in == nil {
return nil
}
out := new(Map)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Slice) DeepCopyInto(out *Slice) {
{
in := &in
*out = make(Slice, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Slice.
func (in Slice) DeepCopy() Slice {
if in == nil {
return nil
}
out := new(Slice)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct) DeepCopyInto(out *Struct) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct.
func (in *Struct) DeepCopy() *Struct {
if in == nil {
return nil
}
out := new(Struct)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
if in.Slice != nil {
in, out := &in.Slice, &out.Slice
*out = make(Slice, len(*in))
copy(*out, *in)
}
if in.Pointer != nil {
in, out := &in.Pointer, &out.Pointer
*out = new(int)
**out = **in
}
if in.PointerAlias != nil {
in, out := &in.PointerAlias, &out.PointerAlias
*out = new(Builtin)
**out = **in
}
out.Struct = in.Struct
if in.Map != nil {
in, out := &in.Map, &out.Map
*out = make(Map, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.SliceSlice != nil {
in, out := &in.SliceSlice, &out.SliceSlice
*out = make([]Slice, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = make(Slice, len(*in))
copy(*out, *in)
}
}
}
if in.MapSlice != nil {
in, out := &in.MapSlice, &out.MapSlice
*out = make(map[string]Slice, len(*in))
for key, val := range *in {
var outVal []int
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make(Slice, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal
}
}
out.FooAlias = in.FooAlias
if in.FooSlice != nil {
in, out := &in.FooSlice, &out.FooSlice
*out = make(FooSlice, len(*in))
copy(*out, *in)
}
if in.FooPointer != nil {
in, out := &in.FooPointer, &out.FooPointer
*out = new(Foo)
**out = **in
}
if in.FooMap != nil {
in, out := &in.FooMap, &out.FooMap
*out = make(FooMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.AliasSlice != nil {
in, out := &in.AliasSlice, &out.AliasSlice
*out = make(AliasSlice, len(*in))
copy(*out, *in)
}
if in.AliasPointer != nil {
in, out := &in.AliasPointer, &out.AliasPointer
*out = new(int)
**out = **in
}
out.AliasStruct = in.AliasStruct
if in.AliasMap != nil {
in, out := &in.AliasMap, &out.AliasMap
*out = make(AliasMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.AliasInterface != nil {
out.AliasInterface = in.AliasInterface.DeepCopyAliasInterface()
}
if in.AliasAliasInterface != nil {
out.AliasAliasInterface = in.AliasAliasInterface.DeepCopyAliasAliasInterface()
}
if in.AliasInterfaceMap != nil {
in, out := &in.AliasInterfaceMap, &out.AliasInterfaceMap
*out = make(AliasInterfaceMap, len(*in))
for key, val := range *in {
if val == nil {
(*out)[key] = nil
} else {
(*out)[key] = val.DeepCopyAliasInterface()
}
}
}
if in.AliasInterfaceSlice != nil {
in, out := &in.AliasInterfaceSlice, &out.AliasInterfaceSlice
*out = make(AliasInterfaceSlice, len(*in))
for i := range *in {
if (*in)[i] != nil {
(*out)[i] = (*in)[i].DeepCopyAliasInterface()
}
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,35 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package builtins
type Ttest struct {
Byte byte
//Int8 int8 //TODO: int8 becomes byte in SnippetWriter
Int16 int16
Int32 int32
Int64 int64
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
Float32 float32
Float64 float64
String string
}

View File

@@ -0,0 +1,37 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package builtins
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,131 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package output_tests
import (
"github.com/google/gofuzz"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/aliases"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/interfaces"
)
// interfaceFuzzers contains fuzzer that set all interface to nil because our
// JSON deepcopy does not work with it.
// TODO: test also interface deepcopy
var interfaceFuzzers = []interface{}{
func(s *aliases.AliasAliasInterface, c fuzz.Continue) {
if c.RandBool() {
*s = nil
} else {
*s = &aliasAliasInterfaceInstance{X: c.Int()}
}
},
func(s *aliases.AliasInterface, c fuzz.Continue) {
if c.RandBool() {
*s = nil
} else {
*s = &aliasAliasInterfaceInstance{X: c.Int()}
}
},
func(s *aliases.Interface, c fuzz.Continue) {
if c.RandBool() {
*s = nil
} else {
*s = &aliasAliasInterfaceInstance{X: c.Int()}
}
},
func(s *aliases.AliasInterfaceMap, c fuzz.Continue) {
if c.RandBool() {
*s = nil
} else {
*s = make(aliases.AliasInterfaceMap)
for i := 0; i < c.Intn(3); i++ {
if c.RandBool() {
(*s)[c.RandString()] = nil
} else {
(*s)[c.RandString()] = &aliasAliasInterfaceInstance{X: c.Int()}
}
}
}
},
func(s *aliases.AliasInterfaceSlice, c fuzz.Continue) {
if c.RandBool() {
*s = nil
} else {
*s = make(aliases.AliasInterfaceSlice, 0, 0)
for i := 0; i < c.Intn(3); i++ {
if c.RandBool() {
*s = append(*s, nil)
} else {
*s = append(*s, &aliasAliasInterfaceInstance{X: c.Int()})
}
}
}
},
func(s *interfaces.Inner, c fuzz.Continue) {
if c.RandBool() {
*s = nil
} else {
*s = &interfacesInnerInstance{X: c.Float64()}
}
},
}
type aliasAliasInterfaceInstance struct {
X int
}
func (i *aliasAliasInterfaceInstance) DeepCopyInterface() aliases.Interface {
if i == nil {
return nil
}
return &aliasAliasInterfaceInstance{X: i.X}
}
func (i *aliasAliasInterfaceInstance) DeepCopyAliasInterface() aliases.AliasInterface {
if i == nil {
return nil
}
return &aliasAliasInterfaceInstance{X: i.X}
}
func (i *aliasAliasInterfaceInstance) DeepCopyAliasAliasInterface() aliases.AliasAliasInterface {
if i == nil {
return nil
}
return &aliasAliasInterfaceInstance{X: i.X}
}
type interfacesInnerInstance struct {
X float64
}
func (i *interfacesInnerInstance) DeepCopyInner() interfaces.Inner {
if i == nil {
return nil
}
return &interfacesInnerInstance{X: i.X}
}
func (i *interfacesInnerInstance) Function() float64 {
return i.X
}

View File

@@ -0,0 +1,29 @@
/*
Copyright 2017 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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package interfaces
type Inner interface {
Function() float64
DeepCopyInner() Inner
}
type Ttest struct {
I []Inner
}

View File

@@ -0,0 +1,46 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package interfaces
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
if in.I != nil {
in, out := &in.I, &out.I
*out = make([]Inner, len(*in))
for i := range *in {
if (*in)[i] != nil {
(*out)[i] = (*in)[i].DeepCopyInner()
}
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,43 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package maps
type Ttest struct {
Byte map[string]byte
//Int8 map[string]int8 //TODO: int8 becomes byte in SnippetWriter
Int16 map[string]int16
Int32 map[string]int32
Int64 map[string]int64
Uint8 map[string]uint8
Uint16 map[string]uint16
Uint32 map[string]uint32
Uint64 map[string]uint64
Float32 map[string]float32
Float64 map[string]float64
String map[string]string
StringPtr map[string]*string
StringPtrPtr map[string]**string
Map map[string]map[string]string
MapPtr map[string]*map[string]string
Slice map[string][]string
SlicePtr map[string]*[]string
Struct map[string]Ttest
StructPtr map[string]*Ttest
}

View File

@@ -0,0 +1,242 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package maps
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
if in.Byte != nil {
in, out := &in.Byte, &out.Byte
*out = make(map[string]byte, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Int16 != nil {
in, out := &in.Int16, &out.Int16
*out = make(map[string]int16, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Int32 != nil {
in, out := &in.Int32, &out.Int32
*out = make(map[string]int32, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Int64 != nil {
in, out := &in.Int64, &out.Int64
*out = make(map[string]int64, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Uint8 != nil {
in, out := &in.Uint8, &out.Uint8
*out = make(map[string]byte, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Uint16 != nil {
in, out := &in.Uint16, &out.Uint16
*out = make(map[string]uint16, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Uint32 != nil {
in, out := &in.Uint32, &out.Uint32
*out = make(map[string]uint32, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Uint64 != nil {
in, out := &in.Uint64, &out.Uint64
*out = make(map[string]uint64, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Float32 != nil {
in, out := &in.Float32, &out.Float32
*out = make(map[string]float32, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Float64 != nil {
in, out := &in.Float64, &out.Float64
*out = make(map[string]float64, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.String != nil {
in, out := &in.String, &out.String
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.StringPtr != nil {
in, out := &in.StringPtr, &out.StringPtr
*out = make(map[string]*string, len(*in))
for key, val := range *in {
var outVal *string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(string)
**out = **in
}
(*out)[key] = outVal
}
}
if in.StringPtrPtr != nil {
in, out := &in.StringPtrPtr, &out.StringPtrPtr
*out = make(map[string]**string, len(*in))
for key, val := range *in {
var outVal **string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(*string)
if **in != nil {
in, out := *in, *out
*out = new(string)
**out = **in
}
}
(*out)[key] = outVal
}
}
if in.Map != nil {
in, out := &in.Map, &out.Map
*out = make(map[string]map[string]string, len(*in))
for key, val := range *in {
var outVal map[string]string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
(*out)[key] = outVal
}
}
if in.MapPtr != nil {
in, out := &in.MapPtr, &out.MapPtr
*out = make(map[string]*map[string]string, len(*in))
for key, val := range *in {
var outVal *map[string]string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
(*out)[key] = outVal
}
}
if in.Slice != nil {
in, out := &in.Slice, &out.Slice
*out = make(map[string][]string, len(*in))
for key, val := range *in {
var outVal []string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make([]string, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal
}
}
if in.SlicePtr != nil {
in, out := &in.SlicePtr, &out.SlicePtr
*out = make(map[string]*[]string, len(*in))
for key, val := range *in {
var outVal *[]string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
(*out)[key] = outVal
}
}
if in.Struct != nil {
in, out := &in.Struct, &out.Struct
*out = make(map[string]Ttest, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.StructPtr != nil {
in, out := &in.StructPtr, &out.StructPtr
*out = make(map[string]*Ttest, len(*in))
for key, val := range *in {
var outVal *Ttest
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(Ttest)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,25 @@
/*
Copyright 2017 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 otherpkg
type Object interface {
DeepCopyObject() Object
}
type List interface {
DeepCopyList() List
}

View File

@@ -0,0 +1,157 @@
package output_tests
import (
"fmt"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/google/gofuzz"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/aliases"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/builtins"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/interfaces"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/maps"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/pointer"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/slices"
"k8s.io/gengo/examples/deepcopy-gen/output_tests/structs"
)
func TestWithValueFuzzer(t *testing.T) {
tests := []interface{}{
aliases.Ttest{},
builtins.Ttest{},
interfaces.Ttest{},
maps.Ttest{},
pointer.Ttest{},
slices.Ttest{},
structs.Ttest{},
}
fuzzer := fuzz.New()
fuzzer.NilChance(0.5)
fuzzer.NumElements(0, 2)
fuzzer.Funcs(interfaceFuzzers...)
for _, test := range tests {
t.Run(fmt.Sprintf("%T", test), func(t *testing.T) {
N := 1000
for i := 0; i < N; i++ {
original := reflect.New(reflect.TypeOf(test)).Interface()
fuzzer.Fuzz(original)
reflectCopy := ReflectDeepCopy(original)
if !reflect.DeepEqual(original, reflectCopy) {
t.Errorf("original and reflectCopy are different:\n\n original = %s\n\n jsonCopy = %s", spew.Sdump(original), spew.Sdump(reflectCopy))
}
deepCopy := reflect.ValueOf(original).MethodByName("DeepCopy").Call(nil)[0].Interface()
if !reflect.DeepEqual(original, deepCopy) {
t.Fatalf("original and deepCopy are different:\n\n original = %s\n\n deepCopy() = %s", spew.Sdump(original), spew.Sdump(deepCopy))
}
ValueFuzz(original)
if !reflect.DeepEqual(reflectCopy, deepCopy) {
t.Fatalf("reflectCopy and deepCopy are different:\n\n origin = %s\n\n jsonCopy() = %s", spew.Sdump(original), spew.Sdump(deepCopy))
}
}
})
}
}
func BenchmarkReflectDeepCopy(b *testing.B) {
fourtytwo := "fourtytwo"
fourtytwoPtr := &fourtytwo
var nilMap map[string]string
var nilSlice []string
mapPtr := &map[string]string{"0": "fourtytwo", "1": "fourtytwo"}
slicePtr := &[]string{"fourtytwo", "fourtytwo", "fourtytwo"}
structPtr := &pointer.Ttest{
Builtin: &fourtytwo,
Ptr: &fourtytwoPtr,
}
tests := []interface{}{
maps.Ttest{
Byte: map[string]byte{"0": 42, "1": 42, "3": 42},
Int16: map[string]int16{"0": 42, "1": 42, "3": 42},
Int32: map[string]int32{"0": 42, "1": 42, "3": 42},
Int64: map[string]int64{"0": 42, "1": 42, "3": 42},
Uint8: map[string]uint8{"0": 42, "1": 42, "3": 42},
Uint16: map[string]uint16{"0": 42, "1": 42, "3": 42},
Uint32: map[string]uint32{"0": 42, "1": 42, "3": 42},
Uint64: map[string]uint64{"0": 42, "1": 42, "3": 42},
Float32: map[string]float32{"0": 42.0, "1": 42.0, "3": 42.0},
Float64: map[string]float64{"0": 42, "1": 42, "3": 42},
String: map[string]string{"0": "fourtytwo", "1": "fourtytwo", "3": "fourtytwo"},
StringPtr: map[string]*string{"0": &fourtytwo, "1": &fourtytwo, "3": &fourtytwo},
StringPtrPtr: map[string]**string{"0": &fourtytwoPtr, "1": &fourtytwoPtr, "3": &fourtytwoPtr},
Map: map[string]map[string]string{"0": nil, "1": {"a": fourtytwo, "b": fourtytwo}, "3": {}},
MapPtr: map[string]*map[string]string{"0": nil, "1": {"a": fourtytwo, "b": fourtytwo}, "3": &nilMap},
Slice: map[string][]string{"0": nil, "1": {"a", "b"}, "2": {}},
SlicePtr: map[string]*[]string{"0": nil, "1": {"a", "b"}, "2": &nilSlice},
Struct: map[string]maps.Ttest{"0": {}, "1": {Byte: map[string]byte{"0": 42, "1": 42, "3": 42}}},
StructPtr: map[string]*maps.Ttest{"0": nil, "1": {}, "2": {Byte: map[string]byte{"0": 42, "1": 42, "3": 42}}},
},
slices.Ttest{
Byte: []byte{42, 42, 42},
Int16: []int16{42, 42, 42},
Int32: []int32{42, 42, 42},
Int64: []int64{42, 42, 42},
Uint8: []uint8{42, 42, 42},
Uint16: []uint16{42, 42, 42},
Uint32: []uint32{42, 42, 42},
Uint64: []uint64{42, 42, 42},
Float32: []float32{42.0, 42.0, 42.0},
Float64: []float64{42, 42, 42},
String: []string{"fourtytwo", "fourtytwo", "fourtytwo"},
StringPtr: []*string{&fourtytwo, &fourtytwo, &fourtytwo},
StringPtrPtr: []**string{&fourtytwoPtr, &fourtytwoPtr, &fourtytwoPtr},
Map: []map[string]string{nil, {"a": fourtytwo, "b": fourtytwo}, {}},
MapPtr: []*map[string]string{nil, {"a": fourtytwo, "b": fourtytwo}, &nilMap},
Slice: [][]string{nil, {"a", "b"}, {}},
SlicePtr: []*[]string{nil, {"a", "b"}, &nilSlice},
Struct: []slices.Ttest{{}, {Byte: []byte{42, 42, 42}}},
StructPtr: []*slices.Ttest{nil, {}, {Byte: []byte{42, 42, 42}}},
},
pointer.Ttest{
Builtin: &fourtytwo,
Ptr: &fourtytwoPtr,
Map: &map[string]string{"0": "fourtytwo", "1": "fourtytwo"},
Slice: &[]string{"fourtytwo", "fourtytwo", "fourtytwo"},
MapPtr: &mapPtr,
SlicePtr: &slicePtr,
Struct: &pointer.Ttest{
Builtin: &fourtytwo,
Ptr: &fourtytwoPtr,
},
StructPtr: &structPtr,
},
}
fuzzer := fuzz.New()
fuzzer.NilChance(0.5)
fuzzer.NumElements(0, 2)
fuzzer.Funcs(interfaceFuzzers...)
for _, test := range tests {
b.Run(fmt.Sprintf("%T", test), func(b *testing.B) {
for i := 0; i < b.N; i++ {
switch t := test.(type) {
case maps.Ttest:
t.DeepCopy()
case slices.Ttest:
t.DeepCopy()
case pointer.Ttest:
t.DeepCopy()
default:
b.Fatalf("missing type case in switch for %T", t)
}
}
})
}
}

View File

@@ -0,0 +1,31 @@
/*
Copyright 2017 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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package pointer
type Ttest struct {
Builtin *string
Ptr **string
Map *map[string]string
Slice *[]string
MapPtr **map[string]string
SlicePtr **[]string
Struct *Ttest
StructPtr **Ttest
}

View File

@@ -0,0 +1,113 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package pointer
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
if in.Builtin != nil {
in, out := &in.Builtin, &out.Builtin
*out = new(string)
**out = **in
}
if in.Ptr != nil {
in, out := &in.Ptr, &out.Ptr
*out = new(*string)
if **in != nil {
in, out := *in, *out
*out = new(string)
**out = **in
}
}
if in.Map != nil {
in, out := &in.Map, &out.Map
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
if in.Slice != nil {
in, out := &in.Slice, &out.Slice
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
if in.MapPtr != nil {
in, out := &in.MapPtr, &out.MapPtr
*out = new(*map[string]string)
if **in != nil {
in, out := *in, *out
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
}
if in.SlicePtr != nil {
in, out := &in.SlicePtr, &out.SlicePtr
*out = new(*[]string)
if **in != nil {
in, out := *in, *out
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
}
if in.Struct != nil {
in, out := &in.Struct, &out.Struct
*out = new(Ttest)
(*in).DeepCopyInto(*out)
}
if in.StructPtr != nil {
in, out := &in.StructPtr, &out.StructPtr
*out = new(*Ttest)
if **in != nil {
in, out := *in, *out
*out = new(Ttest)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,81 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package output_tests
import (
"fmt"
"reflect"
)
// ReflectDeepCopy deep copies the object using reflection.
func ReflectDeepCopy(in interface{}) interface{} {
return reflectDeepCopy(reflect.ValueOf(in)).Interface()
}
func reflectDeepCopy(src reflect.Value) reflect.Value {
switch src.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
if src.IsNil() {
return src
}
}
switch src.Kind() {
case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr:
panic(fmt.Sprintf("cannot deep copy kind: %s", src.Kind()))
case reflect.Array:
dst := reflect.New(src.Type())
for i := 0; i < src.Len(); i++ {
dst.Elem().Index(i).Set(reflectDeepCopy(src.Index(i)))
}
return dst.Elem()
case reflect.Interface:
return reflectDeepCopy(src.Elem())
case reflect.Map:
dst := reflect.MakeMap(src.Type())
for _, k := range src.MapKeys() {
dst.SetMapIndex(k, reflectDeepCopy(src.MapIndex(k)))
}
return dst
case reflect.Ptr:
dst := reflect.New(src.Type().Elem())
dst.Elem().Set(reflectDeepCopy(src.Elem()))
return dst
case reflect.Slice:
dst := reflect.MakeSlice(src.Type(), 0, src.Len())
for i := 0; i < src.Len(); i++ {
dst = reflect.Append(dst, reflectDeepCopy(src.Index(i)))
}
return dst
case reflect.Struct:
dst := reflect.New(src.Type())
for i := 0; i < src.NumField(); i++ {
if !dst.Elem().Field(i).CanSet() {
// Can't set private fields. At this point, the
// best we can do is a shallow copy. For
// example, time.Time is a value type with
// private members that can be shallow copied.
return src
}
dst.Elem().Field(i).Set(reflectDeepCopy(src.Field(i)))
}
return dst.Elem()
default:
// Value types like numbers, booleans, and strings.
return src
}
}

View File

@@ -0,0 +1,43 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package slices
type Ttest struct {
Byte []byte
//Int8 []int8 //TODO: int8 becomes byte in SnippetWriter
Int16 []int16
Int32 []int32
Int64 []int64
Uint8 []uint8
Uint16 []uint16
Uint32 []uint32
Uint64 []uint64
Float32 []float32
Float64 []float64
String []string
StringPtr []*string
StringPtrPtr []**string
Map []map[string]string
MapPtr []*map[string]string
Slice [][]string
SlicePtr []*[]string
Struct []Ttest
StructPtr []*Ttest
}

View File

@@ -0,0 +1,192 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package slices
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
if in.Byte != nil {
in, out := &in.Byte, &out.Byte
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.Int16 != nil {
in, out := &in.Int16, &out.Int16
*out = make([]int16, len(*in))
copy(*out, *in)
}
if in.Int32 != nil {
in, out := &in.Int32, &out.Int32
*out = make([]int32, len(*in))
copy(*out, *in)
}
if in.Int64 != nil {
in, out := &in.Int64, &out.Int64
*out = make([]int64, len(*in))
copy(*out, *in)
}
if in.Uint8 != nil {
in, out := &in.Uint8, &out.Uint8
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.Uint16 != nil {
in, out := &in.Uint16, &out.Uint16
*out = make([]uint16, len(*in))
copy(*out, *in)
}
if in.Uint32 != nil {
in, out := &in.Uint32, &out.Uint32
*out = make([]uint32, len(*in))
copy(*out, *in)
}
if in.Uint64 != nil {
in, out := &in.Uint64, &out.Uint64
*out = make([]uint64, len(*in))
copy(*out, *in)
}
if in.Float32 != nil {
in, out := &in.Float32, &out.Float32
*out = make([]float32, len(*in))
copy(*out, *in)
}
if in.Float64 != nil {
in, out := &in.Float64, &out.Float64
*out = make([]float64, len(*in))
copy(*out, *in)
}
if in.String != nil {
in, out := &in.String, &out.String
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.StringPtr != nil {
in, out := &in.StringPtr, &out.StringPtr
*out = make([]*string, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(string)
**out = **in
}
}
}
if in.StringPtrPtr != nil {
in, out := &in.StringPtrPtr, &out.StringPtrPtr
*out = make([]**string, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(*string)
if **in != nil {
in, out := *in, *out
*out = new(string)
**out = **in
}
}
}
}
if in.Map != nil {
in, out := &in.Map, &out.Map
*out = make([]map[string]string, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
}
if in.MapPtr != nil {
in, out := &in.MapPtr, &out.MapPtr
*out = make([]*map[string]string, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
}
}
if in.Slice != nil {
in, out := &in.Slice, &out.Slice
*out = make([][]string, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = make([]string, len(*in))
copy(*out, *in)
}
}
}
if in.SlicePtr != nil {
in, out := &in.SlicePtr, &out.SlicePtr
*out = make([]*[]string, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
}
}
if in.Struct != nil {
in, out := &in.Struct, &out.Struct
*out = make([]Ttest, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.StructPtr != nil {
in, out := &in.StructPtr, &out.StructPtr
*out = make([]*Ttest, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(Ttest)
(*in).DeepCopyInto(*out)
}
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,40 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package structs
type Inner struct {
Byte byte
//Int8 int8 //TODO: int8 becomes byte in SnippetWriter
Int16 int16
Int32 int32
Int64 int64
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
Float32 float32
Float64 float64
String string
}
type Ttest struct {
Inner1 Inner
Inner2 Inner
}

View File

@@ -0,0 +1,55 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package structs
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Inner) DeepCopyInto(out *Inner) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Inner.
func (in *Inner) DeepCopy() *Inner {
if in == nil {
return nil
}
out := new(Inner)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ttest) DeepCopyInto(out *Ttest) {
*out = *in
out.Inner1 = in.Inner1
out.Inner2 = in.Inner2
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest.
func (in *Ttest) DeepCopy() *Ttest {
if in == nil {
return nil
}
out := new(Ttest)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,86 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package output_tests
import (
"reflect"
)
// ValueFuzz recursively changes all basic type values in an object. Any kind of references will not
// be touched, i.e. the addresses of slices, maps, pointers will stay unchanged.
func ValueFuzz(obj interface{}) {
valueFuzz(reflect.ValueOf(obj))
}
func valueFuzz(obj reflect.Value) {
switch obj.Kind() {
case reflect.Array:
for i := 0; i < obj.Len(); i++ {
valueFuzz(obj.Index(i))
}
case reflect.Slice:
if obj.IsNil() {
// TODO: set non-nil value
} else {
for i := 0; i < obj.Len(); i++ {
valueFuzz(obj.Index(i))
}
}
case reflect.Interface, reflect.Ptr:
if obj.IsNil() {
// TODO: set non-nil value
} else {
valueFuzz(obj.Elem())
}
case reflect.Struct:
for i, n := 0, obj.NumField(); i < n; i++ {
valueFuzz(obj.Field(i))
}
case reflect.Map:
if obj.IsNil() {
// TODO: set non-nil value
} else {
for _, k := range obj.MapKeys() {
// map values are not addressable. We need a copy.
v := obj.MapIndex(k)
copy := reflect.New(v.Type())
copy.Elem().Set(v)
valueFuzz(copy.Elem())
obj.SetMapIndex(k, copy.Elem())
}
// TODO: set some new value
}
case reflect.Func: // ignore, we don't have function types in our API
default:
if !obj.CanSet() {
return
}
switch obj.Kind() {
case reflect.String:
obj.SetString(obj.String() + "x")
case reflect.Bool:
obj.SetBool(!obj.Bool())
case reflect.Float32, reflect.Float64:
obj.SetFloat(obj.Float()*2.0 + 1.0)
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
obj.SetInt(obj.Int() + 1)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
obj.SetUint(obj.Uint() + 1)
default:
}
}
}

View File

@@ -0,0 +1,171 @@
/*
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 wholepkg
import "k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg"
// Trivial
type Struct_Empty struct{}
// Only primitives
type Struct_Primitives struct {
BoolField bool
IntField int
StringField string
FloatField float64
}
type Struct_Primitives_Alias Struct_Primitives
type Struct_Embed_Struct_Primitives struct {
Struct_Primitives
}
type Struct_Embed_Int struct {
int
}
type Struct_Struct_Primitives struct {
StructField Struct_Primitives
}
// Manual DeepCopy method
type ManualStruct struct {
StringField string
}
func (m ManualStruct) DeepCopy() ManualStruct {
return m
}
type ManualStruct_Alias ManualStruct
type Struct_Embed_ManualStruct struct {
ManualStruct
}
// Only pointers to primitives
type Struct_PrimitivePointers struct {
BoolPtrField *bool
IntPtrField *int
StringPtrField *string
FloatPtrField *float64
}
type Struct_PrimitivePointers_Alias Struct_PrimitivePointers
type Struct_Embed_Struct_PrimitivePointers struct {
Struct_PrimitivePointers
}
type Struct_Embed_Pointer struct {
*int
}
type Struct_Struct_PrimitivePointers struct {
StructField Struct_PrimitivePointers
}
// Manual DeepCopy method
type ManualSlice []string
func (m ManualSlice) DeepCopy() ManualSlice {
r := make(ManualSlice, len(m))
copy(r, m)
return r
}
// Slices
type Struct_Slices struct {
SliceBoolField []bool
SliceByteField []byte
SliceIntField []int
SliceStringField []string
SliceFloatField []float64
SliceStructPrimitivesField []Struct_Primitives
SliceStructPrimitivesAliasField []Struct_Primitives_Alias
SliceStructPrimitivePointersField []Struct_PrimitivePointers
SliceStructPrimitivePointersAliasField []Struct_PrimitivePointers_Alias
SliceSliceIntField [][]int
SliceManualStructField []ManualStruct
ManualSliceField ManualSlice
}
type Struct_Slices_Alias Struct_Slices
type Struct_Embed_Struct_Slices struct {
Struct_Slices
}
type Struct_Struct_Slices struct {
StructField Struct_Slices
}
// Everything
type Struct_Everything struct {
BoolField bool
IntField int
StringField string
FloatField float64
StructField Struct_Primitives
EmptyStructField Struct_Empty
ManualStructField ManualStruct
ManualStructAliasField ManualStruct_Alias
BoolPtrField *bool
IntPtrField *int
StringPtrField *string
FloatPtrField *float64
PrimitivePointersField Struct_PrimitivePointers
ManualStructPtrField *ManualStruct
ManualStructAliasPtrField *ManualStruct_Alias
SliceBoolField []bool
SliceByteField []byte
SliceIntField []int
SliceStringField []string
SliceFloatField []float64
SlicesField Struct_Slices
SliceManualStructField []ManualStruct
ManualSliceField ManualSlice
}
// An Object
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.Object
type Struct_ExplicitObject struct {
x int
}
// An Object which is used a non-pointer
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.Object
// +k8s:deepcopy-gen:nonpointer-interfaces=true
type Struct_NonPointerExplicitObject struct {
x int
}
// +k8s:deepcopy-gen=false
type Struct_TypeMeta struct {
}
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.Object
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.List
type Struct_ObjectAndList struct {
}
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.Object
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.Object
type Struct_ObjectAndObject struct {
}
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/wholepkg.Selector
// +k8s:deepcopy-gen:interfaces=k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg.Object
type Struct_ExplicitSelectorExplicitObject struct {
Struct_TypeMeta
}
type Struct_Interfaces struct {
ObjectField otherpkg.Object
NilObjectField otherpkg.Object
SelectorField Selector
}

View File

@@ -0,0 +1,20 @@
/*
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 wholepkg
// Another type in another file.
type Struct_B struct{}

View File

@@ -0,0 +1,145 @@
/*
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 wholepkg
import (
"reflect"
"testing"
fuzz "github.com/google/gofuzz"
)
func TestDeepCopyPrimitives(t *testing.T) {
x := Struct_Primitives{}
y := Struct_Primitives{}
if !reflect.DeepEqual(&x, &y) {
t.Errorf("objects should be equal to start, but are not")
}
fuzzer := fuzz.New()
fuzzer.Fuzz(&x)
fuzzer.Fuzz(&y)
if reflect.DeepEqual(&x, &y) {
t.Errorf("objects should not be equal, but are")
}
x.DeepCopyInto(&y)
if !reflect.DeepEqual(&x, &y) {
t.Errorf("objects should be equal, but are not")
}
}
func TestDeepCopyInterfaceFields(t *testing.T) {
x := Struct_Interfaces{}
y := Struct_Interfaces{}
if !reflect.DeepEqual(&x, &y) {
t.Errorf("objects should be equal to start, but are not")
}
fuzzer := fuzz.New()
obj := Struct_ExplicitObject{}
fuzzer.Fuzz(&obj)
x.ObjectField = &obj
sel := Struct_ExplicitSelectorExplicitObject{}
fuzzer.Fuzz(&sel)
x.SelectorField = &sel
if reflect.DeepEqual(&x, &y) {
t.Errorf("objects should not be equal, but are")
}
x.DeepCopyInto(&y)
if !reflect.DeepEqual(&x, &y) {
t.Errorf("objects should be equal, but are not")
}
}
func TestNilCopy(t *testing.T) {
var x *Struct_B
y := x.DeepCopy()
if y != nil {
t.Errorf("Expected nil as deepcopy of nil, got %+v", y)
}
}
func assertMethod(t *testing.T, typ reflect.Type, name string) {
if _, found := typ.MethodByName(name); !found {
t.Errorf("Struct_ExplicitObject must have %v method", name)
}
}
func assertNotMethod(t *testing.T, typ reflect.Type, name string) {
if _, found := typ.MethodByName(name); found {
t.Errorf("%v must not have %v method", typ, name)
}
}
func TestInterfaceTypes(t *testing.T) {
explicitObject := reflect.TypeOf(&Struct_ExplicitObject{})
assertMethod(t, explicitObject, "DeepCopyObject")
typeMeta := reflect.TypeOf(&Struct_TypeMeta{})
assertNotMethod(t, typeMeta, "DeepCopy")
objectAndList := reflect.TypeOf(&Struct_ObjectAndList{})
assertMethod(t, objectAndList, "DeepCopyObject")
assertMethod(t, objectAndList, "DeepCopyList")
objectAndObject := reflect.TypeOf(&Struct_ObjectAndObject{})
assertMethod(t, objectAndObject, "DeepCopyObject")
explicitSelectorExplicitObject := reflect.TypeOf(&Struct_ExplicitSelectorExplicitObject{})
assertMethod(t, explicitSelectorExplicitObject, "DeepCopySelector")
assertMethod(t, explicitSelectorExplicitObject, "DeepCopyObject")
}
func TestInterfaceDeepCopy(t *testing.T) {
x := Struct_ExplicitObject{}
fuzzer := fuzz.New()
fuzzer.Fuzz(&x)
y_obj := x.DeepCopyObject()
y, ok := y_obj.(*Struct_ExplicitObject)
if !ok {
t.Fatalf("epxected Struct_ExplicitObject from Struct_ExplicitObject.DeepCopyObject, got: %t", y_obj)
}
if !reflect.DeepEqual(y, &x) {
t.Error("objects should be equal, but are not")
}
}
func TestInterfaceNonPointerDeepCopy(t *testing.T) {
x := Struct_NonPointerExplicitObject{}
fuzzer := fuzz.New()
fuzzer.Fuzz(&x)
y_obj := x.DeepCopyObject()
y, ok := y_obj.(Struct_NonPointerExplicitObject)
if !ok {
t.Fatalf("epxected Struct_NonPointerExplicitObject from Struct_NonPointerExplicitObject.DeepCopyObject, got: %t", y_obj)
}
if !reflect.DeepEqual(y, x) {
t.Error("objects should be equal, but are not")
}
}

View File

@@ -0,0 +1,20 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// This is a test package.
package wholepkg

View File

@@ -0,0 +1,21 @@
/*
Copyright 2017 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 wholepkg
type Selector interface {
DeepCopySelector() Selector
}

View File

@@ -0,0 +1,760 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package wholepkg
import (
otherpkg "k8s.io/gengo/examples/deepcopy-gen/output_tests/otherpkg"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ManualSlice) DeepCopyInto(out *ManualSlice) {
{
in := &in
*out = in.DeepCopy()
return
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ManualStruct) DeepCopyInto(out *ManualStruct) {
*out = in.DeepCopy()
return
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ManualStruct_Alias) DeepCopyInto(out *ManualStruct_Alias) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManualStruct_Alias.
func (in *ManualStruct_Alias) DeepCopy() *ManualStruct_Alias {
if in == nil {
return nil
}
out := new(ManualStruct_Alias)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_B) DeepCopyInto(out *Struct_B) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_B.
func (in *Struct_B) DeepCopy() *Struct_B {
if in == nil {
return nil
}
out := new(Struct_B)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Embed_Int) DeepCopyInto(out *Struct_Embed_Int) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Embed_Int.
func (in *Struct_Embed_Int) DeepCopy() *Struct_Embed_Int {
if in == nil {
return nil
}
out := new(Struct_Embed_Int)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Embed_ManualStruct) DeepCopyInto(out *Struct_Embed_ManualStruct) {
*out = *in
out.ManualStruct = in.ManualStruct.DeepCopy()
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Embed_ManualStruct.
func (in *Struct_Embed_ManualStruct) DeepCopy() *Struct_Embed_ManualStruct {
if in == nil {
return nil
}
out := new(Struct_Embed_ManualStruct)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Embed_Pointer) DeepCopyInto(out *Struct_Embed_Pointer) {
*out = *in
if in.int != nil {
in, out := &in.int, &out.int
*out = new(int)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Embed_Pointer.
func (in *Struct_Embed_Pointer) DeepCopy() *Struct_Embed_Pointer {
if in == nil {
return nil
}
out := new(Struct_Embed_Pointer)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Embed_Struct_PrimitivePointers) DeepCopyInto(out *Struct_Embed_Struct_PrimitivePointers) {
*out = *in
in.Struct_PrimitivePointers.DeepCopyInto(&out.Struct_PrimitivePointers)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Embed_Struct_PrimitivePointers.
func (in *Struct_Embed_Struct_PrimitivePointers) DeepCopy() *Struct_Embed_Struct_PrimitivePointers {
if in == nil {
return nil
}
out := new(Struct_Embed_Struct_PrimitivePointers)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Embed_Struct_Primitives) DeepCopyInto(out *Struct_Embed_Struct_Primitives) {
*out = *in
out.Struct_Primitives = in.Struct_Primitives
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Embed_Struct_Primitives.
func (in *Struct_Embed_Struct_Primitives) DeepCopy() *Struct_Embed_Struct_Primitives {
if in == nil {
return nil
}
out := new(Struct_Embed_Struct_Primitives)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Embed_Struct_Slices) DeepCopyInto(out *Struct_Embed_Struct_Slices) {
*out = *in
in.Struct_Slices.DeepCopyInto(&out.Struct_Slices)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Embed_Struct_Slices.
func (in *Struct_Embed_Struct_Slices) DeepCopy() *Struct_Embed_Struct_Slices {
if in == nil {
return nil
}
out := new(Struct_Embed_Struct_Slices)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Empty) DeepCopyInto(out *Struct_Empty) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Empty.
func (in *Struct_Empty) DeepCopy() *Struct_Empty {
if in == nil {
return nil
}
out := new(Struct_Empty)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Everything) DeepCopyInto(out *Struct_Everything) {
*out = *in
out.StructField = in.StructField
out.EmptyStructField = in.EmptyStructField
out.ManualStructField = in.ManualStructField.DeepCopy()
out.ManualStructAliasField = in.ManualStructAliasField
if in.BoolPtrField != nil {
in, out := &in.BoolPtrField, &out.BoolPtrField
*out = new(bool)
**out = **in
}
if in.IntPtrField != nil {
in, out := &in.IntPtrField, &out.IntPtrField
*out = new(int)
**out = **in
}
if in.StringPtrField != nil {
in, out := &in.StringPtrField, &out.StringPtrField
*out = new(string)
**out = **in
}
if in.FloatPtrField != nil {
in, out := &in.FloatPtrField, &out.FloatPtrField
*out = new(float64)
**out = **in
}
in.PrimitivePointersField.DeepCopyInto(&out.PrimitivePointersField)
if in.ManualStructPtrField != nil {
in, out := &in.ManualStructPtrField, &out.ManualStructPtrField
x := (*in).DeepCopy()
*out = &x
}
if in.ManualStructAliasPtrField != nil {
in, out := &in.ManualStructAliasPtrField, &out.ManualStructAliasPtrField
*out = new(ManualStruct_Alias)
**out = **in
}
if in.SliceBoolField != nil {
in, out := &in.SliceBoolField, &out.SliceBoolField
*out = make([]bool, len(*in))
copy(*out, *in)
}
if in.SliceByteField != nil {
in, out := &in.SliceByteField, &out.SliceByteField
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.SliceIntField != nil {
in, out := &in.SliceIntField, &out.SliceIntField
*out = make([]int, len(*in))
copy(*out, *in)
}
if in.SliceStringField != nil {
in, out := &in.SliceStringField, &out.SliceStringField
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.SliceFloatField != nil {
in, out := &in.SliceFloatField, &out.SliceFloatField
*out = make([]float64, len(*in))
copy(*out, *in)
}
in.SlicesField.DeepCopyInto(&out.SlicesField)
if in.SliceManualStructField != nil {
in, out := &in.SliceManualStructField, &out.SliceManualStructField
*out = make([]ManualStruct, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
out.ManualSliceField = in.ManualSliceField.DeepCopy()
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Everything.
func (in *Struct_Everything) DeepCopy() *Struct_Everything {
if in == nil {
return nil
}
out := new(Struct_Everything)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_ExplicitObject) DeepCopyInto(out *Struct_ExplicitObject) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_ExplicitObject.
func (in *Struct_ExplicitObject) DeepCopy() *Struct_ExplicitObject {
if in == nil {
return nil
}
out := new(Struct_ExplicitObject)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object.
func (in *Struct_ExplicitObject) DeepCopyObject() otherpkg.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_ExplicitSelectorExplicitObject) DeepCopyInto(out *Struct_ExplicitSelectorExplicitObject) {
*out = *in
out.Struct_TypeMeta = in.Struct_TypeMeta
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_ExplicitSelectorExplicitObject.
func (in *Struct_ExplicitSelectorExplicitObject) DeepCopy() *Struct_ExplicitSelectorExplicitObject {
if in == nil {
return nil
}
out := new(Struct_ExplicitSelectorExplicitObject)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object.
func (in *Struct_ExplicitSelectorExplicitObject) DeepCopyObject() otherpkg.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopySelector is an autogenerated deepcopy function, copying the receiver, creating a new Selector.
func (in *Struct_ExplicitSelectorExplicitObject) DeepCopySelector() Selector {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Interfaces) DeepCopyInto(out *Struct_Interfaces) {
*out = *in
if in.ObjectField != nil {
out.ObjectField = in.ObjectField.DeepCopyObject()
}
if in.NilObjectField != nil {
out.NilObjectField = in.NilObjectField.DeepCopyObject()
}
if in.SelectorField != nil {
out.SelectorField = in.SelectorField.DeepCopySelector()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Interfaces.
func (in *Struct_Interfaces) DeepCopy() *Struct_Interfaces {
if in == nil {
return nil
}
out := new(Struct_Interfaces)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_NonPointerExplicitObject) DeepCopyInto(out *Struct_NonPointerExplicitObject) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_NonPointerExplicitObject.
func (in *Struct_NonPointerExplicitObject) DeepCopy() *Struct_NonPointerExplicitObject {
if in == nil {
return nil
}
out := new(Struct_NonPointerExplicitObject)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object.
func (in Struct_NonPointerExplicitObject) DeepCopyObject() otherpkg.Object {
return *in.DeepCopy()
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_ObjectAndList) DeepCopyInto(out *Struct_ObjectAndList) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_ObjectAndList.
func (in *Struct_ObjectAndList) DeepCopy() *Struct_ObjectAndList {
if in == nil {
return nil
}
out := new(Struct_ObjectAndList)
in.DeepCopyInto(out)
return out
}
// DeepCopyList is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.List.
func (in *Struct_ObjectAndList) DeepCopyList() otherpkg.List {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object.
func (in *Struct_ObjectAndList) DeepCopyObject() otherpkg.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_ObjectAndObject) DeepCopyInto(out *Struct_ObjectAndObject) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_ObjectAndObject.
func (in *Struct_ObjectAndObject) DeepCopy() *Struct_ObjectAndObject {
if in == nil {
return nil
}
out := new(Struct_ObjectAndObject)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object.
func (in *Struct_ObjectAndObject) DeepCopyObject() otherpkg.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_PrimitivePointers) DeepCopyInto(out *Struct_PrimitivePointers) {
*out = *in
if in.BoolPtrField != nil {
in, out := &in.BoolPtrField, &out.BoolPtrField
*out = new(bool)
**out = **in
}
if in.IntPtrField != nil {
in, out := &in.IntPtrField, &out.IntPtrField
*out = new(int)
**out = **in
}
if in.StringPtrField != nil {
in, out := &in.StringPtrField, &out.StringPtrField
*out = new(string)
**out = **in
}
if in.FloatPtrField != nil {
in, out := &in.FloatPtrField, &out.FloatPtrField
*out = new(float64)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_PrimitivePointers.
func (in *Struct_PrimitivePointers) DeepCopy() *Struct_PrimitivePointers {
if in == nil {
return nil
}
out := new(Struct_PrimitivePointers)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_PrimitivePointers_Alias) DeepCopyInto(out *Struct_PrimitivePointers_Alias) {
*out = *in
if in.BoolPtrField != nil {
in, out := &in.BoolPtrField, &out.BoolPtrField
*out = new(bool)
**out = **in
}
if in.IntPtrField != nil {
in, out := &in.IntPtrField, &out.IntPtrField
*out = new(int)
**out = **in
}
if in.StringPtrField != nil {
in, out := &in.StringPtrField, &out.StringPtrField
*out = new(string)
**out = **in
}
if in.FloatPtrField != nil {
in, out := &in.FloatPtrField, &out.FloatPtrField
*out = new(float64)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_PrimitivePointers_Alias.
func (in *Struct_PrimitivePointers_Alias) DeepCopy() *Struct_PrimitivePointers_Alias {
if in == nil {
return nil
}
out := new(Struct_PrimitivePointers_Alias)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Primitives) DeepCopyInto(out *Struct_Primitives) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Primitives.
func (in *Struct_Primitives) DeepCopy() *Struct_Primitives {
if in == nil {
return nil
}
out := new(Struct_Primitives)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Primitives_Alias) DeepCopyInto(out *Struct_Primitives_Alias) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Primitives_Alias.
func (in *Struct_Primitives_Alias) DeepCopy() *Struct_Primitives_Alias {
if in == nil {
return nil
}
out := new(Struct_Primitives_Alias)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Slices) DeepCopyInto(out *Struct_Slices) {
*out = *in
if in.SliceBoolField != nil {
in, out := &in.SliceBoolField, &out.SliceBoolField
*out = make([]bool, len(*in))
copy(*out, *in)
}
if in.SliceByteField != nil {
in, out := &in.SliceByteField, &out.SliceByteField
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.SliceIntField != nil {
in, out := &in.SliceIntField, &out.SliceIntField
*out = make([]int, len(*in))
copy(*out, *in)
}
if in.SliceStringField != nil {
in, out := &in.SliceStringField, &out.SliceStringField
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.SliceFloatField != nil {
in, out := &in.SliceFloatField, &out.SliceFloatField
*out = make([]float64, len(*in))
copy(*out, *in)
}
if in.SliceStructPrimitivesField != nil {
in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField
*out = make([]Struct_Primitives, len(*in))
copy(*out, *in)
}
if in.SliceStructPrimitivesAliasField != nil {
in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField
*out = make([]Struct_Primitives_Alias, len(*in))
copy(*out, *in)
}
if in.SliceStructPrimitivePointersField != nil {
in, out := &in.SliceStructPrimitivePointersField, &out.SliceStructPrimitivePointersField
*out = make([]Struct_PrimitivePointers, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.SliceStructPrimitivePointersAliasField != nil {
in, out := &in.SliceStructPrimitivePointersAliasField, &out.SliceStructPrimitivePointersAliasField
*out = make([]Struct_PrimitivePointers_Alias, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.SliceSliceIntField != nil {
in, out := &in.SliceSliceIntField, &out.SliceSliceIntField
*out = make([][]int, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = make([]int, len(*in))
copy(*out, *in)
}
}
}
if in.SliceManualStructField != nil {
in, out := &in.SliceManualStructField, &out.SliceManualStructField
*out = make([]ManualStruct, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
out.ManualSliceField = in.ManualSliceField.DeepCopy()
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Slices.
func (in *Struct_Slices) DeepCopy() *Struct_Slices {
if in == nil {
return nil
}
out := new(Struct_Slices)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Slices_Alias) DeepCopyInto(out *Struct_Slices_Alias) {
*out = *in
if in.SliceBoolField != nil {
in, out := &in.SliceBoolField, &out.SliceBoolField
*out = make([]bool, len(*in))
copy(*out, *in)
}
if in.SliceByteField != nil {
in, out := &in.SliceByteField, &out.SliceByteField
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.SliceIntField != nil {
in, out := &in.SliceIntField, &out.SliceIntField
*out = make([]int, len(*in))
copy(*out, *in)
}
if in.SliceStringField != nil {
in, out := &in.SliceStringField, &out.SliceStringField
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.SliceFloatField != nil {
in, out := &in.SliceFloatField, &out.SliceFloatField
*out = make([]float64, len(*in))
copy(*out, *in)
}
if in.SliceStructPrimitivesField != nil {
in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField
*out = make([]Struct_Primitives, len(*in))
copy(*out, *in)
}
if in.SliceStructPrimitivesAliasField != nil {
in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField
*out = make([]Struct_Primitives_Alias, len(*in))
copy(*out, *in)
}
if in.SliceStructPrimitivePointersField != nil {
in, out := &in.SliceStructPrimitivePointersField, &out.SliceStructPrimitivePointersField
*out = make([]Struct_PrimitivePointers, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.SliceStructPrimitivePointersAliasField != nil {
in, out := &in.SliceStructPrimitivePointersAliasField, &out.SliceStructPrimitivePointersAliasField
*out = make([]Struct_PrimitivePointers_Alias, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.SliceSliceIntField != nil {
in, out := &in.SliceSliceIntField, &out.SliceSliceIntField
*out = make([][]int, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = make([]int, len(*in))
copy(*out, *in)
}
}
}
if in.SliceManualStructField != nil {
in, out := &in.SliceManualStructField, &out.SliceManualStructField
*out = make([]ManualStruct, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
out.ManualSliceField = in.ManualSliceField.DeepCopy()
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Slices_Alias.
func (in *Struct_Slices_Alias) DeepCopy() *Struct_Slices_Alias {
if in == nil {
return nil
}
out := new(Struct_Slices_Alias)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Struct_PrimitivePointers) DeepCopyInto(out *Struct_Struct_PrimitivePointers) {
*out = *in
in.StructField.DeepCopyInto(&out.StructField)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Struct_PrimitivePointers.
func (in *Struct_Struct_PrimitivePointers) DeepCopy() *Struct_Struct_PrimitivePointers {
if in == nil {
return nil
}
out := new(Struct_Struct_PrimitivePointers)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Struct_Primitives) DeepCopyInto(out *Struct_Struct_Primitives) {
*out = *in
out.StructField = in.StructField
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Struct_Primitives.
func (in *Struct_Struct_Primitives) DeepCopy() *Struct_Struct_Primitives {
if in == nil {
return nil
}
out := new(Struct_Struct_Primitives)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Struct_Struct_Slices) DeepCopyInto(out *Struct_Struct_Slices) {
*out = *in
in.StructField.DeepCopyInto(&out.StructField)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct_Struct_Slices.
func (in *Struct_Struct_Slices) DeepCopy() *Struct_Struct_Slices {
if in == nil {
return nil
}
out := new(Struct_Struct_Slices)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1 @@
defaulter-gen

View File

@@ -0,0 +1,12 @@
{
"Rules": [
{
"SelectorRegexp": "k8s[.]io",
"AllowedPrefixes": [
"k8s.io/gengo",
"k8s.io/kubernetes/third_party/forked/golang",
"k8s.io/apimachinery/pkg/runtime"
]
}
]
}

15
vendor/k8s.io/gengo/examples/defaulter-gen/Makefile generated vendored Normal file
View File

@@ -0,0 +1,15 @@
TOOL=defaulter-gen
test:
@if ! git diff --quiet HEAD; then \
echo "FAIL: git client is not clean"; \
false; \
fi
@go build -o /tmp/$(TOOL)
@PKGS=$$(cd _output_tests; go list ./... | paste -sd' ' -); \
/tmp/$(TOOL) --logtostderr --v=4 -i $$(echo $$PKGS | sed 's/ /,/g') -O zz_generated
@if ! git diff --quiet HEAD; then \
echo "FAIL: output files changed"; \
git diff; \
false; \
fi

2
vendor/k8s.io/gengo/examples/defaulter-gen/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,2 @@
approvers:
- smarterclayton

View File

@@ -0,0 +1,20 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:defaulter-gen=covers
// This is a test package.
package empty // import "k8s.io/gengo/examples/defaulter-gen/_output_tests/empty"

View File

@@ -0,0 +1,29 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package empty
// Only test
type Ttest struct {
BoolField bool
IntField int
StringField string
FloatField float64
}
type TypeMeta struct {
Fortest bool
}

View File

@@ -0,0 +1,32 @@
// +build !ignore_autogenerated
/*
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 defaulter-gen. DO NOT EDIT.
package empty
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@@ -0,0 +1,32 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pointer
import (
"k8s.io/apimachinery/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
func SetDefaults_Tpointer(obj *Tpointer) {
if obj.BoolField == nil {
obj.BoolField = new(bool)
*obj.BoolField = true
}
}

View File

@@ -0,0 +1,20 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:defaulter-gen=TypeMeta
// This is a test package.
package pointer // import "k8s.io/gengo/examples/defaulter-gen/_output_tests/pointer"

View File

@@ -0,0 +1,33 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pointer
import (
"k8s.io/gengo/examples/defaulter-gen/_output_tests/empty"
)
type Tpointer struct {
empty.TypeMeta
BoolField *bool
}
// Only test
type Ttest struct {
empty.TypeMeta
NTP Tpointer
Tp *Tpointer
}

View File

@@ -0,0 +1,45 @@
// +build !ignore_autogenerated
/*
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 defaulter-gen. DO NOT EDIT.
package pointer
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&Tpointer{}, func(obj interface{}) { SetObjectDefaults_Tpointer(obj.(*Tpointer)) })
scheme.AddTypeDefaultingFunc(&Ttest{}, func(obj interface{}) { SetObjectDefaults_Ttest(obj.(*Ttest)) })
return nil
}
func SetObjectDefaults_Tpointer(in *Tpointer) {
SetDefaults_Tpointer(in)
}
func SetObjectDefaults_Ttest(in *Ttest) {
SetObjectDefaults_Tpointer(&in.NTP)
if in.Tp != nil {
SetObjectDefaults_Tpointer(in.Tp)
}
}

View File

@@ -0,0 +1,32 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package slices
import (
"k8s.io/apimachinery/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
func SetDefaults_Ttest(obj *Ttest) {
if obj.BoolField == nil {
obj.BoolField = new(bool)
*obj.BoolField = true
}
}

View File

@@ -0,0 +1,20 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:defaulter-gen=TypeMeta
// This is a test package.
package slices // import "k8s.io/gengo/examples/defaulter-gen/_output_tests/slices"

View File

@@ -0,0 +1,37 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package slices
import (
"k8s.io/gengo/examples/defaulter-gen/_output_tests/empty"
)
// Only test
type Ttest struct {
empty.TypeMeta
BoolField *bool
}
type TtestList struct {
empty.TypeMeta
Items []Ttest
}
type TtestPointerList struct {
empty.TypeMeta
Items []*Ttest
}

View File

@@ -0,0 +1,55 @@
// +build !ignore_autogenerated
/*
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 defaulter-gen. DO NOT EDIT.
package slices
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&Ttest{}, func(obj interface{}) { SetObjectDefaults_Ttest(obj.(*Ttest)) })
scheme.AddTypeDefaultingFunc(&TtestList{}, func(obj interface{}) { SetObjectDefaults_TtestList(obj.(*TtestList)) })
scheme.AddTypeDefaultingFunc(&TtestPointerList{}, func(obj interface{}) { SetObjectDefaults_TtestPointerList(obj.(*TtestPointerList)) })
return nil
}
func SetObjectDefaults_Ttest(in *Ttest) {
SetDefaults_Ttest(in)
}
func SetObjectDefaults_TtestList(in *TtestList) {
for i := range in.Items {
a := &in.Items[i]
SetObjectDefaults_Ttest(a)
}
}
func SetObjectDefaults_TtestPointerList(in *TtestPointerList) {
for i := range in.Items {
a := in.Items[i]
if a != nil {
SetObjectDefaults_Ttest(a)
}
}
}

View File

@@ -0,0 +1,32 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package wholepkg
import (
"k8s.io/apimachinery/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
func SetDefaults_Struct_Primitives(obj *Struct_Primitives) {
if obj.BoolField == nil {
obj.BoolField = new(bool)
*obj.BoolField = true
}
}

View File

@@ -0,0 +1,20 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:defaulter-gen=TypeMeta
// This is a test package.
package wholepkg // import "k8s.io/gengo/examples/defaulter-gen/_output_tests/wholepkg"

View File

@@ -0,0 +1,74 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package wholepkg
import (
"k8s.io/gengo/examples/defaulter-gen/_output_tests/empty"
)
// Only primitives
type Struct_Primitives struct {
empty.TypeMeta
BoolField *bool
IntField *int
StringField *string
FloatField *float64
}
type Struct_Primitives_Alias Struct_Primitives
type Struct_Struct_Primitives struct {
empty.TypeMeta
StructField Struct_Primitives
}
//Pointer
type Struct_Pointer struct {
empty.TypeMeta
PointerStructPrimitivesField Struct_Primitives
PointerPointerStructPrimitivesField *Struct_Primitives
PointerStructPrimitivesAliasField Struct_Primitives_Alias
PointerPointerStructPrimitivesAliasField Struct_Primitives_Alias
PointerStructStructPrimitives Struct_Struct_Primitives
PointerPointerStructStructPrimitives *Struct_Struct_Primitives
}
// Slices
type Struct_Slices struct {
empty.TypeMeta
SliceStructPrimitivesField []Struct_Primitives
SlicePointerStructPrimitivesField []*Struct_Primitives
SliceStructPrimitivesAliasField []Struct_Primitives_Alias
SlicePointerStructPrimitivesAliasField []*Struct_Primitives_Alias
SliceStructStructPrimitives []Struct_Struct_Primitives
SlicePointerStructStructPrimitives []*Struct_Struct_Primitives
}
// Everything
type Struct_Everything struct {
empty.TypeMeta
BoolPtrField *bool
IntPtrField *int
StringPtrField *string
FloatPtrField *float64
PointerStructField Struct_Pointer
SliceBoolField []bool
SliceByteField []byte
SliceIntField []int
SliceStringField []string
SliceFloatField []float64
SlicesStructField Struct_Slices
}

View File

@@ -0,0 +1,84 @@
// +build !ignore_autogenerated
/*
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 defaulter-gen. DO NOT EDIT.
package wholepkg
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&Struct_Everything{}, func(obj interface{}) { SetObjectDefaults_Struct_Everything(obj.(*Struct_Everything)) })
scheme.AddTypeDefaultingFunc(&Struct_Pointer{}, func(obj interface{}) { SetObjectDefaults_Struct_Pointer(obj.(*Struct_Pointer)) })
scheme.AddTypeDefaultingFunc(&Struct_Primitives{}, func(obj interface{}) { SetObjectDefaults_Struct_Primitives(obj.(*Struct_Primitives)) })
scheme.AddTypeDefaultingFunc(&Struct_Slices{}, func(obj interface{}) { SetObjectDefaults_Struct_Slices(obj.(*Struct_Slices)) })
scheme.AddTypeDefaultingFunc(&Struct_Struct_Primitives{}, func(obj interface{}) { SetObjectDefaults_Struct_Struct_Primitives(obj.(*Struct_Struct_Primitives)) })
return nil
}
func SetObjectDefaults_Struct_Everything(in *Struct_Everything) {
SetObjectDefaults_Struct_Pointer(&in.PointerStructField)
SetObjectDefaults_Struct_Slices(&in.SlicesStructField)
}
func SetObjectDefaults_Struct_Pointer(in *Struct_Pointer) {
SetObjectDefaults_Struct_Primitives(&in.PointerStructPrimitivesField)
if in.PointerPointerStructPrimitivesField != nil {
SetObjectDefaults_Struct_Primitives(in.PointerPointerStructPrimitivesField)
}
SetObjectDefaults_Struct_Struct_Primitives(&in.PointerStructStructPrimitives)
if in.PointerPointerStructStructPrimitives != nil {
SetObjectDefaults_Struct_Struct_Primitives(in.PointerPointerStructStructPrimitives)
}
}
func SetObjectDefaults_Struct_Primitives(in *Struct_Primitives) {
SetDefaults_Struct_Primitives(in)
}
func SetObjectDefaults_Struct_Slices(in *Struct_Slices) {
for i := range in.SliceStructPrimitivesField {
a := &in.SliceStructPrimitivesField[i]
SetObjectDefaults_Struct_Primitives(a)
}
for i := range in.SlicePointerStructPrimitivesField {
a := in.SlicePointerStructPrimitivesField[i]
if a != nil {
SetObjectDefaults_Struct_Primitives(a)
}
}
for i := range in.SliceStructStructPrimitives {
a := &in.SliceStructStructPrimitives[i]
SetObjectDefaults_Struct_Struct_Primitives(a)
}
for i := range in.SlicePointerStructStructPrimitives {
a := in.SlicePointerStructStructPrimitives[i]
if a != nil {
SetObjectDefaults_Struct_Struct_Primitives(a)
}
}
}
func SetObjectDefaults_Struct_Struct_Primitives(in *Struct_Struct_Primitives) {
SetObjectDefaults_Struct_Primitives(&in.StructField)
}

View 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"
"github.com/golang/glog"
)
// 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 {
glog.Errorf("Malformed function: %#v", f)
continue
}
if f.Underlying.Signature == nil {
glog.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
glog.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
glog.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
glog.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 {
glog.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 {
glog.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
glog.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 {
glog.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.
glog.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 {
glog.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 {
glog.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
glog.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") {
glog.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 {
//glog.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
}
glog.V(5).Infof("generating for type %v", t)
callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true)
if callTree == nil {
glog.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))
glog.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, ", ")
}

75
vendor/k8s.io/gengo/examples/defaulter-gen/main.go generated vendored Normal file
View File

@@ -0,0 +1,75 @@
/*
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.
*/
// defaulter-gen is a tool for auto-generating Defaulter functions.
//
// Given a list of input directories, it will scan for top level types
// and generate efficient defaulters for an entire object from the sum
// of the SetDefault_* methods contained in the object tree.
//
// Generation is governed by comment tags in the source. Any package may
// request defaulter generation by including one or more comment tags at
// the package comment level:
//
// // +k8s:defaulter-gen=<field-name-to-flag>
//
// which will create defaulters for any type that contains the provided
// field name (if the type has defaulters). Any type may request explicit
// defaulting by providing the comment tag:
//
// // +k8s:defaulter-gen=true|false
//
// An existing defaulter method (`SetDefaults_TYPE`) can provide the
// comment tag:
//
// // +k8s:defaulter-gen=covers
//
// to indicate that the defaulter does not or should not call any nested
// defaulters.
package main
import (
"k8s.io/gengo/args"
"k8s.io/gengo/examples/defaulter-gen/generators"
"github.com/golang/glog"
"github.com/spf13/pflag"
)
func main() {
arguments := args.Default()
// Override defaults.
arguments.OutputFileBaseName = "defaulter_generated"
// Custom args.
customArgs := &generators.CustomArgs{
ExtraPeerDirs: []string{},
}
pflag.CommandLine.StringSliceVar(&customArgs.ExtraPeerDirs, "extra-peer-dirs", customArgs.ExtraPeerDirs,
"Comma-separated list of import paths which are considered, after tag-specified peers, for conversions.")
arguments.CustomArgs = customArgs
// Run it.
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
glog.V(2).Info("Completed successfully.")
}

View File

@@ -0,0 +1 @@
go-to-protobuf

View File

@@ -0,0 +1,11 @@
{
"Rules": [
{
"SelectorRegexp": "k8s[.]io",
"AllowedPrefixes": [
"k8s.io/gengo",
"k8s.io/kubernetes/third_party/forked/golang"
]
}
]
}

2
vendor/k8s.io/gengo/examples/go-to-protobuf/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,2 @@
approvers:
- smarterclayton

View File

@@ -0,0 +1,24 @@
# 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.
# This file creates a standard build environment for building Kubernetes
FROM k8s.gcr.io/kube-cross:KUBE_BUILD_IMAGE_CROSS_TAG
# Mark this as a kube-build container
RUN touch /kube-build-image
WORKDIR /go/src/k8s.io/kubernetes
# Install goimports tool
RUN go get golang.org/x/tools/cmd/goimports

36
vendor/k8s.io/gengo/examples/go-to-protobuf/main.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
/*
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.
*/
// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any
// existing IDL tags on the Go struct.
package main
import (
"k8s.io/gengo/examples/go-to-protobuf/protobuf"
flag "github.com/spf13/pflag"
)
var g = protobuf.New()
func init() {
g.BindFlags(flag.CommandLine)
}
func main() {
flag.Parse()
protobuf.Run(g)
}

View File

@@ -0,0 +1,306 @@
/*
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.
*/
// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any
// existing IDL tags on the Go struct.
package protobuf
import (
"bytes"
"fmt"
"log"
"os/exec"
"path/filepath"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/parser"
"k8s.io/gengo/types"
flag "github.com/spf13/pflag"
)
type Generator struct {
Common args.GeneratorArgs
Packages string
OutputBase string
ProtoImport []string
Conditional string
Clean bool
OnlyIDL bool
KeepGogoproto bool
SkipGeneratedRewrite bool
DropEmbeddedFields string
}
func New() *Generator {
sourceTree := args.DefaultSourceTree()
common := args.GeneratorArgs{
OutputBase: sourceTree,
GoHeaderFilePath: filepath.Join(sourceTree, "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt"),
}
defaultProtoImport := filepath.Join(sourceTree, "k8s.io", "kubernetes", "vendor", "github.com", "gogo", "protobuf", "protobuf")
return &Generator{
Common: common,
OutputBase: sourceTree,
ProtoImport: []string{defaultProtoImport},
Packages: strings.Join([]string{
`+k8s.io/kubernetes/pkg/util/intstr`,
`+k8s.io/kubernetes/pkg/api/resource`,
`+k8s.io/kubernetes/pkg/runtime`,
`+k8s.io/kubernetes/pkg/watch/versioned`,
`k8s.io/kubernetes/pkg/api/unversioned`,
`k8s.io/kubernetes/pkg/api/v1`,
`k8s.io/kubernetes/pkg/apis/policy/v1alpha1`,
`k8s.io/kubernetes/pkg/apis/extensions/v1beta1`,
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
`k8s.io/kubernetes/pkg/apis/authorization/v1beta1`,
`k8s.io/kubernetes/pkg/apis/batch/v1`,
`k8s.io/kubernetes/pkg/apis/batch/v2alpha1`,
`k8s.io/kubernetes/pkg/apis/apps/v1alpha1`,
`k8s.io/kubernetes/pkg/apis/authentication/v1beta1`,
`k8s.io/kubernetes/pkg/apis/rbac/v1alpha1`,
`k8s.io/kubernetes/federation/apis/federation/v1beta1`,
`k8s.io/kubernetes/pkg/apis/certificates/v1alpha1`,
`k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1`,
}, ","),
DropEmbeddedFields: "k8s.io/kubernetes/pkg/api/unversioned.TypeMeta",
}
}
func (g *Generator) BindFlags(flag *flag.FlagSet) {
flag.StringVarP(&g.Common.GoHeaderFilePath, "go-header-file", "h", g.Common.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
flag.BoolVar(&g.Common.VerifyOnly, "verify-only", g.Common.VerifyOnly, "If true, only verify existing output, do not write anything.")
flag.StringVarP(&g.Packages, "packages", "p", g.Packages, "comma-separated list of directories to get input types from. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.")
flag.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/")
flag.StringSliceVar(&g.ProtoImport, "proto-import", g.ProtoImport, "The search path for the core protobuf .protos, required, defaults to GODEPS on path.")
flag.StringVar(&g.Conditional, "conditional", g.Conditional, "An optional Golang build tag condition to add to the generated Go code")
flag.BoolVar(&g.Clean, "clean", g.Clean, "If true, remove all generated files for the specified Packages.")
flag.BoolVar(&g.OnlyIDL, "only-idl", g.OnlyIDL, "If true, only generate the IDL for each package.")
flag.BoolVar(&g.KeepGogoproto, "keep-gogoproto", g.KeepGogoproto, "If true, the generated IDL will contain gogoprotobuf extensions which are normally removed")
flag.BoolVar(&g.SkipGeneratedRewrite, "skip-generated-rewrite", g.SkipGeneratedRewrite, "If true, skip fixing up the generated.pb.go file (debugging only).")
flag.StringVar(&g.DropEmbeddedFields, "drop-embedded-fields", g.DropEmbeddedFields, "Comma-delimited list of embedded Go types to omit from generated protobufs")
}
func Run(g *Generator) {
if g.Common.VerifyOnly {
g.OnlyIDL = true
g.Clean = false
}
b := parser.New()
b.AddBuildTags("proto")
omitTypes := map[types.Name]struct{}{}
for _, t := range strings.Split(g.DropEmbeddedFields, ",") {
name := types.Name{}
if i := strings.LastIndex(t, "."); i != -1 {
name.Package, name.Name = t[:i], t[i+1:]
} else {
name.Name = t
}
if len(name.Name) == 0 {
log.Fatalf("--drop-embedded-types requires names in the form of [GOPACKAGE.]TYPENAME: %v", t)
}
omitTypes[name] = struct{}{}
}
boilerplate, err := g.Common.LoadGoBoilerplate()
if err != nil {
log.Fatalf("Failed loading boilerplate: %v", err)
}
protobufNames := NewProtobufNamer()
outputPackages := generator.Packages{}
for _, d := range strings.Split(g.Packages, ",") {
generateAllTypes, outputPackage := true, true
switch {
case strings.HasPrefix(d, "+"):
d = d[1:]
generateAllTypes = false
case strings.HasPrefix(d, "-"):
d = d[1:]
outputPackage = false
}
name := protoSafePackage(d)
parts := strings.SplitN(d, "=", 2)
if len(parts) > 1 {
d = parts[0]
name = parts[1]
}
p := newProtobufPackage(d, name, generateAllTypes, omitTypes)
header := append([]byte{}, boilerplate...)
header = append(header, p.HeaderText...)
p.HeaderText = header
protobufNames.Add(p)
if outputPackage {
outputPackages = append(outputPackages, p)
}
}
if !g.Common.VerifyOnly {
for _, p := range outputPackages {
if err := p.(*protobufPackage).Clean(g.OutputBase); err != nil {
log.Fatalf("Unable to clean package %s: %v", p.Name(), err)
}
}
}
if g.Clean {
return
}
for _, p := range protobufNames.List() {
if err := b.AddDir(p.Path()); err != nil {
log.Fatalf("Unable to add directory %q: %v", p.Path(), err)
}
}
c, err := generator.NewContext(
b,
namer.NameSystems{
"public": namer.NewPublicNamer(3),
"proto": protobufNames,
},
"public",
)
if err != nil {
log.Fatalf("Failed making a context: %v", err)
}
c.Verify = g.Common.VerifyOnly
c.FileTypes["protoidl"] = NewProtoFile()
if err := protobufNames.AssignTypesToPackages(c); err != nil {
log.Fatalf("Failed to identify Common types: %v", err)
}
if err := c.ExecutePackages(g.OutputBase, outputPackages); err != nil {
log.Fatalf("Failed executing generator: %v", err)
}
if g.OnlyIDL {
return
}
if _, err := exec.LookPath("protoc"); err != nil {
log.Fatalf("Unable to find 'protoc': %v", err)
}
searchArgs := []string{"-I", ".", "-I", g.OutputBase}
if len(g.ProtoImport) != 0 {
for _, s := range g.ProtoImport {
searchArgs = append(searchArgs, "-I", s)
}
}
args := append(searchArgs, fmt.Sprintf("--gogo_out=%s", g.OutputBase))
buf := &bytes.Buffer{}
if len(g.Conditional) > 0 {
fmt.Fprintf(buf, "// +build %s\n\n", g.Conditional)
}
buf.Write(boilerplate)
for _, outputPackage := range outputPackages {
p := outputPackage.(*protobufPackage)
path := filepath.Join(g.OutputBase, p.ImportPath())
outputPath := filepath.Join(g.OutputBase, p.OutputPath())
// generate the gogoprotobuf protoc
cmd := exec.Command("protoc", append(args, path)...)
out, err := cmd.CombinedOutput()
if len(out) > 0 {
log.Printf(string(out))
}
if err != nil {
log.Println(strings.Join(cmd.Args, " "))
log.Fatalf("Unable to generate protoc on %s: %v", p.PackageName, err)
}
if g.SkipGeneratedRewrite {
continue
}
// alter the generated protobuf file to remove the generated types (but leave the serializers) and rewrite the
// package statement to match the desired package name
if err := RewriteGeneratedGogoProtobufFile(outputPath, p.ExtractGeneratedType, p.OptionalTypeName, buf.Bytes()); err != nil {
log.Fatalf("Unable to rewrite generated %s: %v", outputPath, err)
}
// sort imports
cmd = exec.Command("goimports", "-w", outputPath)
out, err = cmd.CombinedOutput()
if len(out) > 0 {
log.Printf(string(out))
}
if err != nil {
log.Println(strings.Join(cmd.Args, " "))
log.Fatalf("Unable to rewrite imports for %s: %v", p.PackageName, err)
}
// format and simplify the generated file
cmd = exec.Command("gofmt", "-s", "-w", outputPath)
out, err = cmd.CombinedOutput()
if len(out) > 0 {
log.Printf(string(out))
}
if err != nil {
log.Println(strings.Join(cmd.Args, " "))
log.Fatalf("Unable to apply gofmt for %s: %v", p.PackageName, err)
}
}
if g.SkipGeneratedRewrite {
return
}
if !g.KeepGogoproto {
// generate, but do so without gogoprotobuf extensions
for _, outputPackage := range outputPackages {
p := outputPackage.(*protobufPackage)
p.OmitGogo = true
}
if err := c.ExecutePackages(g.OutputBase, outputPackages); err != nil {
log.Fatalf("Failed executing generator: %v", err)
}
}
for _, outputPackage := range outputPackages {
p := outputPackage.(*protobufPackage)
if len(p.StructTags) == 0 {
continue
}
pattern := filepath.Join(g.OutputBase, p.PackagePath, "*.go")
files, err := filepath.Glob(pattern)
if err != nil {
log.Fatalf("Can't glob pattern %q: %v", pattern, err)
}
for _, s := range files {
if strings.HasSuffix(s, "_test.go") {
continue
}
if err := RewriteTypesWithProtobufStructTags(s, p.StructTags); err != nil {
log.Fatalf("Unable to rewrite with struct tags %s: %v", s, err)
}
}
}
}

View File

@@ -0,0 +1,762 @@
/*
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 protobuf
import (
"fmt"
"io"
"log"
"reflect"
"sort"
"strconv"
"strings"
"github.com/golang/glog"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// genProtoIDL produces a .proto IDL.
type genProtoIDL struct {
generator.DefaultGen
localPackage types.Name
localGoPackage types.Name
imports namer.ImportTracker
generateAll bool
omitGogo bool
omitFieldTypes map[types.Name]struct{}
}
func (g *genProtoIDL) PackageVars(c *generator.Context) []string {
if g.omitGogo {
return []string{
fmt.Sprintf("option go_package = %q;", g.localGoPackage.Name),
}
}
return []string{
"option (gogoproto.marshaler_all) = true;",
"option (gogoproto.sizer_all) = true;",
"option (gogoproto.goproto_stringer_all) = false;",
"option (gogoproto.stringer_all) = true;",
"option (gogoproto.unmarshaler_all) = true;",
"option (gogoproto.goproto_unrecognized_all) = false;",
"option (gogoproto.goproto_enum_prefix_all) = false;",
"option (gogoproto.goproto_getters_all) = false;",
fmt.Sprintf("option go_package = %q;", g.localGoPackage.Name),
}
}
func (g *genProtoIDL) Filename() string { return g.OptionalName + ".proto" }
func (g *genProtoIDL) FileType() string { return "protoidl" }
func (g *genProtoIDL) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
// The local namer returns the correct protobuf name for a proto type
// in the context of a package
"local": localNamer{g.localPackage},
}
}
// Filter ignores types that are identified as not exportable.
func (g *genProtoIDL) Filter(c *generator.Context, t *types.Type) bool {
tagVals := types.ExtractCommentTags("+", t.CommentLines)["protobuf"]
if tagVals != nil {
if tagVals[0] == "false" {
// Type specified "false".
return false
}
if tagVals[0] == "true" {
// Type specified "true".
return true
}
glog.Fatalf(`Comment tag "protobuf" must be true or false, found: %q`, tagVals[0])
}
if !g.generateAll {
// We're not generating everything.
return false
}
seen := map[*types.Type]bool{}
ok := isProtoable(seen, t)
return ok
}
func isProtoable(seen map[*types.Type]bool, t *types.Type) bool {
if seen[t] {
// be optimistic in the case of type cycles.
return true
}
seen[t] = true
switch t.Kind {
case types.Builtin:
return true
case types.Alias:
return isProtoable(seen, t.Underlying)
case types.Slice, types.Pointer:
return isProtoable(seen, t.Elem)
case types.Map:
return isProtoable(seen, t.Key) && isProtoable(seen, t.Elem)
case types.Struct:
for _, m := range t.Members {
if isProtoable(seen, m.Type) {
return true
}
}
return false
case types.Func, types.Chan:
return false
case types.DeclarationOf, types.Unknown, types.Unsupported:
return false
case types.Interface:
return false
default:
log.Printf("WARNING: type %q is not portable: %s", t.Kind, t.Name)
return false
}
}
// isOptionalAlias should return true if the specified type has an underlying type
// (is an alias) of a map or slice and has the comment tag protobuf.nullable=true,
// indicating that the type should be nullable in protobuf.
func isOptionalAlias(t *types.Type) bool {
if t.Underlying == nil || (t.Underlying.Kind != types.Map && t.Underlying.Kind != types.Slice) {
return false
}
if extractBoolTagOrDie("protobuf.nullable", t.CommentLines) == false {
return false
}
return true
}
func (g *genProtoIDL) Imports(c *generator.Context) (imports []string) {
lines := []string{}
// TODO: this could be expressed more cleanly
for _, line := range g.imports.ImportLines() {
if g.omitGogo && line == "github.com/gogo/protobuf/gogoproto/gogo.proto" {
continue
}
lines = append(lines, line)
}
return lines
}
// GenerateType makes the body of a file implementing a set for type t.
func (g *genProtoIDL) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
b := bodyGen{
locator: &protobufLocator{
namer: c.Namers["proto"].(ProtobufFromGoNamer),
tracker: g.imports,
universe: c.Universe,
localGoPackage: g.localGoPackage.Package,
},
localPackage: g.localPackage,
omitGogo: g.omitGogo,
omitFieldTypes: g.omitFieldTypes,
t: t,
}
switch t.Kind {
case types.Alias:
return b.doAlias(sw)
case types.Struct:
return b.doStruct(sw)
default:
return b.unknown(sw)
}
}
// ProtobufFromGoNamer finds the protobuf name of a type (and its package, and
// the package path) from its Go name.
type ProtobufFromGoNamer interface {
GoNameToProtoName(name types.Name) types.Name
}
type ProtobufLocator interface {
ProtoTypeFor(t *types.Type) (*types.Type, error)
GoTypeForName(name types.Name) *types.Type
CastTypeName(name types.Name) string
}
type protobufLocator struct {
namer ProtobufFromGoNamer
tracker namer.ImportTracker
universe types.Universe
localGoPackage string
}
// CastTypeName returns the cast type name of a Go type
// TODO: delegate to a new localgo namer?
func (p protobufLocator) CastTypeName(name types.Name) string {
if name.Package == p.localGoPackage {
return name.Name
}
return name.String()
}
func (p protobufLocator) GoTypeForName(name types.Name) *types.Type {
if len(name.Package) == 0 {
name.Package = p.localGoPackage
}
return p.universe.Type(name)
}
// ProtoTypeFor locates a Protobuf type for the provided Go type (if possible).
func (p protobufLocator) ProtoTypeFor(t *types.Type) (*types.Type, error) {
switch {
// we've already converted the type, or it's a map
case t.Kind == types.Protobuf || t.Kind == types.Map:
p.tracker.AddType(t)
return t, nil
}
// it's a fundamental type
if t, ok := isFundamentalProtoType(t); ok {
p.tracker.AddType(t)
return t, nil
}
// it's a message
if t.Kind == types.Struct || isOptionalAlias(t) {
t := &types.Type{
Name: p.namer.GoNameToProtoName(t.Name),
Kind: types.Protobuf,
CommentLines: t.CommentLines,
}
p.tracker.AddType(t)
return t, nil
}
return nil, errUnrecognizedType
}
type bodyGen struct {
locator ProtobufLocator
localPackage types.Name
omitGogo bool
omitFieldTypes map[types.Name]struct{}
t *types.Type
}
func (b bodyGen) unknown(sw *generator.SnippetWriter) error {
return fmt.Errorf("not sure how to generate: %#v", b.t)
}
func (b bodyGen) doAlias(sw *generator.SnippetWriter) error {
if !isOptionalAlias(b.t) {
return nil
}
var kind string
switch b.t.Underlying.Kind {
case types.Map:
kind = "map"
default:
kind = "slice"
}
optional := &types.Type{
Name: b.t.Name,
Kind: types.Struct,
CommentLines: b.t.CommentLines,
SecondClosestCommentLines: b.t.SecondClosestCommentLines,
Members: []types.Member{
{
Name: "Items",
CommentLines: []string{fmt.Sprintf("items, if empty, will result in an empty %s\n", kind)},
Type: b.t.Underlying,
},
},
}
nested := b
nested.t = optional
return nested.doStruct(sw)
}
func (b bodyGen) doStruct(sw *generator.SnippetWriter) error {
if len(b.t.Name.Name) == 0 {
return nil
}
if namer.IsPrivateGoName(b.t.Name.Name) {
return nil
}
var alias *types.Type
var fields []protoField
options := []string{}
allOptions := types.ExtractCommentTags("+", b.t.CommentLines)
for k, v := range allOptions {
switch {
case strings.HasPrefix(k, "protobuf.options."):
key := strings.TrimPrefix(k, "protobuf.options.")
switch key {
case "marshal":
if v[0] == "false" {
if !b.omitGogo {
options = append(options,
"(gogoproto.marshaler) = false",
"(gogoproto.unmarshaler) = false",
"(gogoproto.sizer) = false",
)
}
}
default:
if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") {
if key == "(gogoproto.goproto_stringer)" && v[0] == "false" {
options = append(options, "(gogoproto.stringer) = false")
}
options = append(options, fmt.Sprintf("%s = %s", key, v[0]))
}
}
// protobuf.as allows a type to have the same message contents as another Go type
case k == "protobuf.as":
fields = nil
if alias = b.locator.GoTypeForName(types.Name{Name: v[0]}); alias == nil {
return fmt.Errorf("type %v references alias %q which does not exist", b.t, v[0])
}
// protobuf.embed instructs the generator to use the named type in this package
// as an embedded message.
case k == "protobuf.embed":
fields = []protoField{
{
Tag: 1,
Name: v[0],
Type: &types.Type{
Name: types.Name{
Name: v[0],
Package: b.localPackage.Package,
Path: b.localPackage.Path,
},
},
},
}
}
}
if alias == nil {
alias = b.t
}
// If we don't explicitly embed anything, generate fields by traversing fields.
if fields == nil {
memberFields, err := membersToFields(b.locator, alias, b.localPackage, b.omitFieldTypes)
if err != nil {
return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err)
}
fields = memberFields
}
out := sw.Out()
genComment(out, b.t.CommentLines, "")
sw.Do(`message $.Name.Name$ {
`, b.t)
if len(options) > 0 {
sort.Sort(sort.StringSlice(options))
for _, s := range options {
fmt.Fprintf(out, " option %s;\n", s)
}
fmt.Fprintln(out)
}
for i, field := range fields {
genComment(out, field.CommentLines, " ")
fmt.Fprintf(out, " ")
switch {
case field.Map:
case field.Repeated:
fmt.Fprintf(out, "repeated ")
case field.Required:
fmt.Fprintf(out, "required ")
default:
fmt.Fprintf(out, "optional ")
}
sw.Do(`$.Type|local$ $.Name$ = $.Tag$`, field)
if len(field.Extras) > 0 {
extras := []string{}
for k, v := range field.Extras {
if b.omitGogo && strings.HasPrefix(k, "(gogoproto.") {
continue
}
extras = append(extras, fmt.Sprintf("%s = %s", k, v))
}
sort.Sort(sort.StringSlice(extras))
if len(extras) > 0 {
fmt.Fprintf(out, " [")
fmt.Fprint(out, strings.Join(extras, ", "))
fmt.Fprintf(out, "]")
}
}
fmt.Fprintf(out, ";\n")
if i != len(fields)-1 {
fmt.Fprintf(out, "\n")
}
}
fmt.Fprintf(out, "}\n\n")
return nil
}
type protoField struct {
LocalPackage types.Name
Tag int
Name string
Type *types.Type
Map bool
Repeated bool
Optional bool
Required bool
Nullable bool
Extras map[string]string
CommentLines []string
}
var (
errUnrecognizedType = fmt.Errorf("did not recognize the provided type")
)
func isFundamentalProtoType(t *types.Type) (*types.Type, bool) {
// TODO: when we enable proto3, also include other fundamental types in the google.protobuf package
// switch {
// case t.Kind == types.Struct && t.Name == types.Name{Package: "time", Name: "Time"}:
// return &types.Type{
// Kind: types.Protobuf,
// Name: types.Name{Path: "google/protobuf/timestamp.proto", Package: "google.protobuf", Name: "Timestamp"},
// }, true
// }
switch t.Kind {
case types.Slice:
if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 {
return &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf}, true
}
case types.Builtin:
switch t.Name.Name {
case "string", "uint32", "int32", "uint64", "int64", "bool":
return &types.Type{Name: types.Name{Name: t.Name.Name}, Kind: types.Protobuf}, true
case "int":
return &types.Type{Name: types.Name{Name: "int64"}, Kind: types.Protobuf}, true
case "uint":
return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true
case "float64", "float":
return &types.Type{Name: types.Name{Name: "double"}, Kind: types.Protobuf}, true
case "float32":
return &types.Type{Name: types.Name{Name: "float"}, Kind: types.Protobuf}, true
case "uintptr":
return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true
}
// TODO: complex?
}
return t, false
}
func memberTypeToProtobufField(locator ProtobufLocator, field *protoField, t *types.Type) error {
var err error
switch t.Kind {
case types.Protobuf:
field.Type, err = locator.ProtoTypeFor(t)
case types.Builtin:
field.Type, err = locator.ProtoTypeFor(t)
case types.Map:
valueField := &protoField{}
if err := memberTypeToProtobufField(locator, valueField, t.Elem); err != nil {
return err
}
keyField := &protoField{}
if err := memberTypeToProtobufField(locator, keyField, t.Key); err != nil {
return err
}
// All other protobuf types have kind types.Protobuf, so setting types.Map
// here would be very misleading.
field.Type = &types.Type{
Kind: types.Protobuf,
Key: keyField.Type,
Elem: valueField.Type,
}
if !strings.HasPrefix(t.Name.Name, "map[") {
field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name))
}
if k, ok := keyField.Extras["(gogoproto.casttype)"]; ok {
field.Extras["(gogoproto.castkey)"] = k
}
if v, ok := valueField.Extras["(gogoproto.casttype)"]; ok {
field.Extras["(gogoproto.castvalue)"] = v
}
field.Map = true
case types.Pointer:
if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil {
return err
}
field.Nullable = true
case types.Alias:
if isOptionalAlias(t) {
field.Type, err = locator.ProtoTypeFor(t)
field.Nullable = true
} else {
if err := memberTypeToProtobufField(locator, field, t.Underlying); err != nil {
log.Printf("failed to alias: %s %s: err %v", t.Name, t.Underlying.Name, err)
return err
}
if field.Extras == nil {
field.Extras = make(map[string]string)
}
field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name))
}
case types.Slice:
if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 {
field.Type = &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf}
return nil
}
if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil {
return err
}
field.Repeated = true
case types.Struct:
if len(t.Name.Name) == 0 {
return errUnrecognizedType
}
field.Type, err = locator.ProtoTypeFor(t)
field.Nullable = false
default:
return errUnrecognizedType
}
return err
}
// protobufTagToField extracts information from an existing protobuf tag
func protobufTagToField(tag string, field *protoField, m types.Member, t *types.Type, localPackage types.Name) error {
if len(tag) == 0 || tag == "-" {
return nil
}
// protobuf:"bytes,3,opt,name=Id,customtype=github.com/gogo/protobuf/test.Uuid"
parts := strings.Split(tag, ",")
if len(parts) < 3 {
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, not enough segments\n", m.Name, t.Name)
}
protoTag, err := strconv.Atoi(parts[1])
if err != nil {
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, field ID is %q which is not an integer: %v\n", m.Name, t.Name, parts[1], err)
}
field.Tag = protoTag
// In general there is doesn't make sense to parse the protobuf tags to get the type,
// as all auto-generated once will have wire type "bytes", "varint" or "fixed64".
// However, sometimes we explicitly set them to have a custom serialization, e.g.:
// type Time struct {
// time.Time `protobuf:"Timestamp,1,req,name=time"`
// }
// to force the generator to use a given type (that we manually wrote serialization &
// deserialization methods for).
switch parts[0] {
case "varint", "fixed32", "fixed64", "bytes", "group":
default:
name := types.Name{}
if last := strings.LastIndex(parts[0], "."); last != -1 {
prefix := parts[0][:last]
name = types.Name{
Name: parts[0][last+1:],
Package: prefix,
Path: strings.Replace(prefix, ".", "/", -1),
}
} else {
name = types.Name{
Name: parts[0],
Package: localPackage.Package,
Path: localPackage.Path,
}
}
field.Type = &types.Type{
Name: name,
Kind: types.Protobuf,
}
}
protoExtra := make(map[string]string)
for i, extra := range parts[3:] {
parts := strings.SplitN(extra, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, tag %d should be key=value, got %q\n", m.Name, t.Name, i+4, extra)
}
switch parts[0] {
case "name":
protoExtra[parts[0]] = parts[1]
case "casttype", "castkey", "castvalue":
parts[0] = fmt.Sprintf("(gogoproto.%s)", parts[0])
protoExtra[parts[0]] = parts[1]
}
}
field.Extras = protoExtra
if name, ok := protoExtra["name"]; ok {
field.Name = name
delete(protoExtra, "name")
}
return nil
}
func membersToFields(locator ProtobufLocator, t *types.Type, localPackage types.Name, omitFieldTypes map[types.Name]struct{}) ([]protoField, error) {
fields := []protoField{}
for _, m := range t.Members {
if namer.IsPrivateGoName(m.Name) {
// skip private fields
continue
}
if _, ok := omitFieldTypes[types.Name{Name: m.Type.Name.Name, Package: m.Type.Name.Package}]; ok {
continue
}
tags := reflect.StructTag(m.Tags)
field := protoField{
LocalPackage: localPackage,
Tag: -1,
Extras: make(map[string]string),
}
protobufTag := tags.Get("protobuf")
if protobufTag == "-" {
continue
}
if err := protobufTagToField(protobufTag, &field, m, t, localPackage); err != nil {
return nil, err
}
// extract information from JSON field tag
if tag := tags.Get("json"); len(tag) > 0 {
parts := strings.Split(tag, ",")
if len(field.Name) == 0 && len(parts[0]) != 0 {
field.Name = parts[0]
}
if field.Tag == -1 && field.Name == "-" {
continue
}
}
if field.Type == nil {
if err := memberTypeToProtobufField(locator, &field, m.Type); err != nil {
return nil, fmt.Errorf("unable to embed type %q as field %q in %q: %v", m.Type, field.Name, t.Name, err)
}
}
if len(field.Name) == 0 {
field.Name = namer.IL(m.Name)
}
if field.Map && field.Repeated {
// maps cannot be repeated
field.Repeated = false
field.Nullable = true
}
if !field.Nullable {
field.Extras["(gogoproto.nullable)"] = "false"
}
if (field.Type.Name.Name == "bytes" && field.Type.Name.Package == "") || (field.Repeated && field.Type.Name.Package == "" && namer.IsPrivateGoName(field.Type.Name.Name)) {
delete(field.Extras, "(gogoproto.nullable)")
}
if field.Name != m.Name {
field.Extras["(gogoproto.customname)"] = strconv.Quote(m.Name)
}
field.CommentLines = m.CommentLines
fields = append(fields, field)
}
// assign tags
highest := 0
byTag := make(map[int]*protoField)
// fields are in Go struct order, which we preserve
for i := range fields {
field := &fields[i]
tag := field.Tag
if tag != -1 {
if existing, ok := byTag[tag]; ok {
return nil, fmt.Errorf("field %q and %q both have tag %d", field.Name, existing.Name, tag)
}
byTag[tag] = field
}
if tag > highest {
highest = tag
}
}
// starting from the highest observed tag, assign new field tags
for i := range fields {
field := &fields[i]
if field.Tag != -1 {
continue
}
highest++
field.Tag = highest
byTag[field.Tag] = field
}
return fields, nil
}
func genComment(out io.Writer, lines []string, indent string) {
for {
l := len(lines)
if l == 0 || len(lines[l-1]) != 0 {
break
}
lines = lines[:l-1]
}
for _, c := range lines {
fmt.Fprintf(out, "%s// %s\n", indent, c)
}
}
func formatProtoFile(source []byte) ([]byte, error) {
// TODO; Is there any protobuf formatter?
return source, nil
}
func assembleProtoFile(w io.Writer, f *generator.File) {
w.Write(f.Header)
fmt.Fprint(w, "syntax = 'proto2';\n\n")
if len(f.PackageName) > 0 {
fmt.Fprintf(w, "package %s;\n\n", f.PackageName)
}
if len(f.Imports) > 0 {
imports := []string{}
for i := range f.Imports {
imports = append(imports, i)
}
sort.Strings(imports)
for _, s := range imports {
fmt.Fprintf(w, "import %q;\n", s)
}
fmt.Fprint(w, "\n")
}
if f.Vars.Len() > 0 {
fmt.Fprintf(w, "%s\n", f.Vars.String())
}
w.Write(f.Body.Bytes())
}
func NewProtoFile() *generator.DefaultFileType {
return &generator.DefaultFileType{
Format: formatProtoFile,
Assemble: assembleProtoFile,
}
}

View File

@@ -0,0 +1,50 @@
/*
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 protobuf
import (
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
type ImportTracker struct {
namer.DefaultImportTracker
}
func NewImportTracker(local types.Name, typesToAdd ...*types.Type) *ImportTracker {
tracker := namer.NewDefaultImportTracker(local)
tracker.IsInvalidType = func(t *types.Type) bool { return t.Kind != types.Protobuf }
tracker.LocalName = func(name types.Name) string { return name.Package }
tracker.PrintImport = func(path, name string) string { return path }
tracker.AddTypes(typesToAdd...)
return &ImportTracker{
DefaultImportTracker: tracker,
}
}
// AddNullable ensures that support for the nullable Gogo-protobuf extension is added.
func (tracker *ImportTracker) AddNullable() {
tracker.AddType(&types.Type{
Kind: types.Protobuf,
Name: types.Name{
Name: "nullable",
Package: "gogoproto",
Path: "github.com/gogo/protobuf/gogoproto/gogo.proto",
},
})
}

View File

@@ -0,0 +1,186 @@
/*
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 protobuf
import (
"fmt"
"reflect"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
type localNamer struct {
localPackage types.Name
}
func (n localNamer) Name(t *types.Type) string {
if t.Key != nil && t.Elem != nil {
return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem))
}
if len(n.localPackage.Package) != 0 && n.localPackage.Package == t.Name.Package {
return t.Name.Name
}
return t.Name.String()
}
type protobufNamer struct {
packages []*protobufPackage
packagesByPath map[string]*protobufPackage
}
func NewProtobufNamer() *protobufNamer {
return &protobufNamer{
packagesByPath: make(map[string]*protobufPackage),
}
}
func (n *protobufNamer) Name(t *types.Type) string {
if t.Kind == types.Map {
return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem))
}
return t.Name.String()
}
func (n *protobufNamer) List() []generator.Package {
packages := make([]generator.Package, 0, len(n.packages))
for i := range n.packages {
packages = append(packages, n.packages[i])
}
return packages
}
func (n *protobufNamer) Add(p *protobufPackage) {
if _, ok := n.packagesByPath[p.PackagePath]; !ok {
n.packagesByPath[p.PackagePath] = p
n.packages = append(n.packages, p)
}
}
func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name {
if p, ok := n.packagesByPath[name.Package]; ok {
return types.Name{
Name: name.Name,
Package: p.PackageName,
Path: p.ImportPath(),
}
}
for _, p := range n.packages {
if _, ok := p.FilterTypes[name]; ok {
return types.Name{
Name: name.Name,
Package: p.PackageName,
Path: p.ImportPath(),
}
}
}
return types.Name{Name: name.Name}
}
func protoSafePackage(name string) string {
pkg := strings.Replace(name, "/", ".", -1)
return strings.Replace(pkg, "-", "_", -1)
}
type typeNameSet map[types.Name]*protobufPackage
// assignGoTypeToProtoPackage looks for Go and Protobuf types that are referenced by a type in
// a package. It will not recurse into protobuf types.
func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global typeNameSet, optional map[types.Name]struct{}) {
newT, isProto := isFundamentalProtoType(t)
if isProto {
t = newT
}
if otherP, ok := global[t.Name]; ok {
if _, ok := local[t.Name]; !ok {
p.Imports.AddType(&types.Type{
Kind: types.Protobuf,
Name: otherP.ProtoTypeName(),
})
}
return
}
global[t.Name] = p
if _, ok := local[t.Name]; ok {
return
}
// don't recurse into existing proto types
if isProto {
p.Imports.AddType(t)
return
}
local[t.Name] = p
for _, m := range t.Members {
if namer.IsPrivateGoName(m.Name) {
continue
}
field := &protoField{}
tag := reflect.StructTag(m.Tags).Get("protobuf")
if tag == "-" {
continue
}
if err := protobufTagToField(tag, field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil {
assignGoTypeToProtoPackage(p, field.Type, local, global, optional)
continue
}
assignGoTypeToProtoPackage(p, m.Type, local, global, optional)
}
// TODO: should methods be walked?
if t.Elem != nil {
assignGoTypeToProtoPackage(p, t.Elem, local, global, optional)
}
if t.Key != nil {
assignGoTypeToProtoPackage(p, t.Key, local, global, optional)
}
if t.Underlying != nil {
if t.Kind == types.Alias && isOptionalAlias(t) {
optional[t.Name] = struct{}{}
}
assignGoTypeToProtoPackage(p, t.Underlying, local, global, optional)
}
}
func (n *protobufNamer) AssignTypesToPackages(c *generator.Context) error {
global := make(typeNameSet)
for _, p := range n.packages {
local := make(typeNameSet)
optional := make(map[types.Name]struct{})
p.Imports = NewImportTracker(p.ProtoTypeName())
for _, t := range c.Order {
if t.Name.Package != p.PackagePath {
continue
}
assignGoTypeToProtoPackage(p, t, local, global, optional)
}
p.FilterTypes = make(map[types.Name]struct{})
p.LocalNames = make(map[string]struct{})
p.OptionalTypeNames = make(map[string]struct{})
for k, v := range local {
if v == p {
p.FilterTypes[k] = struct{}{}
p.LocalNames[k.Name] = struct{}{}
if _, ok := optional[k]; ok {
p.OptionalTypeNames[k.Name] = struct{}{}
}
}
}
}
return nil
}

View File

@@ -0,0 +1,50 @@
/*
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 protobuf
import "testing"
func TestProtoSafePackage(t *testing.T) {
tests := []struct {
pkg string
expected string
}{
{
pkg: "foo",
expected: "foo",
},
{
pkg: "foo/bar",
expected: "foo.bar",
},
{
pkg: "foo/bar/baz",
expected: "foo.bar.baz",
},
{
pkg: "foo/bar-baz/x/y-z/q",
expected: "foo.bar_baz.x.y_z.q",
},
}
for _, test := range tests {
actual := protoSafePackage(test.pkg)
if e, a := test.expected, actual; e != a {
t.Errorf("%s: expected %s, got %s", test.pkg, e, a)
}
}
}

View File

@@ -0,0 +1,211 @@
/*
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 protobuf
import (
"fmt"
"go/ast"
"log"
"os"
"path/filepath"
"reflect"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
)
func newProtobufPackage(packagePath, packageName string, generateAll bool, omitFieldTypes map[types.Name]struct{}) *protobufPackage {
pkg := &protobufPackage{
DefaultPackage: generator.DefaultPackage{
// The protobuf package name (foo.bar.baz)
PackageName: packageName,
// A path segment relative to the GOPATH root (foo/bar/baz)
PackagePath: packagePath,
HeaderText: []byte(
`
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
`),
PackageDocumentation: []byte(fmt.Sprintf(
`// Package %s is an autogenerated protobuf IDL.
`, packageName)),
},
GenerateAll: generateAll,
OmitFieldTypes: omitFieldTypes,
}
pkg.FilterFunc = pkg.filterFunc
pkg.GeneratorFunc = pkg.generatorFunc
return pkg
}
// protobufPackage contains the protobuf implementation of Package.
type protobufPackage struct {
generator.DefaultPackage
// If true, generate protobuf serializations for all public types.
// If false, only generate protobuf serializations for structs that
// request serialization.
GenerateAll bool
// A list of types to filter to; if not specified all types will be included.
FilterTypes map[types.Name]struct{}
// If true, omit any gogoprotobuf extensions not defined as types.
OmitGogo bool
// A list of field types that will be excluded from the output struct
OmitFieldTypes map[types.Name]struct{}
// A list of names that this package exports
LocalNames map[string]struct{}
// A list of type names in this package that will need marshaller rewriting
// to remove synthetic protobuf fields.
OptionalTypeNames map[string]struct{}
// A list of struct tags to generate onto named struct fields
StructTags map[string]map[string]string
// An import tracker for this package
Imports *ImportTracker
}
func (p *protobufPackage) Clean(outputBase string) error {
for _, s := range []string{p.ImportPath(), p.OutputPath()} {
if err := os.Remove(filepath.Join(outputBase, s)); err != nil && !os.IsNotExist(err) {
return err
}
}
return nil
}
func (p *protobufPackage) ProtoTypeName() types.Name {
return types.Name{
Name: p.Path(), // the go path "foo/bar/baz"
Package: p.Name(), // the protobuf package "foo.bar.baz"
Path: p.ImportPath(), // the path of the import to get the proto
}
}
func (p *protobufPackage) filterFunc(c *generator.Context, t *types.Type) bool {
switch t.Kind {
case types.Func, types.Chan:
return false
case types.Struct:
if t.Name.Name == "struct{}" {
return false
}
case types.Builtin:
return false
case types.Alias:
if !isOptionalAlias(t) {
return false
}
case types.Slice, types.Array, types.Map:
return false
case types.Pointer:
return false
}
if _, ok := isFundamentalProtoType(t); ok {
return false
}
_, ok := p.FilterTypes[t.Name]
return ok
}
func (p *protobufPackage) HasGoType(name string) bool {
_, ok := p.LocalNames[name]
return ok
}
func (p *protobufPackage) OptionalTypeName(name string) bool {
_, ok := p.OptionalTypeNames[name]
return ok
}
func (p *protobufPackage) ExtractGeneratedType(t *ast.TypeSpec) bool {
if !p.HasGoType(t.Name.Name) {
return false
}
switch s := t.Type.(type) {
case *ast.StructType:
for i, f := range s.Fields.List {
if len(f.Tag.Value) == 0 {
continue
}
tag := strings.Trim(f.Tag.Value, "`")
protobufTag := reflect.StructTag(tag).Get("protobuf")
if len(protobufTag) == 0 {
continue
}
if len(f.Names) > 1 {
log.Printf("WARNING: struct %s field %d %s: defined multiple names but single protobuf tag", t.Name.Name, i, f.Names[0].Name)
// TODO hard error?
}
if p.StructTags == nil {
p.StructTags = make(map[string]map[string]string)
}
m := p.StructTags[t.Name.Name]
if m == nil {
m = make(map[string]string)
p.StructTags[t.Name.Name] = m
}
m[f.Names[0].Name] = tag
}
default:
log.Printf("WARNING: unexpected Go AST type definition: %#v", t)
}
return true
}
func (p *protobufPackage) generatorFunc(c *generator.Context) []generator.Generator {
generators := []generator.Generator{}
p.Imports.AddNullable()
generators = append(generators, &genProtoIDL{
DefaultGen: generator.DefaultGen{
OptionalName: "generated",
},
localPackage: types.Name{Package: p.PackageName, Path: p.PackagePath},
localGoPackage: types.Name{Package: p.PackagePath, Name: p.GoPackageName()},
imports: p.Imports,
generateAll: p.GenerateAll,
omitGogo: p.OmitGogo,
omitFieldTypes: p.OmitFieldTypes,
})
return generators
}
func (p *protobufPackage) GoPackageName() string {
return filepath.Base(p.PackagePath)
}
func (p *protobufPackage) ImportPath() string {
return filepath.Join(p.PackagePath, "generated.proto")
}
func (p *protobufPackage) OutputPath() string {
return filepath.Join(p.PackagePath, "generated.pb.go")
}
var (
_ = generator.Package(&protobufPackage{})
)

View File

@@ -0,0 +1,452 @@
/*
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 protobuf
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/printer"
"go/token"
"io/ioutil"
"os"
"reflect"
"strings"
customreflect "k8s.io/kubernetes/third_party/forked/golang/reflect"
)
func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error {
fset := token.NewFileSet()
src, err := ioutil.ReadFile(name)
if err != nil {
return err
}
file, err := parser.ParseFile(fset, name, src, parser.DeclarationErrors|parser.ParseComments)
if err != nil {
return err
}
if err := rewriteFn(fset, file); err != nil {
return err
}
b := &bytes.Buffer{}
b.Write(header)
if err := printer.Fprint(b, fset, file); err != nil {
return err
}
body, err := format.Source(b.Bytes())
if err != nil {
return err
}
f, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Write(body); err != nil {
return err
}
return f.Close()
}
// ExtractFunc extracts information from the provided TypeSpec and returns true if the type should be
// removed from the destination file.
type ExtractFunc func(*ast.TypeSpec) bool
// OptionalFunc returns true if the provided local name is a type that has protobuf.nullable=true
// and should have its marshal functions adjusted to remove the 'Items' accessor.
type OptionalFunc func(name string) bool
func RewriteGeneratedGogoProtobufFile(name string, extractFn ExtractFunc, optionalFn OptionalFunc, header []byte) error {
return rewriteFile(name, header, func(fset *token.FileSet, file *ast.File) error {
cmap := ast.NewCommentMap(fset, file, file.Comments)
// transform methods that point to optional maps or slices
for _, d := range file.Decls {
rewriteOptionalMethods(d, optionalFn)
}
// remove types that are already declared
decls := []ast.Decl{}
for _, d := range file.Decls {
if dropExistingTypeDeclarations(d, extractFn) {
continue
}
if dropEmptyImportDeclarations(d) {
continue
}
decls = append(decls, d)
}
file.Decls = decls
// remove unmapped comments
file.Comments = cmap.Filter(file).Comments()
return nil
})
}
// rewriteOptionalMethods makes specific mutations to marshaller methods that belong to types identified
// as being "optional" (they may be nil on the wire). This allows protobuf to serialize a map or slice and
// properly discriminate between empty and nil (which is not possible in protobuf).
// TODO: move into upstream gogo-protobuf once https://github.com/gogo/protobuf/issues/181
// has agreement
func rewriteOptionalMethods(decl ast.Decl, isOptional OptionalFunc) {
switch t := decl.(type) {
case *ast.FuncDecl:
ident, ptr, ok := receiver(t)
if !ok {
return
}
// correct initialization of the form `m.Field = &OptionalType{}` to
// `m.Field = OptionalType{}`
if t.Name.Name == "Unmarshal" {
ast.Walk(optionalAssignmentVisitor{fn: isOptional}, t.Body)
}
if !isOptional(ident.Name) {
return
}
switch t.Name.Name {
case "Unmarshal":
ast.Walk(&optionalItemsVisitor{}, t.Body)
case "MarshalTo", "Size", "String":
ast.Walk(&optionalItemsVisitor{}, t.Body)
fallthrough
case "Marshal":
// if the method has a pointer receiver, set it back to a normal receiver
if ptr {
t.Recv.List[0].Type = ident
}
}
}
}
type optionalAssignmentVisitor struct {
fn OptionalFunc
}
// Visit walks the provided node, transforming field initializations of the form
// m.Field = &OptionalType{} -> m.Field = OptionalType{}
func (v optionalAssignmentVisitor) Visit(n ast.Node) ast.Visitor {
switch t := n.(type) {
case *ast.AssignStmt:
if len(t.Lhs) == 1 && len(t.Rhs) == 1 {
if !isFieldSelector(t.Lhs[0], "m", "") {
return nil
}
unary, ok := t.Rhs[0].(*ast.UnaryExpr)
if !ok || unary.Op != token.AND {
return nil
}
composite, ok := unary.X.(*ast.CompositeLit)
if !ok || composite.Type == nil || len(composite.Elts) != 0 {
return nil
}
if ident, ok := composite.Type.(*ast.Ident); ok && v.fn(ident.Name) {
t.Rhs[0] = composite
}
}
return nil
}
return v
}
type optionalItemsVisitor struct{}
// Visit walks the provided node, looking for specific patterns to transform that match
// the effective outcome of turning struct{ map[x]y || []x } into map[x]y or []x.
func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor {
switch t := n.(type) {
case *ast.RangeStmt:
if isFieldSelector(t.X, "m", "Items") {
t.X = &ast.Ident{Name: "m"}
}
case *ast.AssignStmt:
if len(t.Lhs) == 1 && len(t.Rhs) == 1 {
switch lhs := t.Lhs[0].(type) {
case *ast.IndexExpr:
if isFieldSelector(lhs.X, "m", "Items") {
lhs.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
default:
if isFieldSelector(t.Lhs[0], "m", "Items") {
t.Lhs[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
}
switch rhs := t.Rhs[0].(type) {
case *ast.CallExpr:
if ident, ok := rhs.Fun.(*ast.Ident); ok && ident.Name == "append" {
ast.Walk(v, rhs)
if len(rhs.Args) > 0 {
switch arg := rhs.Args[0].(type) {
case *ast.Ident:
if arg.Name == "m" {
rhs.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
}
}
return nil
}
}
}
case *ast.IfStmt:
switch cond := t.Cond.(type) {
case *ast.BinaryExpr:
if cond.Op == token.EQL {
if isFieldSelector(cond.X, "m", "Items") && isIdent(cond.Y, "nil") {
cond.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
}
}
if t.Init != nil {
// Find form:
// if err := m[len(m.Items)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
// return err
// }
switch s := t.Init.(type) {
case *ast.AssignStmt:
if call, ok := s.Rhs[0].(*ast.CallExpr); ok {
if sel, ok := call.Fun.(*ast.SelectorExpr); ok {
if x, ok := sel.X.(*ast.IndexExpr); ok {
// m[] -> (*m)[]
if sel2, ok := x.X.(*ast.SelectorExpr); ok {
if ident, ok := sel2.X.(*ast.Ident); ok && ident.Name == "m" {
x.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
}
// len(m.Items) -> len(*m)
if bin, ok := x.Index.(*ast.BinaryExpr); ok {
if call2, ok := bin.X.(*ast.CallExpr); ok && len(call2.Args) == 1 {
if isFieldSelector(call2.Args[0], "m", "Items") {
call2.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
}
}
}
}
}
}
}
case *ast.IndexExpr:
if isFieldSelector(t.X, "m", "Items") {
t.X = &ast.Ident{Name: "m"}
return nil
}
case *ast.CallExpr:
changed := false
for i := range t.Args {
if isFieldSelector(t.Args[i], "m", "Items") {
t.Args[i] = &ast.Ident{Name: "m"}
changed = true
}
}
if changed {
return nil
}
}
return v
}
func isFieldSelector(n ast.Expr, name, field string) bool {
s, ok := n.(*ast.SelectorExpr)
if !ok || s.Sel == nil || (field != "" && s.Sel.Name != field) {
return false
}
return isIdent(s.X, name)
}
func isIdent(n ast.Expr, value string) bool {
ident, ok := n.(*ast.Ident)
return ok && ident.Name == value
}
func receiver(f *ast.FuncDecl) (ident *ast.Ident, pointer bool, ok bool) {
if f.Recv == nil || len(f.Recv.List) != 1 {
return nil, false, false
}
switch t := f.Recv.List[0].Type.(type) {
case *ast.StarExpr:
identity, ok := t.X.(*ast.Ident)
if !ok {
return nil, false, false
}
return identity, true, true
case *ast.Ident:
return t, false, true
}
return nil, false, false
}
// dropExistingTypeDeclarations removes any type declaration for which extractFn returns true. The function
// returns true if the entire declaration should be dropped.
func dropExistingTypeDeclarations(decl ast.Decl, extractFn ExtractFunc) bool {
switch t := decl.(type) {
case *ast.GenDecl:
if t.Tok != token.TYPE {
return false
}
specs := []ast.Spec{}
for _, s := range t.Specs {
switch spec := s.(type) {
case *ast.TypeSpec:
if extractFn(spec) {
continue
}
specs = append(specs, spec)
}
}
if len(specs) == 0 {
return true
}
t.Specs = specs
}
return false
}
// dropEmptyImportDeclarations strips any generated but no-op imports from the generated code
// to prevent generation from being able to define side-effects. The function returns true
// if the entire declaration should be dropped.
func dropEmptyImportDeclarations(decl ast.Decl) bool {
switch t := decl.(type) {
case *ast.GenDecl:
if t.Tok != token.IMPORT {
return false
}
specs := []ast.Spec{}
for _, s := range t.Specs {
switch spec := s.(type) {
case *ast.ImportSpec:
if spec.Name != nil && spec.Name.Name == "_" {
continue
}
specs = append(specs, spec)
}
}
if len(specs) == 0 {
return true
}
t.Specs = specs
}
return false
}
func RewriteTypesWithProtobufStructTags(name string, structTags map[string]map[string]string) error {
return rewriteFile(name, []byte{}, func(fset *token.FileSet, file *ast.File) error {
allErrs := []error{}
// set any new struct tags
for _, d := range file.Decls {
if errs := updateStructTags(d, structTags, []string{"protobuf"}); len(errs) > 0 {
allErrs = append(allErrs, errs...)
}
}
if len(allErrs) > 0 {
var s string
for _, err := range allErrs {
s += err.Error() + "\n"
}
return errors.New(s)
}
return nil
})
}
func updateStructTags(decl ast.Decl, structTags map[string]map[string]string, toCopy []string) []error {
var errs []error
t, ok := decl.(*ast.GenDecl)
if !ok {
return nil
}
if t.Tok != token.TYPE {
return nil
}
for _, s := range t.Specs {
spec, ok := s.(*ast.TypeSpec)
if !ok {
continue
}
typeName := spec.Name.Name
fieldTags, ok := structTags[typeName]
if !ok {
continue
}
st, ok := spec.Type.(*ast.StructType)
if !ok {
continue
}
for i := range st.Fields.List {
f := st.Fields.List[i]
var name string
if len(f.Names) == 0 {
switch t := f.Type.(type) {
case *ast.Ident:
name = t.Name
case *ast.SelectorExpr:
name = t.Sel.Name
default:
errs = append(errs, fmt.Errorf("unable to get name for tag from struct %q, field %#v", spec.Name.Name, t))
continue
}
} else {
name = f.Names[0].Name
}
value, ok := fieldTags[name]
if !ok {
continue
}
var tags customreflect.StructTags
if f.Tag != nil {
oldTags, err := customreflect.ParseStructTags(strings.Trim(f.Tag.Value, "`"))
if err != nil {
errs = append(errs, fmt.Errorf("unable to read struct tag from struct %q, field %q: %v", spec.Name.Name, name, err))
continue
}
tags = oldTags
}
for _, name := range toCopy {
// don't overwrite existing tags
if tags.Has(name) {
continue
}
// append new tags
if v := reflect.StructTag(value).Get(name); len(v) > 0 {
tags = append(tags, customreflect.StructTag{Name: name, Value: v})
}
}
if len(tags) == 0 {
continue
}
if f.Tag == nil {
f.Tag = &ast.BasicLit{}
}
f.Tag.Value = tags.String()
}
}
return errs
}

View 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 protobuf
import (
"github.com/golang/glog"
"k8s.io/gengo/types"
)
// 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 {
glog.Fatalf(err.Error())
}
return val
}

View File

@@ -0,0 +1,32 @@
/*
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 main defines the protoc-gen-gogo binary we use to generate our proto go files,
// as well as takes dependencies on the correct gogo/protobuf packages for godeps.
package main
import (
"github.com/gogo/protobuf/vanity/command"
// dependencies that are required for our packages
_ "github.com/gogo/protobuf/gogoproto"
_ "github.com/gogo/protobuf/proto"
_ "github.com/gogo/protobuf/sortkeys"
)
func main() {
command.Write(command.Generate(command.Read()))
}

1
vendor/k8s.io/gengo/examples/import-boss/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
import-boss

View File

@@ -0,0 +1,272 @@
/*
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"
"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"
"github.com/golang/glog"
)
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, &current)
if err != nil {
return nil, fmt.Errorf("couldn't unmarshal %v: %v", path, err)
}
return &current, 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
}
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 {
glog.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 {
glog.V(4).Infof("Checking %v against %v\n", v, forbidden)
if strings.HasPrefix(v, forbidden) {
return fmt.Errorf("import %v has forbidden prefix %v", v, forbidden)
}
}
found := false
for _, allowed := range r.AllowedPrefixes {
glog.V(4).Infof("Checking %v against %v\n", v, allowed)
if strings.HasPrefix(v, allowed) {
found = true
break
}
}
if !found {
return fmt.Errorf("import %v did not match any allowed prefix", v)
}
}
}
if len(rules.Rules) > 0 {
glog.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
}

View File

@@ -0,0 +1,39 @@
/*
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 (
"path/filepath"
"testing"
)
func TestRemoveLastDir(t *testing.T) {
table := map[string]struct{ newPath, removedDir string }{
"a/b/c": {"a/c", "b"},
}
for slashInput, expect := range table {
input := filepath.FromSlash(slashInput)
gotPath, gotRemoved := removeLastDir(input)
if e, a := filepath.FromSlash(expect.newPath), gotPath; e != a {
t.Errorf("%v: wanted %v, got %v", input, e, a)
}
if e, a := filepath.FromSlash(expect.removedDir), gotRemoved; e != a {
t.Errorf("%v: wanted %v, got %v", input, e, a)
}
}
}

78
vendor/k8s.io/gengo/examples/import-boss/main.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
/*
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.
*/
// import-boss enforces import restrictions in a given repository.
//
// When a directory is verified, import-boss looks for a file called
// ".import-restrictions". If this file is not found, parent directories will be
// recursively searched.
//
// If an ".import-restrictions" file is found, then all imports of the package
// are checked against each "rule" in the file. A rule consists of three parts:
// * A SelectorRegexp, to select the import paths that the rule applies to.
// * A list of AllowedPrefixes
// * A list of ForbiddenPrefixes
// An import is allowed if it matches at least one allowed prefix and does not
// match any forbidden prefix. An example file looks like this:
//
// {
// "Rules": [
// {
// "SelectorRegexp": "k8s[.]io",
// "AllowedPrefixes": [
// "k8s.io/gengo",
// "k8s.io/kubernetes/third_party"
// ],
// "ForbiddenPrefixes": [
// "k8s.io/kubernetes/pkg/third_party/deprecated"
// ]
// },
// {
// "SelectorRegexp": "^unsafe$",
// "AllowedPrefixes": [
// ],
// "ForbiddenPrefixes": [
// ""
// ]
// }
// ]
// }
//
// Note the secound block explicitly matches the unsafe package, and forbids it
// ("" is a prefix of everything).
package main
import (
"os"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/import-boss/generators"
"github.com/golang/glog"
)
func main() {
arguments := args.Default()
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Errorf("Error: %v", err)
os.Exit(1)
}
glog.V(2).Info("Completed successfully.")
}

1
vendor/k8s.io/gengo/examples/set-gen/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
set-gen

15
vendor/k8s.io/gengo/examples/set-gen/Makefile generated vendored Normal file
View File

@@ -0,0 +1,15 @@
TOOL=set-gen
test:
@if ! git diff --quiet HEAD; then \
echo "FAIL: git client is not clean"; \
false; \
fi
@go build -o /tmp/$(TOOL)
@PKGS=$$(go list ./sets/types | paste -sd' ' -); \
/tmp/$(TOOL) --logtostderr --v=4 -i $$(echo $$PKGS | sed 's/ /,/g') -O zz_generated -o ./sets
@if ! git diff --quiet HEAD; then \
echo "FAIL: output files changed"; \
git diff; \
false; \
fi

360
vendor/k8s.io/gengo/examples/set-gen/generators/sets.go generated vendored Normal file
View File

@@ -0,0 +1,360 @@
/*
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"
"github.com/golang/glog"
)
// 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 {
glog.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$) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s $.type|public$) Delete(items ...$.type|raw$) {
for _, item := range items {
delete(s, item)
}
}
// 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)
}
`

View 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 (
"github.com/golang/glog"
"k8s.io/gengo/types"
)
// 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 {
glog.Fatalf(err.Error())
}
return val
}

47
vendor/k8s.io/gengo/examples/set-gen/main.go generated vendored Normal file
View File

@@ -0,0 +1,47 @@
/*
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.
*/
// set-gen is an example usage of go2idl.
//
// Structs in the input directories with the below line in their comments will
// have sets generated for them.
// // +genset
//
// Any builtin type referenced anywhere in the input directories will have a
// set generated for it.
package main
import (
"os"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/set-gen/generators"
"github.com/golang/glog"
)
func main() {
arguments := args.Default()
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Errorf("Error: %v", err)
os.Exit(1)
}
glog.V(2).Info("Completed successfully.")
}

203
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go generated vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
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) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s Byte) Delete(items ...byte) {
for _, item := range items {
delete(s, item)
}
}
// 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
View 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
View 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{}

203
vendor/k8s.io/gengo/examples/set-gen/sets/int.go generated vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
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) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s Int) Delete(items ...int) {
for _, item := range items {
delete(s, item)
}
}
// 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
}

203
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go generated vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
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) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s Int64) Delete(items ...int64) {
for _, item := range items {
delete(s, item)
}
}
// 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
}

270
vendor/k8s.io/gengo/examples/set-gen/sets/set_test.go generated vendored Normal file
View File

@@ -0,0 +1,270 @@
/*
Copyright 2014 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 sets
import (
"reflect"
"testing"
)
func TestStringSet(t *testing.T) {
s := String{}
s2 := String{}
if len(s) != 0 {
t.Errorf("Expected len=0: %d", len(s))
}
s.Insert("a", "b")
if len(s) != 2 {
t.Errorf("Expected len=2: %d", len(s))
}
s.Insert("c")
if s.Has("d") {
t.Errorf("Unexpected contents: %#v", s)
}
if !s.Has("a") {
t.Errorf("Missing contents: %#v", s)
}
s.Delete("a")
if s.Has("a") {
t.Errorf("Unexpected contents: %#v", s)
}
s.Insert("a")
if s.HasAll("a", "b", "d") {
t.Errorf("Unexpected contents: %#v", s)
}
if !s.HasAll("a", "b") {
t.Errorf("Missing contents: %#v", s)
}
s2.Insert("a", "b", "d")
if s.IsSuperset(s2) {
t.Errorf("Unexpected contents: %#v", s)
}
s2.Delete("d")
if !s.IsSuperset(s2) {
t.Errorf("Missing contents: %#v", s)
}
}
func TestStringSetDeleteMultiples(t *testing.T) {
s := String{}
s.Insert("a", "b", "c")
if len(s) != 3 {
t.Errorf("Expected len=3: %d", len(s))
}
s.Delete("a", "c")
if len(s) != 1 {
t.Errorf("Expected len=1: %d", len(s))
}
if s.Has("a") {
t.Errorf("Unexpected contents: %#v", s)
}
if s.Has("c") {
t.Errorf("Unexpected contents: %#v", s)
}
if !s.Has("b") {
t.Errorf("Missing contents: %#v", s)
}
}
func TestNewStringSet(t *testing.T) {
s := NewString("a", "b", "c")
if len(s) != 3 {
t.Errorf("Expected len=3: %d", len(s))
}
if !s.Has("a") || !s.Has("b") || !s.Has("c") {
t.Errorf("Unexpected contents: %#v", s)
}
}
func TestStringSetList(t *testing.T) {
s := NewString("z", "y", "x", "a")
if !reflect.DeepEqual(s.List(), []string{"a", "x", "y", "z"}) {
t.Errorf("List gave unexpected result: %#v", s.List())
}
}
func TestStringSetDifference(t *testing.T) {
a := NewString("1", "2", "3")
b := NewString("1", "2", "4", "5")
c := a.Difference(b)
d := b.Difference(a)
if len(c) != 1 {
t.Errorf("Expected len=1: %d", len(c))
}
if !c.Has("3") {
t.Errorf("Unexpected contents: %#v", c.List())
}
if len(d) != 2 {
t.Errorf("Expected len=2: %d", len(d))
}
if !d.Has("4") || !d.Has("5") {
t.Errorf("Unexpected contents: %#v", d.List())
}
}
func TestStringSetHasAny(t *testing.T) {
a := NewString("1", "2", "3")
if !a.HasAny("1", "4") {
t.Errorf("expected true, got false")
}
if a.HasAny("0", "4") {
t.Errorf("expected false, got true")
}
}
func TestStringSetEquals(t *testing.T) {
// Simple case (order doesn't matter)
a := NewString("1", "2")
b := NewString("2", "1")
if !a.Equal(b) {
t.Errorf("Expected to be equal: %v vs %v", a, b)
}
// It is a set; duplicates are ignored
b = NewString("2", "2", "1")
if !a.Equal(b) {
t.Errorf("Expected to be equal: %v vs %v", a, b)
}
// Edge cases around empty sets / empty strings
a = NewString()
b = NewString()
if !a.Equal(b) {
t.Errorf("Expected to be equal: %v vs %v", a, b)
}
b = NewString("1", "2", "3")
if a.Equal(b) {
t.Errorf("Expected to be not-equal: %v vs %v", a, b)
}
b = NewString("1", "2", "")
if a.Equal(b) {
t.Errorf("Expected to be not-equal: %v vs %v", a, b)
}
// Check for equality after mutation
a = NewString()
a.Insert("1")
if a.Equal(b) {
t.Errorf("Expected to be not-equal: %v vs %v", a, b)
}
a.Insert("2")
if a.Equal(b) {
t.Errorf("Expected to be not-equal: %v vs %v", a, b)
}
a.Insert("")
if !a.Equal(b) {
t.Errorf("Expected to be equal: %v vs %v", a, b)
}
a.Delete("")
if a.Equal(b) {
t.Errorf("Expected to be not-equal: %v vs %v", a, b)
}
}
func TestStringUnion(t *testing.T) {
tests := []struct {
s1 String
s2 String
expected String
}{
{
NewString("1", "2", "3", "4"),
NewString("3", "4", "5", "6"),
NewString("1", "2", "3", "4", "5", "6"),
},
{
NewString("1", "2", "3", "4"),
NewString(),
NewString("1", "2", "3", "4"),
},
{
NewString(),
NewString("1", "2", "3", "4"),
NewString("1", "2", "3", "4"),
},
{
NewString(),
NewString(),
NewString(),
},
}
for _, test := range tests {
union := test.s1.Union(test.s2)
if union.Len() != test.expected.Len() {
t.Errorf("Expected union.Len()=%d but got %d", test.expected.Len(), union.Len())
}
if !union.Equal(test.expected) {
t.Errorf("Expected union.Equal(expected) but not true. union:%v expected:%v", union.List(), test.expected.List())
}
}
}
func TestStringIntersection(t *testing.T) {
tests := []struct {
s1 String
s2 String
expected String
}{
{
NewString("1", "2", "3", "4"),
NewString("3", "4", "5", "6"),
NewString("3", "4"),
},
{
NewString("1", "2", "3", "4"),
NewString("1", "2", "3", "4"),
NewString("1", "2", "3", "4"),
},
{
NewString("1", "2", "3", "4"),
NewString(),
NewString(),
},
{
NewString(),
NewString("1", "2", "3", "4"),
NewString(),
},
{
NewString(),
NewString(),
NewString(),
},
}
for _, test := range tests {
intersection := test.s1.Intersection(test.s2)
if intersection.Len() != test.expected.Len() {
t.Errorf("Expected intersection.Len()=%d but got %d", test.expected.Len(), intersection.Len())
}
if !intersection.Equal(test.expected) {
t.Errorf("Expected intersection.Equal(expected) but not true. intersection:%v expected:%v", intersection.List(), test.expected.List())
}
}
}

203
vendor/k8s.io/gengo/examples/set-gen/sets/string.go generated vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
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) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s String) Delete(items ...string) {
for _, item := range items {
delete(s, item)
}
}
// 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
}

View File

@@ -0,0 +1,30 @@
/*
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 types just provides input types to the set generator. It also
// contains a "go generate" block.
// (You must first `go install k8s.io/gengo/examples/set-gen`)
package types
//go:generate set-gen -i k8s.io/gengo/examples/set-gen/sets/types -o k8s.io/gengo/examples/set-gen/sets
type ReferenceSetTypes struct {
// These types all cause files to be generated
a int64
b int
c byte
d string
}