func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { boilerplate, err := arguments.LoadGoBoilerplate() if err != nil { glog.Fatalf("Failed loading boilerplate: %v", err) } header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) header = append(header, []byte( ` // This file was autogenerated by openapi-gen. Do not edit it manually! `)...) if err := context.AddDir(arguments.OutputPackagePath); err != nil { glog.Fatalf("Failed to load output package: %v", err) } pkg := context.Universe[arguments.OutputPackagePath] if pkg == nil { glog.Fatalf("Got nil output package: %v", err) } return generator.Packages{ &generator.DefaultPackage{ PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0], PackagePath: pkg.Path, HeaderText: header, GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { return []generator.Generator{NewOpenAPIGen(arguments.OutputFileBaseName, pkg, context)} }, FilterFunc: func(c *generator.Context, t *types.Type) bool { // There is a conflict between this codegen and codecgen, we should avoid types generated for codecgen if strings.HasPrefix(t.Name.Name, "codecSelfer") { return false } pkg := context.Universe.Package(t.Name.Package) if hasOpenAPITagValue(pkg.Comments, tagValueTrue) { return !hasOpenAPITagValue(t.CommentLines, tagValueFalse) } if hasOpenAPITagValue(t.CommentLines, tagValueTrue) { return true } return false }, }, } }
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...) header = append(header, []byte( ` // This file was autogenerated by defaulter-gen. Do not edit it manually! `)...) // 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 } // 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 } newDefaulters := defaulterFuncMap{} for _, t := range pkg.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 buildCallTreeForType(t, true, existingDefaulters, newDefaulters) != 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) } packages = append(packages, &generator.DefaultPackage{ PackageName: filepath.Base(pkg.Path), PackagePath: pkg.Path, HeaderText: header, GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { return []generator.Generator{ NewGenDefaulter(arguments.OutputFileBaseName, pkg.Path, existingDefaulters, newDefaulters, peerPkgs), } }, FilterFunc: func(c *generator.Context, t *types.Type) bool { return t.Name.Package == pkg.Path }, }) } return packages }
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...) header = append(header, []byte("\n// This file was autogenerated by conversion-gen. Do not edit it manually!\n\n")...) // Accumulate pre-existing conversion and default functions. // TODO: This is too ad-hoc. We need a better way. manualConversions := conversionFuncMap{} manualDefaults := defaulterFuncMap{} // We are generating conversions only for packages that are explicitly // passed as InputDir. 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 } // Add conversion and defaulting functions. getManualConversionFunctions(context, pkg, manualConversions) getManualDefaultingFunctions(context, pkg, manualDefaults) // Only generate conversions for packages which explicitly request it // by specifying one or more "+k8s:conversion-gen=<peer-pkg>" // in their doc.go file. peerPkgs := extractTag(pkg.Comments) if peerPkgs != nil { glog.V(5).Infof(" tags: %q", peerPkgs) } else { glog.V(5).Infof(" no tag") continue } if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok { if len(customArgs.ExtraPeerDirs) > 0 { peerPkgs = append(peerPkgs, customArgs.ExtraPeerDirs...) } } // Make sure our peer-packages are added and fully parsed. for _, pp := range peerPkgs { context.AddDir(pp) getManualConversionFunctions(context, context.Universe[pp], manualConversions) getManualDefaultingFunctions(context, context.Universe[pp], manualDefaults) } packages = append(packages, &generator.DefaultPackage{ PackageName: filepath.Base(pkg.Path), PackagePath: pkg.Path, HeaderText: header, GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { return []generator.Generator{ NewGenConversion(arguments.OutputFileBaseName, pkg.Path, manualConversions, manualDefaults, peerPkgs), } }, FilterFunc: func(c *generator.Context, t *types.Type) bool { return t.Name.Package == pkg.Path }, }) } return packages }