1 Star 0 Fork 0

zhuchance/kubernetes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
deep_copy_generator.go 18.77 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 runtime
import (
"fmt"
"io"
"path"
"reflect"
"sort"
"strings"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/util/sets"
)
// TODO(wojtek-t): As suggested in #8320, we should consider the strategy
// to first do the shallow copy and then recurse into things that need a
// deep copy (maps, pointers, slices). That sort of copy function would
// need one parameter - a pointer to the thing it's supposed to expand,
// and it would involve a lot less memory copying.
type DeepCopyGenerator interface {
// Adds a type to a generator.
// If the type is non-struct, it will return an error, otherwise deep-copy
// functions for this type and all nested types will be generated.
AddType(inType reflect.Type) error
// ReplaceType registers a type that should be used instead of the type
// with the provided pkgPath and name.
ReplaceType(pkgPath, name string, in interface{})
// AddImport registers a package name with the generator and returns its
// short name.
AddImport(pkgPath string) string
// RepackImports creates a stable ordering of import short names
RepackImports()
// Writes all imports that are necessary for deep-copy function and
// their registration.
WriteImports(w io.Writer) error
// Writes deel-copy functions for all types added via AddType() method
// and their nested types.
WriteDeepCopyFunctions(w io.Writer) error
// Writes an init() function that registers all the generated deep-copy
// functions.
RegisterDeepCopyFunctions(w io.Writer, pkg string) error
// When generating code, all references to "pkg" package name will be
// replaced with "overwrite". It is used mainly to replace references
// to name of the package in which the code will be created with empty
// string.
OverwritePackage(pkg, overwrite string)
}
func NewDeepCopyGenerator(scheme *conversion.Scheme, targetPkg string, include sets.String) DeepCopyGenerator {
g := &deepCopyGenerator{
scheme: scheme,
targetPkg: targetPkg,
copyables: make(map[reflect.Type]bool),
imports: make(map[string]string),
shortImports: make(map[string]string),
pkgOverwrites: make(map[string]string),
replace: make(map[pkgPathNamePair]reflect.Type),
include: include,
}
g.targetPackage(targetPkg)
g.AddImport("k8s.io/kubernetes/pkg/conversion")
return g
}
type pkgPathNamePair struct {
PkgPath string
Name string
}
type deepCopyGenerator struct {
scheme *conversion.Scheme
targetPkg string
copyables map[reflect.Type]bool
// map of package names to shortname
imports map[string]string
// map of short names to package names
shortImports map[string]string
pkgOverwrites map[string]string
replace map[pkgPathNamePair]reflect.Type
include sets.String
}
func (g *deepCopyGenerator) addImportByPath(pkg string) string {
if name, ok := g.imports[pkg]; ok {
return name
}
name := path.Base(pkg)
if _, ok := g.shortImports[name]; !ok {
g.imports[pkg] = name
g.shortImports[name] = pkg
return name
}
if dirname := path.Base(path.Dir(pkg)); len(dirname) > 0 {
name = dirname + name
if _, ok := g.shortImports[name]; !ok {
g.imports[pkg] = name
g.shortImports[name] = pkg
return name
}
if subdirname := path.Base(path.Dir(path.Dir(pkg))); len(subdirname) > 0 {
name = subdirname + name
if _, ok := g.shortImports[name]; !ok {
g.imports[pkg] = name
g.shortImports[name] = pkg
return name
}
}
}
for i := 2; i < 100; i++ {
generatedName := fmt.Sprintf("%s%d", name, i)
if _, ok := g.shortImports[generatedName]; !ok {
g.imports[pkg] = generatedName
g.shortImports[generatedName] = pkg
return generatedName
}
}
panic(fmt.Sprintf("unable to find a unique name for the package path %q: %v", pkg, g.shortImports))
}
func (g *deepCopyGenerator) targetPackage(pkg string) {
g.imports[pkg] = ""
g.shortImports[""] = pkg
}
func (g *deepCopyGenerator) addAllRecursiveTypes(inType reflect.Type) error {
if _, found := g.copyables[inType]; found {
return nil
}
switch inType.Kind() {
case reflect.Map:
if err := g.addAllRecursiveTypes(inType.Key()); err != nil {
return err
}
if err := g.addAllRecursiveTypes(inType.Elem()); err != nil {
return err
}
case reflect.Slice, reflect.Ptr:
if err := g.addAllRecursiveTypes(inType.Elem()); err != nil {
return err
}
case reflect.Interface:
g.addImportByPath(inType.PkgPath())
return nil
case reflect.Struct:
g.addImportByPath(inType.PkgPath())
found := false
for s := range g.include {
if strings.HasPrefix(inType.PkgPath(), s) {
found = true
break
}
}
if !found {
return nil
}
for i := 0; i < inType.NumField(); i++ {
inField := inType.Field(i)
if err := g.addAllRecursiveTypes(inField.Type); err != nil {
return err
}
}
g.copyables[inType] = true
default:
// Simple types should be copied automatically.
}
return nil
}
func (g *deepCopyGenerator) AddImport(pkg string) string {
return g.addImportByPath(pkg)
}
// ReplaceType registers a replacement type to be used instead of the named type
func (g *deepCopyGenerator) ReplaceType(pkgPath, name string, t interface{}) {
g.replace[pkgPathNamePair{pkgPath, name}] = reflect.TypeOf(t)
}
func (g *deepCopyGenerator) AddType(inType reflect.Type) error {
if inType.Kind() != reflect.Struct {
return fmt.Errorf("non-struct copies are not supported")
}
return g.addAllRecursiveTypes(inType)
}
func (g *deepCopyGenerator) RepackImports() {
var packages []string
for key := range g.imports {
packages = append(packages, key)
}
sort.Strings(packages)
g.imports = make(map[string]string)
g.shortImports = make(map[string]string)
g.targetPackage(g.targetPkg)
for _, pkg := range packages {
g.addImportByPath(pkg)
}
}
func (g *deepCopyGenerator) WriteImports(w io.Writer) error {
var packages []string
for key := range g.imports {
packages = append(packages, key)
}
sort.Strings(packages)
buffer := newBuffer()
indent := 0
buffer.addLine("import (\n", indent)
for _, importPkg := range packages {
if len(importPkg) == 0 {
continue
}
if len(g.imports[importPkg]) == 0 {
continue
}
buffer.addLine(fmt.Sprintf("%s \"%s\"\n", g.imports[importPkg], importPkg), indent+1)
}
buffer.addLine(")\n", indent)
buffer.addLine("\n", indent)
if err := buffer.flushLines(w); err != nil {
return err
}
return nil
}
type byPkgAndName []reflect.Type
func (s byPkgAndName) Len() int {
return len(s)
}
func (s byPkgAndName) Less(i, j int) bool {
fullNameI := s[i].PkgPath() + "/" + s[i].Name()
fullNameJ := s[j].PkgPath() + "/" + s[j].Name()
return fullNameI < fullNameJ
}
func (s byPkgAndName) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (g *deepCopyGenerator) nameForType(inType reflect.Type) string {
switch inType.Kind() {
case reflect.Slice:
return fmt.Sprintf("[]%s", g.typeName(inType.Elem()))
case reflect.Ptr:
return fmt.Sprintf("*%s", g.typeName(inType.Elem()))
case reflect.Map:
if len(inType.Name()) == 0 {
return fmt.Sprintf("map[%s]%s", g.typeName(inType.Key()), g.typeName(inType.Elem()))
}
fallthrough
default:
pkg, name := inType.PkgPath(), inType.Name()
if len(name) == 0 && inType.Kind() == reflect.Struct {
return "struct{}"
}
if len(pkg) == 0 {
// Default package.
return name
}
if val, found := g.pkgOverwrites[pkg]; found {
pkg = val
}
if len(pkg) == 0 {
return name
}
short := g.addImportByPath(pkg)
if len(short) > 0 {
return fmt.Sprintf("%s.%s", short, name)
}
return name
}
}
func (g *deepCopyGenerator) typeName(inType reflect.Type) string {
if t, ok := g.replace[pkgPathNamePair{inType.PkgPath(), inType.Name()}]; ok {
return g.nameForType(t)
}
return g.nameForType(inType)
}
func (g *deepCopyGenerator) deepCopyFunctionName(inType reflect.Type) string {
funcNameFormat := "deepCopy_%s_%s"
inPkg := packageForName(inType)
funcName := fmt.Sprintf(funcNameFormat, inPkg, inType.Name())
return funcName
}
func (g *deepCopyGenerator) writeHeader(b *buffer, inType reflect.Type, indent int) {
format := "func %s(in %s, out *%s, c *conversion.Cloner) error {\n"
stmt := fmt.Sprintf(format, g.deepCopyFunctionName(inType), g.typeName(inType), g.typeName(inType))
b.addLine(stmt, indent)
}
func (g *deepCopyGenerator) writeFooter(b *buffer, indent int) {
b.addLine("return nil\n", indent+1)
b.addLine("}\n", indent)
}
func (g *deepCopyGenerator) WriteDeepCopyFunctions(w io.Writer) error {
var keys []reflect.Type
for key := range g.copyables {
keys = append(keys, key)
}
sort.Sort(byPkgAndName(keys))
buffer := newBuffer()
indent := 0
for _, inType := range keys {
if err := g.writeDeepCopyForType(buffer, inType, indent); err != nil {
return err
}
buffer.addLine("\n", 0)
}
if err := buffer.flushLines(w); err != nil {
return err
}
return nil
}
func (g *deepCopyGenerator) writeDeepCopyForMap(b *buffer, inField reflect.StructField, indent int) error {
ifFormat := "if in.%s != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent)
newFormat := "out.%s = make(%s)\n"
newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type))
b.addLine(newStmt, indent+1)
forFormat := "for key, val := range in.%s {\n"
forStmt := fmt.Sprintf(forFormat, inField.Name)
b.addLine(forStmt, indent+1)
switch inField.Type.Key().Kind() {
case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
return fmt.Errorf("not supported")
default:
switch inField.Type.Elem().Kind() {
case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
if _, found := g.copyables[inField.Type.Elem()]; found {
newFormat := "newVal := new(%s)\n"
newStmt := fmt.Sprintf(newFormat, g.typeName(inField.Type.Elem()))
b.addLine(newStmt, indent+2)
assignFormat := "if err := %s(val, newVal, c); err != nil {\n"
funcName := g.deepCopyFunctionName(inField.Type.Elem())
assignStmt := fmt.Sprintf(assignFormat, funcName)
b.addLine(assignStmt, indent+2)
b.addLine("return err\n", indent+3)
b.addLine("}\n", indent+2)
setFormat := "out.%s[key] = *newVal\n"
setStmt := fmt.Sprintf(setFormat, inField.Name)
b.addLine(setStmt, indent+2)
} else {
ifStmt := "if newVal, err := c.DeepCopy(val); err != nil {\n"
b.addLine(ifStmt, indent+2)
b.addLine("return err\n", indent+3)
b.addLine("} else {\n", indent+2)
assignFormat := "out.%s[key] = newVal.(%s)\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type.Elem()))
b.addLine(assignStmt, indent+3)
b.addLine("}\n", indent+2)
}
default:
assignFormat := "out.%s[key] = val\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name)
b.addLine(assignStmt, indent+2)
}
}
b.addLine("}\n", indent+1)
b.addLine("} else {\n", indent)
elseFormat := "out.%s = nil\n"
elseStmt := fmt.Sprintf(elseFormat, inField.Name)
b.addLine(elseStmt, indent+1)
b.addLine("}\n", indent)
return nil
}
func (g *deepCopyGenerator) writeDeepCopyForPtr(b *buffer, inField reflect.StructField, indent int) error {
ifFormat := "if in.%s != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent)
switch inField.Type.Elem().Kind() {
case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
if _, found := g.copyables[inField.Type.Elem()]; found {
newFormat := "out.%s = new(%s)\n"
newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type.Elem()))
b.addLine(newStmt, indent+1)
assignFormat := "if err := %s(*in.%s, out.%s, c); err != nil {\n"
funcName := g.deepCopyFunctionName(inField.Type.Elem())
assignStmt := fmt.Sprintf(assignFormat, funcName, inField.Name, inField.Name)
b.addLine(assignStmt, indent+1)
b.addLine("return err\n", indent+2)
b.addLine("}\n", indent+1)
} else {
ifFormat := "if newVal, err := c.DeepCopy(in.%s); err != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent+1)
b.addLine("return err\n", indent+2)
b.addLine("} else if newVal == nil {\n", indent+1)
b.addLine(fmt.Sprintf("out.%s = nil\n", inField.Name), indent+2)
b.addLine("} else {\n", indent+1)
assignFormat := "out.%s = newVal.(%s)\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type))
b.addLine(assignStmt, indent+2)
b.addLine("}\n", indent+1)
}
default:
newFormat := "out.%s = new(%s)\n"
newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type.Elem()))
b.addLine(newStmt, indent+1)
assignFormat := "*out.%s = *in.%s\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, inField.Name)
b.addLine(assignStmt, indent+1)
}
b.addLine("} else {\n", indent)
elseFormat := "out.%s = nil\n"
elseStmt := fmt.Sprintf(elseFormat, inField.Name)
b.addLine(elseStmt, indent+1)
b.addLine("}\n", indent)
return nil
}
func (g *deepCopyGenerator) writeDeepCopyForSlice(b *buffer, inField reflect.StructField, indent int) error {
ifFormat := "if in.%s != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent)
newFormat := "out.%s = make(%s, len(in.%s))\n"
newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type), inField.Name)
b.addLine(newStmt, indent+1)
forFormat := "for i := range in.%s {\n"
forStmt := fmt.Sprintf(forFormat, inField.Name)
b.addLine(forStmt, indent+1)
switch inField.Type.Elem().Kind() {
case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
if _, found := g.copyables[inField.Type.Elem()]; found {
assignFormat := "if err := %s(in.%s[i], &out.%s[i], c); err != nil {\n"
funcName := g.deepCopyFunctionName(inField.Type.Elem())
assignStmt := fmt.Sprintf(assignFormat, funcName, inField.Name, inField.Name)
b.addLine(assignStmt, indent+2)
b.addLine("return err\n", indent+3)
b.addLine("}\n", indent+2)
} else {
ifFormat := "if newVal, err := c.DeepCopy(in.%s[i]); err != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent+2)
b.addLine("return err\n", indent+3)
b.addLine("} else if newVal == nil {\n", indent+2)
b.addLine(fmt.Sprintf("out.%s[i] = nil\n", inField.Name), indent+3)
b.addLine("} else {\n", indent+2)
assignFormat := "out.%s[i] = newVal.(%s)\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type.Elem()))
b.addLine(assignStmt, indent+3)
b.addLine("}\n", indent+2)
}
default:
assignFormat := "out.%s[i] = in.%s[i]\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, inField.Name)
b.addLine(assignStmt, indent+2)
}
b.addLine("}\n", indent+1)
b.addLine("} else {\n", indent)
elseFormat := "out.%s = nil\n"
elseStmt := fmt.Sprintf(elseFormat, inField.Name)
b.addLine(elseStmt, indent+1)
b.addLine("}\n", indent)
return nil
}
func (g *deepCopyGenerator) writeDeepCopyForStruct(b *buffer, inType reflect.Type, indent int) error {
for i := 0; i < inType.NumField(); i++ {
inField := inType.Field(i)
switch inField.Type.Kind() {
case reflect.Map:
if err := g.writeDeepCopyForMap(b, inField, indent); err != nil {
return err
}
case reflect.Ptr:
if err := g.writeDeepCopyForPtr(b, inField, indent); err != nil {
return err
}
case reflect.Slice:
if err := g.writeDeepCopyForSlice(b, inField, indent); err != nil {
return err
}
case reflect.Interface:
ifFormat := "if newVal, err := c.DeepCopy(in.%s); err != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent)
b.addLine("return err\n", indent+1)
b.addLine("} else if newVal == nil {\n", indent)
b.addLine(fmt.Sprintf("out.%s = nil\n", inField.Name), indent+1)
b.addLine("} else {\n", indent)
copyFormat := "out.%s = newVal.(%s)\n"
copyStmt := fmt.Sprintf(copyFormat, inField.Name, g.typeName(inField.Type))
b.addLine(copyStmt, indent+1)
b.addLine("}\n", indent)
case reflect.Struct:
if _, found := g.copyables[inField.Type]; found {
ifFormat := "if err := %s(in.%s, &out.%s, c); err != nil {\n"
funcName := g.deepCopyFunctionName(inField.Type)
ifStmt := fmt.Sprintf(ifFormat, funcName, inField.Name, inField.Name)
b.addLine(ifStmt, indent)
b.addLine("return err\n", indent+1)
b.addLine("}\n", indent)
} else {
ifFormat := "if newVal, err := c.DeepCopy(in.%s); err != nil {\n"
ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent)
b.addLine("return err\n", indent+1)
b.addLine("} else {\n", indent)
assignFormat := "out.%s = newVal.(%s)\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type))
b.addLine(assignStmt, indent+1)
b.addLine("}\n", indent)
}
default:
// This should handle all simple types.
assignFormat := "out.%s = in.%s\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, inField.Name)
b.addLine(assignStmt, indent)
}
}
return nil
}
func (g *deepCopyGenerator) writeDeepCopyForType(b *buffer, inType reflect.Type, indent int) error {
g.writeHeader(b, inType, indent)
switch inType.Kind() {
case reflect.Struct:
if err := g.writeDeepCopyForStruct(b, inType, indent+1); err != nil {
return err
}
default:
return fmt.Errorf("type not supported: %v", inType)
}
g.writeFooter(b, indent)
return nil
}
func (g *deepCopyGenerator) writeRegisterHeader(b *buffer, pkg string, indent int) {
b.addLine("func init() {\n", indent)
registerFormat := "err := %s.AddGeneratedDeepCopyFuncs(\n"
b.addLine(fmt.Sprintf(registerFormat, pkg), indent+1)
}
func (g *deepCopyGenerator) writeRegisterFooter(b *buffer, indent int) {
b.addLine(")\n", indent+1)
b.addLine("if err != nil {\n", indent+1)
b.addLine("// if one of the deep copy functions is malformed, detect it immediately.\n", indent+2)
b.addLine("panic(err)\n", indent+2)
b.addLine("}\n", indent+1)
b.addLine("}\n", indent)
b.addLine("\n", indent)
}
func (g *deepCopyGenerator) RegisterDeepCopyFunctions(w io.Writer, pkg string) error {
var keys []reflect.Type
for key := range g.copyables {
keys = append(keys, key)
}
sort.Sort(byPkgAndName(keys))
buffer := newBuffer()
indent := 0
g.writeRegisterHeader(buffer, pkg, indent)
for _, inType := range keys {
funcStmt := fmt.Sprintf("%s,\n", g.deepCopyFunctionName(inType))
buffer.addLine(funcStmt, indent+2)
}
g.writeRegisterFooter(buffer, indent)
if err := buffer.flushLines(w); err != nil {
return err
}
return nil
}
func (g *deepCopyGenerator) OverwritePackage(pkg, overwrite string) {
g.pkgOverwrites[pkg] = overwrite
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/meoom/kubernetes.git
git@gitee.com:meoom/kubernetes.git
meoom
kubernetes
kubernetes
v1.1.7-beta.0

搜索帮助

344bd9b3 5694891 D2dac590 5694891