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
			},
		},
	}
}
示例#2
0
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
}
示例#3
0
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
}