k8s.io/gengo@v0.0.0-20240225000952-471f57d40f57/examples/defaulter-gen/generators/defaulter.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package generators 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io" 24 "path/filepath" 25 "reflect" 26 "regexp" 27 "strconv" 28 "strings" 29 30 "k8s.io/gengo/args" 31 "k8s.io/gengo/generator" 32 "k8s.io/gengo/namer" 33 "k8s.io/gengo/types" 34 35 "k8s.io/klog/v2" 36 ) 37 38 // CustomArgs is used tby the go2idl framework to pass args specific to this 39 // generator. 40 type CustomArgs struct { 41 ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions. 42 } 43 44 var typeZeroValue = map[string]interface{}{ 45 "uint": 0., 46 "uint8": 0., 47 "uint16": 0., 48 "uint32": 0., 49 "uint64": 0., 50 "int": 0., 51 "int8": 0., 52 "int16": 0., 53 "int32": 0., 54 "int64": 0., 55 "byte": 0., 56 "float64": 0., 57 "float32": 0., 58 "bool": false, 59 "time.Time": "", 60 "string": "", 61 "integer": 0., 62 "number": 0., 63 "boolean": false, 64 "[]byte": "", // base64 encoded characters 65 "interface{}": interface{}(nil), 66 } 67 68 // These are the comment tags that carry parameters for defaulter generation. 69 const tagName = "k8s:defaulter-gen" 70 const inputTagName = "k8s:defaulter-gen-input" 71 const defaultTagName = "default" 72 73 func extractDefaultTag(comments []string) []string { 74 return types.ExtractCommentTags("+", comments)[defaultTagName] 75 } 76 77 func extractTag(comments []string) []string { 78 return types.ExtractCommentTags("+", comments)[tagName] 79 } 80 81 func extractInputTag(comments []string) []string { 82 return types.ExtractCommentTags("+", comments)[inputTagName] 83 } 84 85 func checkTag(comments []string, require ...string) bool { 86 values := types.ExtractCommentTags("+", comments)[tagName] 87 if len(require) == 0 { 88 return len(values) == 1 && values[0] == "" 89 } 90 return reflect.DeepEqual(values, require) 91 } 92 93 func defaultFnNamer() *namer.NameStrategy { 94 return &namer.NameStrategy{ 95 Prefix: "SetDefaults_", 96 Join: func(pre string, in []string, post string) string { 97 return pre + strings.Join(in, "_") + post 98 }, 99 } 100 } 101 102 func objectDefaultFnNamer() *namer.NameStrategy { 103 return &namer.NameStrategy{ 104 Prefix: "SetObjectDefaults_", 105 Join: func(pre string, in []string, post string) string { 106 return pre + strings.Join(in, "_") + post 107 }, 108 } 109 } 110 111 // NameSystems returns the name system used by the generators in this package. 112 func NameSystems() namer.NameSystems { 113 return namer.NameSystems{ 114 "public": namer.NewPublicNamer(1), 115 "raw": namer.NewRawNamer("", nil), 116 "defaultfn": defaultFnNamer(), 117 "objectdefaultfn": objectDefaultFnNamer(), 118 } 119 } 120 121 // DefaultNameSystem returns the default name system for ordering the types to be 122 // processed by the generators in this package. 123 func DefaultNameSystem() string { 124 return "public" 125 } 126 127 // defaults holds the declared defaulting functions for a given type (all defaulting functions 128 // are expected to be func(1)) 129 type defaults struct { 130 // object is the defaulter function for a top level type (typically one with TypeMeta) that 131 // invokes all child defaulters. May be nil if the object defaulter has not yet been generated. 132 object *types.Type 133 // base is a defaulter function defined for a type SetDefaults_Pod which does not invoke all 134 // child defaults - the base defaulter alone is insufficient to default a type 135 base *types.Type 136 // additional is zero or more defaulter functions of the form SetDefaults_Pod_XXXX that can be 137 // included in the Object defaulter. 138 additional []*types.Type 139 } 140 141 // All of the types in conversions map are of type "DeclarationOf" with 142 // the underlying type being "Func". 143 type defaulterFuncMap map[*types.Type]defaults 144 145 // Returns all manually-defined defaulting functions in the package. 146 func getManualDefaultingFunctions(context *generator.Context, pkg *types.Package, manualMap defaulterFuncMap) { 147 buffer := &bytes.Buffer{} 148 sw := generator.NewSnippetWriter(buffer, context, "$", "$") 149 150 for _, f := range pkg.Functions { 151 if f.Underlying == nil || f.Underlying.Kind != types.Func { 152 klog.Errorf("Malformed function: %#v", f) 153 continue 154 } 155 if f.Underlying.Signature == nil { 156 klog.Errorf("Function without signature: %#v", f) 157 continue 158 } 159 signature := f.Underlying.Signature 160 // Check whether the function is defaulting function. 161 // Note that all of them have signature: 162 // object: func SetObjectDefaults_inType(*inType) 163 // base: func SetDefaults_inType(*inType) 164 // additional: func SetDefaults_inType_Qualifier(*inType) 165 if signature.Receiver != nil { 166 continue 167 } 168 if len(signature.Parameters) != 1 { 169 continue 170 } 171 if len(signature.Results) != 0 { 172 continue 173 } 174 inType := signature.Parameters[0] 175 if inType.Kind != types.Pointer { 176 continue 177 } 178 // Check if this is the primary defaulter. 179 args := defaultingArgsFromType(inType.Elem) 180 sw.Do("$.inType|defaultfn$", args) 181 switch { 182 case f.Name.Name == buffer.String(): 183 key := inType.Elem 184 // We might scan the same package twice, and that's OK. 185 v, ok := manualMap[key] 186 if ok && v.base != nil && v.base.Name.Package != pkg.Path { 187 panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key)) 188 } 189 v.base = f 190 manualMap[key] = v 191 klog.V(6).Infof("found base defaulter function for %s from %s", key.Name, f.Name) 192 // Is one of the additional defaulters - a top level defaulter on a type that is 193 // also invoked. 194 case strings.HasPrefix(f.Name.Name, buffer.String()+"_"): 195 key := inType.Elem 196 v, ok := manualMap[key] 197 if ok { 198 exists := false 199 for _, existing := range v.additional { 200 if existing.Name == f.Name { 201 exists = true 202 break 203 } 204 } 205 if exists { 206 continue 207 } 208 } 209 v.additional = append(v.additional, f) 210 manualMap[key] = v 211 klog.V(6).Infof("found additional defaulter function for %s from %s", key.Name, f.Name) 212 } 213 buffer.Reset() 214 sw.Do("$.inType|objectdefaultfn$", args) 215 if f.Name.Name == buffer.String() { 216 key := inType.Elem 217 // We might scan the same package twice, and that's OK. 218 v, ok := manualMap[key] 219 if ok && v.base != nil && v.base.Name.Package != pkg.Path { 220 panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key)) 221 } 222 v.object = f 223 manualMap[key] = v 224 klog.V(6).Infof("found object defaulter function for %s from %s", key.Name, f.Name) 225 } 226 buffer.Reset() 227 } 228 } 229 230 func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { 231 boilerplate, err := arguments.LoadGoBoilerplate() 232 if err != nil { 233 klog.Fatalf("Failed loading boilerplate: %v", err) 234 } 235 236 packages := generator.Packages{} 237 header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) 238 239 // Accumulate pre-existing default functions. 240 // TODO: This is too ad-hoc. We need a better way. 241 existingDefaulters := defaulterFuncMap{} 242 243 buffer := &bytes.Buffer{} 244 sw := generator.NewSnippetWriter(buffer, context, "$", "$") 245 246 // We are generating defaults only for packages that are explicitly 247 // passed as InputDir. 248 for _, i := range context.Inputs { 249 klog.V(5).Infof("considering pkg %q", i) 250 pkg := context.Universe[i] 251 if pkg == nil { 252 // If the input had no Go files, for example. 253 continue 254 } 255 // typesPkg is where the types that needs defaulter are defined. 256 // Sometimes it is different from pkg. For example, kubernetes core/v1 257 // types are defined in vendor/k8s.io/api/core/v1, while pkg is at 258 // pkg/api/v1. 259 typesPkg := pkg 260 261 // Add defaulting functions. 262 getManualDefaultingFunctions(context, pkg, existingDefaulters) 263 264 var peerPkgs []string 265 if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok { 266 for _, pkg := range customArgs.ExtraPeerDirs { 267 if i := strings.Index(pkg, "/vendor/"); i != -1 { 268 pkg = pkg[i+len("/vendor/"):] 269 } 270 peerPkgs = append(peerPkgs, pkg) 271 } 272 } 273 // Make sure our peer-packages are added and fully parsed. 274 for _, pp := range peerPkgs { 275 context.AddDir(pp) 276 getManualDefaultingFunctions(context, context.Universe[pp], existingDefaulters) 277 } 278 279 typesWith := extractTag(pkg.Comments) 280 shouldCreateObjectDefaulterFn := func(t *types.Type) bool { 281 if defaults, ok := existingDefaulters[t]; ok && defaults.object != nil { 282 // A default generator is defined 283 baseTypeName := "<unknown>" 284 if defaults.base != nil { 285 baseTypeName = defaults.base.Name.String() 286 } 287 klog.V(5).Infof(" an object defaulter already exists as %s", baseTypeName) 288 return false 289 } 290 // opt-out 291 if checkTag(t.SecondClosestCommentLines, "false") { 292 return false 293 } 294 // opt-in 295 if checkTag(t.SecondClosestCommentLines, "true") { 296 return true 297 } 298 // For every k8s:defaulter-gen tag at the package level, interpret the value as a 299 // field name (like TypeMeta, ListMeta, ObjectMeta) and trigger defaulter generation 300 // for any type with any of the matching field names. Provides a more useful package 301 // level defaulting than global (because we only need defaulters on a subset of objects - 302 // usually those with TypeMeta). 303 if t.Kind == types.Struct && len(typesWith) > 0 { 304 for _, field := range t.Members { 305 for _, s := range typesWith { 306 if field.Name == s { 307 return true 308 } 309 } 310 } 311 } 312 return false 313 } 314 315 // if the types are not in the same package where the defaulter functions to be generated 316 inputTags := extractInputTag(pkg.Comments) 317 if len(inputTags) > 1 { 318 panic(fmt.Sprintf("there could only be one input tag, got %#v", inputTags)) 319 } 320 if len(inputTags) == 1 { 321 var err error 322 323 inputPath := inputTags[0] 324 if strings.HasPrefix(inputPath, "./") || strings.HasPrefix(inputPath, "../") { 325 // this is a relative dir, which will not work under gomodules. 326 // join with the local package path, but warn 327 klog.Warningf("relative path %s=%s will not work under gomodule mode; use full package path (as used by 'import') instead", inputTagName, inputPath) 328 inputPath = filepath.Join(pkg.Path, inputTags[0]) 329 } 330 331 typesPkg, err = context.AddDirectory(inputPath) 332 if err != nil { 333 klog.Fatalf("cannot import package %s", inputPath) 334 } 335 // update context.Order to the latest context.Universe 336 orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)} 337 context.Order = orderer.OrderUniverse(context.Universe) 338 } 339 340 newDefaulters := defaulterFuncMap{} 341 for _, t := range typesPkg.Types { 342 if !shouldCreateObjectDefaulterFn(t) { 343 continue 344 } 345 if namer.IsPrivateGoName(t.Name.Name) { 346 // We won't be able to convert to a private type. 347 klog.V(5).Infof(" found a type %v, but it is a private name", t) 348 continue 349 } 350 351 // create a synthetic type we can use during generation 352 newDefaulters[t] = defaults{} 353 } 354 355 // only generate defaulters for objects that actually have defined defaulters 356 // prevents empty defaulters from being registered 357 for { 358 promoted := 0 359 for t, d := range newDefaulters { 360 if d.object != nil { 361 continue 362 } 363 if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil { 364 args := defaultingArgsFromType(t) 365 sw.Do("$.inType|objectdefaultfn$", args) 366 newDefaulters[t] = defaults{ 367 object: &types.Type{ 368 Name: types.Name{ 369 Package: pkg.Path, 370 Name: buffer.String(), 371 }, 372 Kind: types.Func, 373 }, 374 } 375 buffer.Reset() 376 promoted++ 377 } 378 } 379 if promoted != 0 { 380 continue 381 } 382 383 // prune any types that were not used 384 for t, d := range newDefaulters { 385 if d.object == nil { 386 klog.V(6).Infof("did not generate defaulter for %s because no child defaulters were registered", t.Name) 387 delete(newDefaulters, t) 388 } 389 } 390 break 391 } 392 393 if len(newDefaulters) == 0 { 394 klog.V(5).Infof("no defaulters in package %s", pkg.Name) 395 } 396 397 path := pkg.Path 398 // if the source path is within a /vendor/ directory (for example, 399 // k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow 400 // generation to output to the proper relative path (under vendor). 401 // Otherwise, the generator will create the file in the wrong location 402 // in the output directory. 403 // TODO: build a more fundamental concept in gengo for dealing with modifications 404 // to vendored packages. 405 if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) { 406 expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase) 407 if strings.Contains(expandedPath, "/vendor/") { 408 path = expandedPath 409 } 410 } 411 412 packages = append(packages, 413 &generator.DefaultPackage{ 414 PackageName: filepath.Base(pkg.Path), 415 PackagePath: path, 416 HeaderText: header, 417 GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { 418 return []generator.Generator{ 419 NewGenDefaulter(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, existingDefaulters, newDefaulters, peerPkgs), 420 } 421 }, 422 FilterFunc: func(c *generator.Context, t *types.Type) bool { 423 return t.Name.Package == typesPkg.Path 424 }, 425 }) 426 } 427 return packages 428 } 429 430 // callTreeForType contains fields necessary to build a tree for types. 431 type callTreeForType struct { 432 existingDefaulters defaulterFuncMap 433 newDefaulters defaulterFuncMap 434 currentlyBuildingTypes map[*types.Type]bool 435 } 436 437 func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType { 438 return &callTreeForType{ 439 existingDefaulters: existingDefaulters, 440 newDefaulters: newDefaulters, 441 currentlyBuildingTypes: make(map[*types.Type]bool), 442 } 443 } 444 445 // resolveType follows pointers and aliases of `t` until reaching the first 446 // non-pointer type in `t's` herarchy 447 func resolveTypeAndDepth(t *types.Type) (*types.Type, int) { 448 var prev *types.Type 449 depth := 0 450 for prev != t { 451 prev = t 452 if t.Kind == types.Alias { 453 t = t.Underlying 454 } else if t.Kind == types.Pointer { 455 t = t.Elem 456 depth += 1 457 } 458 } 459 return t, depth 460 } 461 462 // getPointerElementPath follows pointers and aliases to returns all 463 // pointer elements in the path from the given type, to its base value type. 464 // 465 // Example: 466 // 467 // type MyString string 468 // type MyStringPointer *MyString 469 // type MyStringPointerPointer *MyStringPointer 470 // type MyStringAlias MyStringPointer 471 // type MyStringAliasPointer *MyStringAlias 472 // type MyStringAliasDoublePointer **MyStringAlias 473 // 474 // t | defaultPointerElementPath(t) 475 // ---------------------------|---------------------------------------- 476 // MyString | [] 477 // MyStringPointer | [MyString] 478 // MyStringPointerPointer | [MyStringPointer, MyString] 479 // MyStringAlias | [MyStringPointer, MyString] 480 // MyStringAliasPointer | [MyStringAlias, MyStringPointer, MyString] 481 // MyStringAliasDoublePointer | [*MyStringAlias, MyStringAlias, MyStringPointer, MyString] 482 func getPointerElementPath(t *types.Type) []*types.Type { 483 var path []*types.Type 484 for t != nil { 485 switch t.Kind { 486 case types.Alias: 487 t = t.Underlying 488 case types.Pointer: 489 t = t.Elem 490 path = append(path, t) 491 default: 492 t = nil 493 } 494 } 495 return path 496 } 497 498 // getNestedDefault returns the first default value when resolving alias types 499 func getNestedDefault(t *types.Type) string { 500 var prev *types.Type 501 for prev != t { 502 prev = t 503 defaultMap := extractDefaultTag(t.CommentLines) 504 if len(defaultMap) == 1 && defaultMap[0] != "" { 505 return defaultMap[0] 506 } 507 if t.Kind == types.Alias { 508 t = t.Underlying 509 } else if t.Kind == types.Pointer { 510 t = t.Elem 511 } 512 } 513 return "" 514 } 515 516 var refRE = regexp.MustCompile(`^ref\((?P<reference>[^"]+)\)$`) 517 var refREIdentIndex = refRE.SubexpIndex("reference") 518 519 // ParseSymbolReference looks for strings that match one of the following: 520 // - ref(Ident) 521 // - ref(pkgpath.Ident) 522 // If the input string matches either of these, it will return the (optional) 523 // pkgpath, the Ident, and true. Otherwise it will return empty strings and 524 // false. 525 func ParseSymbolReference(s, sourcePackage string) (types.Name, bool) { 526 matches := refRE.FindStringSubmatch(s) 527 if len(matches) < refREIdentIndex || matches[refREIdentIndex] == "" { 528 return types.Name{}, false 529 } 530 531 contents := matches[refREIdentIndex] 532 name := types.ParseFullyQualifiedName(contents) 533 if len(name.Package) == 0 { 534 name.Package = sourcePackage 535 } 536 return name, true 537 } 538 539 func populateDefaultValue(node *callNode, t *types.Type, tags string, commentLines []string, commentPackage string) *callNode { 540 defaultMap := extractDefaultTag(commentLines) 541 var defaultString string 542 if len(defaultMap) == 1 { 543 defaultString = defaultMap[0] 544 } else if len(defaultMap) > 1 { 545 klog.Fatalf("Found more than one default tag for %v", t.Kind) 546 } 547 548 baseT, depth := resolveTypeAndDepth(t) 549 if depth > 0 && defaultString == "" { 550 defaultString = getNestedDefault(t) 551 } 552 553 if len(defaultString) == 0 { 554 return node 555 } 556 var symbolReference types.Name 557 var defaultValue interface{} 558 if id, ok := ParseSymbolReference(defaultString, commentPackage); ok { 559 symbolReference = id 560 defaultString = "" 561 } else if err := json.Unmarshal([]byte(defaultString), &defaultValue); err != nil { 562 klog.Fatalf("Failed to unmarshal default: %v", err) 563 } 564 565 if defaultValue != nil { 566 zero := typeZeroValue[t.String()] 567 if reflect.DeepEqual(defaultValue, zero) { 568 // If the default value annotation matches the default value for the type, 569 // do not generate any defaulting function 570 return node 571 } 572 } 573 574 // callNodes are not automatically generated for primitive types. Generate one if the callNode does not exist 575 if node == nil { 576 node = &callNode{} 577 node.markerOnly = true 578 } 579 580 node.defaultIsPrimitive = baseT.IsPrimitive() 581 node.defaultType = baseT 582 node.defaultTopLevelType = t 583 node.defaultValue.InlineConstant = defaultString 584 node.defaultValue.SymbolReference = symbolReference 585 return node 586 } 587 588 // build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem, 589 // slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree 590 // can be used to generate a Go function that invokes each nested function on the appropriate type. The return 591 // value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be 592 // invoked on structs today). When root is true this function will not use a newDefaulter. existingDefaulters should 593 // contain all defaulting functions by type defined in code - newDefaulters should contain all object defaulters 594 // that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil, 595 // this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for 596 // list types that call empty defaulters. 597 func (c *callTreeForType) build(t *types.Type, root bool) *callNode { 598 parent := &callNode{} 599 600 if root { 601 // the root node is always a pointer 602 parent.elem = true 603 } 604 605 defaults, _ := c.existingDefaulters[t] 606 newDefaults, generated := c.newDefaulters[t] 607 switch { 608 case !root && generated && newDefaults.object != nil: 609 parent.call = append(parent.call, newDefaults.object) 610 // if we will be generating the defaulter, it by definition is a covering 611 // defaulter, so we halt recursion 612 klog.V(6).Infof("the defaulter %s will be generated as an object defaulter", t.Name) 613 return parent 614 615 case defaults.object != nil: 616 // object defaulters are always covering 617 parent.call = append(parent.call, defaults.object) 618 return parent 619 620 case defaults.base != nil: 621 parent.call = append(parent.call, defaults.base) 622 // if the base function indicates it "covers" (it already includes defaulters) 623 // we can halt recursion 624 if checkTag(defaults.base.CommentLines, "covers") { 625 klog.V(6).Infof("the defaulter %s indicates it covers all sub generators", t.Name) 626 return parent 627 } 628 } 629 630 // base has been added already, now add any additional defaulters defined for this object 631 parent.call = append(parent.call, defaults.additional...) 632 633 // if the type already exists, don't build the tree for it and don't generate anything. 634 // This is used to avoid recursion for nested recursive types. 635 if c.currentlyBuildingTypes[t] { 636 return nil 637 } 638 // if type doesn't exist, mark it as existing 639 c.currentlyBuildingTypes[t] = true 640 641 defer func() { 642 // The type will now acts as a parent, not a nested recursive type. 643 // We can now build the tree for it safely. 644 c.currentlyBuildingTypes[t] = false 645 }() 646 647 switch t.Kind { 648 case types.Pointer: 649 if child := c.build(t.Elem, false); child != nil { 650 child.elem = true 651 parent.children = append(parent.children, *child) 652 } 653 case types.Slice, types.Array: 654 if child := c.build(t.Elem, false); child != nil { 655 child.index = true 656 if t.Elem.Kind == types.Pointer { 657 child.elem = true 658 } 659 parent.children = append(parent.children, *child) 660 } else if member := populateDefaultValue(nil, t.Elem, "", t.Elem.CommentLines, t.Elem.Name.Package); member != nil { 661 member.index = true 662 parent.children = append(parent.children, *member) 663 } 664 case types.Map: 665 if child := c.build(t.Elem, false); child != nil { 666 child.key = true 667 parent.children = append(parent.children, *child) 668 } else if member := populateDefaultValue(nil, t.Elem, "", t.Elem.CommentLines, t.Elem.Name.Package); member != nil { 669 member.key = true 670 parent.children = append(parent.children, *member) 671 } 672 673 case types.Struct: 674 for _, field := range t.Members { 675 name := field.Name 676 if len(name) == 0 { 677 if field.Type.Kind == types.Pointer { 678 name = field.Type.Elem.Name.Name 679 } else { 680 name = field.Type.Name.Name 681 } 682 } 683 if child := c.build(field.Type, false); child != nil { 684 child.field = name 685 populateDefaultValue(child, field.Type, field.Tags, field.CommentLines, field.Type.Name.Package) 686 parent.children = append(parent.children, *child) 687 } else if member := populateDefaultValue(nil, field.Type, field.Tags, field.CommentLines, t.Name.Package); member != nil { 688 member.field = name 689 parent.children = append(parent.children, *member) 690 } 691 } 692 case types.Alias: 693 if child := c.build(t.Underlying, false); child != nil { 694 parent.children = append(parent.children, *child) 695 } 696 } 697 if len(parent.children) == 0 && len(parent.call) == 0 { 698 //klog.V(6).Infof("decided type %s needs no generation", t.Name) 699 return nil 700 } 701 return parent 702 } 703 704 const ( 705 runtimePackagePath = "k8s.io/apimachinery/pkg/runtime" 706 conversionPackagePath = "k8s.io/apimachinery/pkg/conversion" 707 ) 708 709 // genDefaulter produces a file with a autogenerated conversions. 710 type genDefaulter struct { 711 generator.DefaultGen 712 typesPackage string 713 outputPackage string 714 peerPackages []string 715 newDefaulters defaulterFuncMap 716 existingDefaulters defaulterFuncMap 717 imports namer.ImportTracker 718 typesForInit []*types.Type 719 } 720 721 func NewGenDefaulter(sanitizedName, typesPackage, outputPackage string, existingDefaulters, newDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator { 722 return &genDefaulter{ 723 DefaultGen: generator.DefaultGen{ 724 OptionalName: sanitizedName, 725 }, 726 typesPackage: typesPackage, 727 outputPackage: outputPackage, 728 peerPackages: peerPkgs, 729 newDefaulters: newDefaulters, 730 existingDefaulters: existingDefaulters, 731 imports: generator.NewImportTrackerForPackage(outputPackage), 732 typesForInit: make([]*types.Type, 0), 733 } 734 } 735 736 func (g *genDefaulter) Namers(c *generator.Context) namer.NameSystems { 737 // Have the raw namer for this file track what it imports. 738 return namer.NameSystems{ 739 "raw": namer.NewRawNamer(g.outputPackage, g.imports), 740 } 741 } 742 743 func (g *genDefaulter) isOtherPackage(pkg string) bool { 744 if pkg == g.outputPackage { 745 return false 746 } 747 if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) { 748 return false 749 } 750 return true 751 } 752 753 func (g *genDefaulter) Filter(c *generator.Context, t *types.Type) bool { 754 defaults, ok := g.newDefaulters[t] 755 if !ok || defaults.object == nil { 756 return false 757 } 758 g.typesForInit = append(g.typesForInit, t) 759 return true 760 } 761 762 func (g *genDefaulter) Imports(c *generator.Context) (imports []string) { 763 var importLines []string 764 for _, singleImport := range g.imports.ImportLines() { 765 if g.isOtherPackage(singleImport) { 766 importLines = append(importLines, singleImport) 767 } 768 } 769 return importLines 770 } 771 772 func (g *genDefaulter) Init(c *generator.Context, w io.Writer) error { 773 sw := generator.NewSnippetWriter(w, c, "$", "$") 774 775 scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"}) 776 schemePtr := &types.Type{ 777 Kind: types.Pointer, 778 Elem: scheme, 779 } 780 sw.Do("// RegisterDefaults adds defaulters functions to the given scheme.\n", nil) 781 sw.Do("// Public to allow building arbitrary schemes.\n", nil) 782 sw.Do("// All generated defaulters are covering - they call all nested defaulters.\n", nil) 783 sw.Do("func RegisterDefaults(scheme $.|raw$) error {\n", schemePtr) 784 for _, t := range g.typesForInit { 785 args := defaultingArgsFromType(t) 786 sw.Do("scheme.AddTypeDefaultingFunc(&$.inType|raw${}, func(obj interface{}) { $.inType|objectdefaultfn$(obj.(*$.inType|raw$)) })\n", args) 787 } 788 sw.Do("return nil\n", nil) 789 sw.Do("}\n\n", nil) 790 return sw.Error() 791 } 792 793 func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { 794 if _, ok := g.newDefaulters[t]; !ok { 795 return nil 796 } 797 798 klog.V(5).Infof("generating for type %v", t) 799 800 callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true) 801 if callTree == nil { 802 klog.V(5).Infof(" no defaulters defined") 803 return nil 804 } 805 i := 0 806 callTree.VisitInOrder(func(ancestors []*callNode, current *callNode) { 807 if ref := ¤t.defaultValue.SymbolReference; len(ref.Name) > 0 { 808 // Ensure package for symbol is imported in output generation 809 g.imports.AddSymbol(*ref) 810 811 // Rewrite the fully qualified name using the local package name 812 // from the imports 813 ref.Package = g.imports.LocalNameOf(ref.Package) 814 } 815 816 if len(current.call) == 0 { 817 return 818 } 819 path := callPath(append(ancestors, current)) 820 klog.V(5).Infof(" %d: %s", i, path) 821 i++ 822 }) 823 824 sw := generator.NewSnippetWriter(w, c, "$", "$") 825 g.generateDefaulter(t, callTree, sw) 826 return sw.Error() 827 } 828 829 func defaultingArgsFromType(inType *types.Type) generator.Args { 830 return generator.Args{ 831 "inType": inType, 832 } 833 } 834 835 func (g *genDefaulter) generateDefaulter(inType *types.Type, callTree *callNode, sw *generator.SnippetWriter) { 836 sw.Do("func $.inType|objectdefaultfn$(in *$.inType|raw$) {\n", defaultingArgsFromType(inType)) 837 callTree.WriteMethod("in", 0, nil, sw) 838 sw.Do("}\n\n", nil) 839 } 840 841 // callNode represents an entry in a tree of Go type accessors - the path from the root to a leaf represents 842 // how in Go code an access would be performed. For example, if a defaulting function exists on a container 843 // lifecycle hook, to invoke that defaulter correctly would require this Go code: 844 // 845 // for i := range pod.Spec.Containers { 846 // o := &pod.Spec.Containers[i] 847 // if o.LifecycleHook != nil { 848 // SetDefaults_LifecycleHook(o.LifecycleHook) 849 // } 850 // } 851 // 852 // That would be represented by a call tree like: 853 // 854 // callNode 855 // field: "Spec" 856 // children: 857 // - field: "Containers" 858 // children: 859 // - index: true 860 // children: 861 // - field: "LifecycleHook" 862 // elem: true 863 // call: 864 // - SetDefaults_LifecycleHook 865 // 866 // which we can traverse to build that Go struct (you must call the field Spec, then Containers, then range over 867 // that field, then check whether the LifecycleHook field is nil, before calling SetDefaults_LifecycleHook on 868 // the pointer to that field). 869 type callNode struct { 870 // field is the name of the Go member to access 871 field string 872 // key is true if this is a map and we must range over the key and values 873 key bool 874 // index is true if this is a slice and we must range over the slice values 875 index bool 876 // elem is true if the previous elements refer to a pointer (typically just field) 877 elem bool 878 879 // call is all of the functions that must be invoked on this particular node, in order 880 call []*types.Type 881 // children is the child call nodes that must also be traversed 882 children []callNode 883 884 // defaultValue is the defaultValue of a callNode struct 885 // Only primitive types and pointer types are eligible to have a default value 886 defaultValue defaultValue 887 888 // defaultIsPrimitive is used to determine how to assign the default value. 889 // Primitive types will be directly assigned while complex types will use JSON unmarshalling 890 defaultIsPrimitive bool 891 892 // markerOnly is true if the callNode exists solely to fill in a default value 893 markerOnly bool 894 895 // defaultType is the transitive underlying/element type of the node. 896 // The provided default value literal or reference is expected to be 897 // convertible to this type. 898 // 899 // e.g: 900 // node type = *string -> defaultType = string 901 // node type = StringPointerAlias -> defaultType = string 902 // Only populated if defaultIsPrimitive is true 903 defaultType *types.Type 904 905 // defaultTopLevelType is the final type the value should resolve to 906 // This is in constrast with default type, which resolves aliases and pointers. 907 defaultTopLevelType *types.Type 908 } 909 910 type defaultValue struct { 911 // The value was written directly in the marker comment and 912 // has been parsed as JSON 913 InlineConstant string 914 // The name of the symbol relative to the parsed package path 915 // i.e. k8s.io/pkg.apis.v1.Foo if from another package or simply `Foo` 916 // if within the same package. 917 SymbolReference types.Name 918 } 919 920 func (d defaultValue) IsEmpty() bool { 921 resolved := d.Resolved() 922 return resolved == "" 923 } 924 925 func (d defaultValue) Resolved() string { 926 if len(d.InlineConstant) > 0 { 927 return d.InlineConstant 928 } 929 return d.SymbolReference.String() 930 } 931 932 // CallNodeVisitorFunc is a function for visiting a call tree. ancestors is the list of all parents 933 // of this node to the root of the tree - will be empty at the root. 934 type CallNodeVisitorFunc func(ancestors []*callNode, node *callNode) 935 936 func (n *callNode) VisitInOrder(fn CallNodeVisitorFunc) { 937 n.visitInOrder(nil, fn) 938 } 939 940 func (n *callNode) visitInOrder(ancestors []*callNode, fn CallNodeVisitorFunc) { 941 fn(ancestors, n) 942 ancestors = append(ancestors, n) 943 for i := range n.children { 944 n.children[i].visitInOrder(ancestors, fn) 945 } 946 } 947 948 var ( 949 indexVariables = "ijklmnop" 950 localVariables = "abcdefgh" 951 ) 952 953 // varsForDepth creates temporary variables guaranteed to be unique within lexical Go scopes 954 // of this depth in a function. It uses canonical Go loop variables for the first 7 levels 955 // and then resorts to uglier prefixes. 956 func varsForDepth(depth int) (index, local string) { 957 if depth > len(indexVariables) { 958 index = fmt.Sprintf("i%d", depth) 959 } else { 960 index = indexVariables[depth : depth+1] 961 } 962 if depth > len(localVariables) { 963 local = fmt.Sprintf("local%d", depth) 964 } else { 965 local = localVariables[depth : depth+1] 966 } 967 return 968 } 969 970 // writeCalls generates a list of function calls based on the calls field for the provided variable 971 // name and pointer. 972 func (n *callNode) writeCalls(varName string, isVarPointer bool, sw *generator.SnippetWriter) { 973 accessor := varName 974 if !isVarPointer { 975 accessor = "&" + accessor 976 } 977 for _, fn := range n.call { 978 sw.Do("$.fn|raw$($.var$)\n", generator.Args{ 979 "fn": fn, 980 "var": accessor, 981 }) 982 } 983 } 984 985 func getTypeZeroValue(t string) (interface{}, error) { 986 defaultZero, ok := typeZeroValue[t] 987 if !ok { 988 return nil, fmt.Errorf("Cannot find zero value for type %v in typeZeroValue", t) 989 } 990 991 // To generate the code for empty string, they must be quoted 992 if defaultZero == "" { 993 defaultZero = strconv.Quote(defaultZero.(string)) 994 } 995 return defaultZero, nil 996 } 997 998 func (n *callNode) writeDefaulter(varName string, index string, isVarPointer bool, sw *generator.SnippetWriter) { 999 if n.defaultValue.IsEmpty() { 1000 return 1001 } 1002 args := generator.Args{ 1003 "defaultValue": n.defaultValue.Resolved(), 1004 "varName": varName, 1005 "index": index, 1006 "varTopType": n.defaultTopLevelType, 1007 } 1008 1009 variablePlaceholder := "" 1010 1011 if n.index { 1012 // Defaulting for array 1013 variablePlaceholder = "$.varName$[$.index$]" 1014 } else if n.key { 1015 // Defaulting for map 1016 variablePlaceholder = "$.varName$[$.index$]" 1017 mapDefaultVar := args["index"].(string) + "_default" 1018 args["mapDefaultVar"] = mapDefaultVar 1019 } else { 1020 // Defaulting for primitive type 1021 variablePlaceholder = "$.varName$" 1022 } 1023 1024 // defaultIsPrimitive is true if the type or underlying type (in an array/map) is primitive 1025 // or is a pointer to a primitive type 1026 // (Eg: int, map[string]*string, []int) 1027 if n.defaultIsPrimitive { 1028 // If the default value is a primitive when the assigned type is a pointer 1029 // keep using the address-of operator on the primitive value until the types match 1030 if pointerPath := getPointerElementPath(n.defaultTopLevelType); len(pointerPath) > 0 { 1031 // If the destination is a pointer, the last element in 1032 // defaultDepth is the element type of the bottommost pointer: 1033 // the base type of our default value. 1034 destElemType := pointerPath[len(pointerPath)-1] 1035 pointerArgs := args.WithArgs(generator.Args{ 1036 "varDepth": len(pointerPath), 1037 "baseElemType": destElemType, 1038 }) 1039 1040 sw.Do(fmt.Sprintf("if %s == nil {\n", variablePlaceholder), pointerArgs) 1041 if len(n.defaultValue.InlineConstant) > 0 { 1042 // If default value is a literal then it can be assigned via var stmt 1043 sw.Do("var ptrVar$.varDepth$ $.baseElemType|raw$ = $.defaultValue$\n", pointerArgs) 1044 } else { 1045 // If default value is not a literal then it may need to be casted 1046 // to the base type of the destination pointer 1047 sw.Do("ptrVar$.varDepth$ := $.baseElemType|raw$($.defaultValue$)\n", pointerArgs) 1048 } 1049 1050 for i := len(pointerPath); i >= 1; i-- { 1051 dest := fmt.Sprintf("ptrVar%d", i-1) 1052 assignment := ":=" 1053 if i == 1 { 1054 // Last assignment is into the storage destination 1055 dest = variablePlaceholder 1056 assignment = "=" 1057 } 1058 1059 sourceType := "*" + destElemType.String() 1060 if i == len(pointerPath) { 1061 // Initial value is not a pointer 1062 sourceType = destElemType.String() 1063 } 1064 destElemType = pointerPath[i-1] 1065 1066 // Cannot include `dest` into args since its value may be 1067 // `variablePlaceholder` which is a template, not a value 1068 elementArgs := pointerArgs.WithArgs(generator.Args{ 1069 "assignment": assignment, 1070 "source": fmt.Sprintf("ptrVar%d", i), 1071 "destElemType": destElemType, 1072 }) 1073 1074 // Skip cast if type is exact match 1075 if destElemType.String() == sourceType { 1076 sw.Do(fmt.Sprintf("%v $.assignment$ &$.source$\n", dest), elementArgs) 1077 } else { 1078 sw.Do(fmt.Sprintf("%v $.assignment$ (*$.destElemType|raw$)(&$.source$)\n", dest), elementArgs) 1079 } 1080 } 1081 } else { 1082 // For primitive types, nil checks cannot be used and the zero value must be determined 1083 defaultZero, err := getTypeZeroValue(n.defaultType.String()) 1084 if err != nil { 1085 klog.Error(err) 1086 } 1087 args["defaultZero"] = defaultZero 1088 1089 sw.Do(fmt.Sprintf("if %s == $.defaultZero$ {\n", variablePlaceholder), args) 1090 1091 if len(n.defaultValue.InlineConstant) > 0 { 1092 sw.Do(fmt.Sprintf("%s = $.defaultValue$", variablePlaceholder), args) 1093 } else { 1094 sw.Do(fmt.Sprintf("%s = $.varTopType|raw$($.defaultValue$)", variablePlaceholder), args) 1095 } 1096 } 1097 } else { 1098 sw.Do(fmt.Sprintf("if %s == nil {\n", variablePlaceholder), args) 1099 // Map values are not directly addressable and we need a temporary variable to do json unmarshalling 1100 // This applies to maps with non-primitive values (eg: map[string]SubStruct) 1101 if n.key { 1102 sw.Do("$.mapDefaultVar$ := $.varName$[$.index$]\n", args) 1103 sw.Do("if err := json.Unmarshal([]byte(`$.defaultValue$`), &$.mapDefaultVar$); err != nil {\n", args) 1104 } else { 1105 variablePointer := variablePlaceholder 1106 if !isVarPointer { 1107 variablePointer = "&" + variablePointer 1108 } 1109 sw.Do(fmt.Sprintf("if err := json.Unmarshal([]byte(`$.defaultValue$`), %s); err != nil {\n", variablePointer), args) 1110 } 1111 sw.Do("panic(err)\n", nil) 1112 sw.Do("}\n", nil) 1113 if n.key { 1114 sw.Do("$.varName$[$.index$] = $.mapDefaultVar$\n", args) 1115 } 1116 } 1117 sw.Do("}\n", nil) 1118 } 1119 1120 // WriteMethod performs an in-order traversal of the calltree, generating loops and if blocks as necessary 1121 // to correctly turn the call tree into a method body that invokes all calls on all child nodes of the call tree. 1122 // Depth is used to generate local variables at the proper depth. 1123 func (n *callNode) WriteMethod(varName string, depth int, ancestors []*callNode, sw *generator.SnippetWriter) { 1124 // if len(n.call) > 0 { 1125 // sw.Do(fmt.Sprintf("// %s\n", callPath(append(ancestors, n)).String()), nil) 1126 // } 1127 1128 if len(n.field) > 0 { 1129 varName = varName + "." + n.field 1130 } 1131 1132 index, local := varsForDepth(depth) 1133 vars := generator.Args{ 1134 "index": index, 1135 "local": local, 1136 "var": varName, 1137 } 1138 1139 isPointer := n.elem && !n.index 1140 if isPointer && len(ancestors) > 0 { 1141 sw.Do("if $.var$ != nil {\n", vars) 1142 } 1143 1144 switch { 1145 case n.index: 1146 sw.Do("for $.index$ := range $.var$ {\n", vars) 1147 if !n.markerOnly { 1148 if n.elem { 1149 sw.Do("$.local$ := $.var$[$.index$]\n", vars) 1150 } else { 1151 sw.Do("$.local$ := &$.var$[$.index$]\n", vars) 1152 } 1153 } 1154 1155 n.writeDefaulter(varName, index, isPointer, sw) 1156 n.writeCalls(local, true, sw) 1157 for i := range n.children { 1158 n.children[i].WriteMethod(local, depth+1, append(ancestors, n), sw) 1159 } 1160 sw.Do("}\n", nil) 1161 case n.key: 1162 if !n.defaultValue.IsEmpty() { 1163 // Map keys are typed and cannot share the same index variable as arrays and other maps 1164 index = index + "_" + ancestors[len(ancestors)-1].field 1165 vars["index"] = index 1166 sw.Do("for $.index$ := range $.var$ {\n", vars) 1167 n.writeDefaulter(varName, index, isPointer, sw) 1168 sw.Do("}\n", nil) 1169 } 1170 default: 1171 n.writeDefaulter(varName, index, isPointer, sw) 1172 n.writeCalls(varName, isPointer, sw) 1173 for i := range n.children { 1174 n.children[i].WriteMethod(varName, depth, append(ancestors, n), sw) 1175 } 1176 } 1177 1178 if isPointer && len(ancestors) > 0 { 1179 sw.Do("}\n", nil) 1180 } 1181 } 1182 1183 type callPath []*callNode 1184 1185 // String prints a representation of a callPath that roughly approximates what a Go accessor 1186 // would look like. Used for debugging only. 1187 func (path callPath) String() string { 1188 if len(path) == 0 { 1189 return "<none>" 1190 } 1191 var parts []string 1192 for _, p := range path { 1193 last := len(parts) - 1 1194 switch { 1195 case p.elem: 1196 if len(parts) > 0 { 1197 parts[last] = "*" + parts[last] 1198 } else { 1199 parts = append(parts, "*") 1200 } 1201 case p.index: 1202 if len(parts) > 0 { 1203 parts[last] = parts[last] + "[i]" 1204 } else { 1205 parts = append(parts, "[i]") 1206 } 1207 case p.key: 1208 if len(parts) > 0 { 1209 parts[last] = parts[last] + "[key]" 1210 } else { 1211 parts = append(parts, "[key]") 1212 } 1213 default: 1214 if len(p.field) > 0 { 1215 parts = append(parts, p.field) 1216 } else { 1217 parts = append(parts, "<root>") 1218 } 1219 } 1220 } 1221 var calls []string 1222 for _, fn := range path[len(path)-1].call { 1223 calls = append(calls, fn.Name.String()) 1224 } 1225 if len(calls) == 0 { 1226 calls = append(calls, "<none>") 1227 } 1228 1229 return strings.Join(parts, ".") + " calls " + strings.Join(calls, ", ") 1230 }