示例#1
0
// GenerateType makes the body of a file implementing the individual typed client for type t.
func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	pkg := filepath.Base(t.Name.Package)
	namespaced := !(types.ExtractCommentTags("+", t.SecondClosestCommentLines)["nonNamespaced"] == "true")
	m := map[string]interface{}{
		"type":              t,
		"package":           pkg,
		"Package":           namer.IC(pkg),
		"Group":             namer.IC(g.group),
		"watchInterface":    c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/watch", Name: "Interface"}),
		"apiDeleteOptions":  c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "DeleteOptions"}),
		"apiListOptions":    c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "ListOptions"}),
		"apiParameterCodec": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "ParameterCodec"}),
		"namespaced":        namespaced,
	}

	sw.Do(getterComment, m)
	if namespaced {
		sw.Do(getterNamesapced, m)
	} else {
		sw.Do(getterNonNamesapced, m)
	}
	noMethods := types.ExtractCommentTags("+", t.SecondClosestCommentLines)["noMethods"] == "true"

	sw.Do(interfaceTemplate1, m)
	if !noMethods {
		sw.Do(interfaceTemplate2, m)
		// Include the UpdateStatus method if the type has a status
		if hasStatus(t) {
			sw.Do(interfaceUpdateStatusTemplate, m)
		}
		sw.Do(interfaceTemplate3, m)
	}
	sw.Do(interfaceTemplate4, m)

	if namespaced {
		sw.Do(structNamespaced, m)
		sw.Do(newStructNamespaced, m)
	} else {
		sw.Do(structNonNamespaced, m)
		sw.Do(newStructNonNamespaced, m)
	}

	if !noMethods {
		sw.Do(createTemplate, m)
		sw.Do(updateTemplate, m)
		// Generate the UpdateStatus method if the type has a status
		if hasStatus(t) {
			sw.Do(updateStatusTemplate, m)
		}
		sw.Do(deleteTemplate, m)
		sw.Do(deleteCollectionTemplate, m)
		sw.Do(getTemplate, m)
		sw.Do(listTemplate, m)
		sw.Do(watchTemplate, m)
	}

	return sw.Error()
}
示例#2
0
func isDirectlyConvertible(in, out *types.Type, preexisting conversions) bool {
	// If one of the types is Alias, resolve it.
	if in.Kind == types.Alias {
		return isConvertible(in.Underlying, out, preexisting)
	}
	if out.Kind == types.Alias {
		return isConvertible(in, out.Underlying, preexisting)
	}

	if in.Kind != out.Kind {
		return false
	}
	switch in.Kind {
	case types.Builtin, types.Struct, types.Map, types.Slice, types.Pointer:
	default:
		// We don't support conversion of other types yet.
		return false
	}
	switch out.Kind {
	case types.Builtin, types.Struct, types.Map, types.Slice, types.Pointer:
	default:
		// We don't support conversion of other types yet.
		return false
	}

	switch in.Kind {
	case types.Builtin:
		if in == out {
			return true
		}
		// TODO: Support more conversion types.
		return types.IsInteger(in) && types.IsInteger(out)
	case types.Struct:
		convertible := true
		for _, inMember := range in.Members {
			// Check if there is an out member with that name.
			outMember, found := findMember(out, inMember.Name)
			if !found {
				// Check if the member doesn't have comment:
				// "+ genconversion=false"
				// comment to ignore this field for conversion.
				// TODO: Switch to SecondClosestCommentLines.
				if types.ExtractCommentTags("+", inMember.CommentLines)["genconversion"] == "false" {
					continue
				}
				return false
			}
			convertible = convertible && isConvertible(inMember.Type, outMember.Type, preexisting)
		}
		return convertible
	case types.Map:
		return isConvertible(in.Key, out.Key, preexisting) && isConvertible(in.Elem, out.Elem, preexisting)
	case types.Slice:
		return isConvertible(in.Elem, out.Elem, preexisting)
	case types.Pointer:
		return isConvertible(in.Elem, out.Elem, preexisting)
	}
	glog.Fatalf("All other types should be filtered before")
	return false
}
示例#3
0
func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type) bool {
	var t *types.Type
	var other *types.Type
	if inType.Name.Package == g.targetPackage {
		t, other = inType, outType
	} else {
		t, other = outType, inType
	}

	if t.Name.Package != g.targetPackage {
		return false
	}
	if types.ExtractCommentTags("+", t.CommentLines)["genconversion"] == "false" {
		return false
	}
	// TODO: Consider generating functions for other kinds too.
	if t.Kind != types.Struct {
		return false
	}
	// Also, filter out private types.
	if namer.IsPrivateGoName(other.Name.Name) {
		return false
	}
	return true
}
示例#4
0
func packageForGroup(gv unversioned.GroupVersion, typeList []*types.Type, packageBasePath string, srcTreePath string, boilerplate []byte, generatedBy string) generator.Package {
	outputPackagePath := filepath.Join(packageBasePath, gv.Group, gv.Version)
	return &generator.DefaultPackage{
		PackageName: gv.Version,
		PackagePath: outputPackagePath,
		HeaderText:  boilerplate,
		PackageDocumentation: []byte(
			generatedBy +
				`// This package has the automatically generated typed clients.
`),
		// 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"},
			}
			// Since we want a file per type that we generate a client for, we
			// have to provide a function for this.
			for _, t := range typeList {
				generators = append(generators, &genClientForType{
					DefaultGen: generator.DefaultGen{
						OptionalName: strings.ToLower(c.Namers["private"].Name(t)),
					},
					outputPackage: outputPackagePath,
					group:         normalization.BeforeFirstDot(gv.Group),
					typeToMatch:   t,
					imports:       generator.NewImportTracker(),
				})
			}

			generators = append(generators, &genGroup{
				DefaultGen: generator.DefaultGen{
					OptionalName: normalization.BeforeFirstDot(gv.Group) + "_client",
				},
				outputPackage: outputPackagePath,
				group:         gv.Group,
				version:       gv.Version,
				types:         typeList,
				imports:       generator.NewImportTracker(),
			})

			expansionFileName := "generated_expansion"
			// To avoid overriding user's manual modification, only generate the expansion file if it doesn't exist.
			if _, err := os.Stat(filepath.Join(srcTreePath, outputPackagePath, expansionFileName+".go")); os.IsNotExist(err) {
				generators = append(generators, &genExpansion{
					DefaultGen: generator.DefaultGen{
						OptionalName: expansionFileName,
					},
					types: typeList,
				})
			}

			return generators
		},
		FilterFunc: func(c *generator.Context, t *types.Type) bool {
			return types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] == "true"
		},
	}
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	groupToTypes := map[string][]*types.Type{}
	for _, inputDir := range arguments.InputDirs {
		p := context.Universe.Package(inputDir)
		for _, t := range p.Types {
			if types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] != "true" {
				continue
			}
			group := filepath.Base(t.Name.Package)
			// Special case for the legacy API.
			if group == "api" {
				group = "legacy"
			}
			if _, found := groupToTypes[group]; !found {
				groupToTypes[group] = []*types.Type{}
			}
			groupToTypes[group] = append(groupToTypes[group], t)
		}
	}

	var packageList []generator.Package
	orderer := namer.Orderer{namer.NewPrivateNamer(0)}
	for group, types := range groupToTypes {
		packageList = append(packageList, packageForGroup(group, "unversioned", orderer.OrderTypes(types), arguments.OutputPackagePath, boilerplate))
	}

	return generator.Packages(packageList)
}
func (g *genFakeForGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	const pkgTestingCore = "k8s.io/kubernetes/pkg/client/testing/core"
	m := map[string]interface{}{
		"group": g.group,
		"Group": namer.IC(g.group),
		"Fake":  c.Universe.Type(types.Name{Package: pkgTestingCore, Name: "Fake"}),
	}
	sw.Do(groupClientTemplate, m)
	for _, t := range g.types {
		wrapper := map[string]interface{}{
			"type":              t,
			"Group":             namer.IC(g.group),
			"realClientPackage": filepath.Base(g.realClientPath),
		}
		namespaced := !(types.ExtractCommentTags("+", t.SecondClosestCommentLines)["nonNamespaced"] == "true")
		if namespaced {
			sw.Do(getterImplNamespaced, wrapper)
		} else {
			sw.Do(getterImplNonNamespaced, wrapper)

		}
	}
	return sw.Error()
}
示例#7
0
// 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 types.ExtractCommentTags("+", t.CommentLines)["protobuf.nullable"] != "true" {
		return false
	}
	return true
}
func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	const pkgUnversioned = "k8s.io/kubernetes/pkg/client/unversioned"
	const pkgRegistered = "k8s.io/kubernetes/pkg/apimachinery/registered"
	const pkgAPI = "k8s.io/kubernetes/pkg/api"
	apiPath := func(group string) string {
		if group == "legacy" {
			return `"/api"`
		}
		return `"/apis"`
	}

	canonize := func(group string) string {
		if group == "legacy" {
			return ""
		}
		return group
	}

	m := map[string]interface{}{
		"group":                      g.group,
		"Group":                      namer.IC(g.group),
		"canonicalGroup":             canonize(g.group),
		"types":                      g.types,
		"Config":                     c.Universe.Type(types.Name{Package: pkgUnversioned, Name: "Config"}),
		"DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: pkgUnversioned, Name: "DefaultKubernetesUserAgent"}),
		"RESTClient":                 c.Universe.Type(types.Name{Package: pkgUnversioned, Name: "RESTClient"}),
		"RESTClientFor":              c.Universe.Function(types.Name{Package: pkgUnversioned, Name: "RESTClientFor"}),
		"latestGroup":                c.Universe.Variable(types.Name{Package: pkgRegistered, Name: "Group"}),
		"GroupOrDie":                 c.Universe.Variable(types.Name{Package: pkgRegistered, Name: "GroupOrDie"}),
		"apiPath":                    apiPath(g.group),
		"codecs":                     c.Universe.Variable(types.Name{Package: pkgAPI, Name: "Codecs"}),
	}
	sw.Do(groupInterfaceTemplate, m)
	sw.Do(groupClientTemplate, m)
	for _, t := range g.types {
		wrapper := map[string]interface{}{
			"type":  t,
			"Group": namer.IC(g.group),
		}
		namespaced := !(types.ExtractCommentTags("+", t.SecondClosestCommentLines)["nonNamespaced"] == "true")
		if namespaced {
			sw.Do(getterImplNamespaced, wrapper)
		} else {
			sw.Do(getterImplNonNamespaced, wrapper)

		}
	}
	sw.Do(newClientForConfigTemplate, m)
	sw.Do(newClientForConfigOrDieTemplate, m)
	sw.Do(newClientForRESTClientTemplate, m)
	sw.Do(setClientDefaultsTemplate, m)

	return sw.Error()
}
示例#9
0
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	customArgs, ok := arguments.CustomArgs.(clientgenargs.Args)
	if !ok {
		glog.Fatalf("cannot convert arguments.CustomArgs to clientgenargs.Args")
	}

	if len(customArgs.CmdArgs) != 0 {
		boilerplate = append(boilerplate, []byte(fmt.Sprintf("\n// This file is generated by client-gen with arguments: %s\n\n", customArgs.CmdArgs))...)
	} else {
		boilerplate = append(boilerplate, []byte(fmt.Sprintf("\n// This file is generated by client-gen with the default arguments.\n\n"))...)
	}
	gvToTypes := map[unversioned.GroupVersion][]*types.Type{}
	for gv, inputDir := range customArgs.GroupVersionToInputPath {
		p := context.Universe.Package(inputDir)
		for _, t := range p.Types {
			if types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] != "true" {
				continue
			}
			if _, found := gvToTypes[gv]; !found {
				gvToTypes[gv] = []*types.Type{}
			}
			gvToTypes[gv] = append(gvToTypes[gv], t)
		}
	}

	var packageList []generator.Package
	typedClientBasePath := filepath.Join(customArgs.ClientsetOutputPath, customArgs.ClientsetName, "typed")

	packageList = append(packageList, packageForClientset(customArgs, typedClientBasePath, boilerplate))
	if customArgs.FakeClient {
		packageList = append(packageList, fake.PackageForClientset(customArgs, typedClientBasePath, boilerplate))
	}

	// If --clientset-only=true, we don't regenerate the individual typed clients.
	if customArgs.ClientsetOnly {
		return generator.Packages(packageList)
	}

	orderer := namer.Orderer{namer.NewPrivateNamer(0)}
	for _, gv := range customArgs.GroupVersions {
		types := gvToTypes[gv]
		packageList = append(packageList, packageForGroup(normalization.GroupVersion(gv), orderer.OrderTypes(types), typedClientBasePath, arguments.OutputBase, boilerplate))
		if customArgs.FakeClient {
			packageList = append(packageList, fake.PackageForGroup(normalization.GroupVersion(gv), orderer.OrderTypes(types), typedClientBasePath, arguments.OutputBase, boilerplate))
		}
	}

	return generator.Packages(packageList)
}
示例#10
0
func hasOpenAPITagValue(comments []string, value string) bool {
	tagValues := types.ExtractCommentTags("+", comments)[tagName]
	if tagValues == nil {
		return false
	}
	for _, val := range tagValues {
		if val == value {
			return true
		}
	}
	return false
}
func packageForGroup(group string, version string, typeList []*types.Type, basePath string, boilerplate []byte) generator.Package {
	outputPackagePath := filepath.Join(basePath, group, version)
	return &generator.DefaultPackage{
		PackageName: version,
		PackagePath: outputPackagePath,
		HeaderText:  boilerplate,
		PackageDocumentation: []byte(
			`// Package unversioned has the automatically generated clients for unversioned resources.
`),
		// 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"},
			}
			// Since we want a file per type that we generate a client for, we
			// have to provide a function for this.
			for _, t := range typeList {
				generators = append(generators, &genClientForType{
					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: outputPackagePath,
					group:         group,
					typeToMatch:   t,
					imports:       generator.NewImportTracker(),
				})
			}

			generators = append(generators, &genGroup{
				DefaultGen: generator.DefaultGen{
					OptionalName: group + "_client",
				},
				outputPackage: outputPackagePath,
				group:         group,
				types:         typeList,
				imports:       generator.NewImportTracker(),
			})
			return generators
		},
		FilterFunc: func(c *generator.Context, t *types.Type) bool {
			return types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] == "true"
		},
	}
}
示例#12
0
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	groupToTypes := map[string][]*types.Type{}
	for _, inputDir := range arguments.InputDirs {
		p := context.Universe.Package(inputDir)
		for _, t := range p.Types {
			if types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] != "true" {
				continue
			}
			group := filepath.Base(t.Name.Package)
			// Special case for the core API.
			if group == "api" {
				group = "core"
			}
			if _, found := groupToTypes[group]; !found {
				groupToTypes[group] = []*types.Type{}
			}
			groupToTypes[group] = append(groupToTypes[group], t)
		}
	}

	customArgs, ok := arguments.CustomArgs.(ClientGenArgs)
	if !ok {
		glog.Fatalf("cannot convert arguments.CustomArgs to ClientGenArgs")
	}

	var packageList []generator.Package

	packageList = append(packageList, packageForClientset(customArgs, arguments.OutputPackagePath, boilerplate))
	if customArgs.FakeClient {
		packageList = append(packageList, fake.PackageForClientset(arguments.OutputPackagePath, customArgs.GroupVersions, boilerplate))
	}

	// If --clientset-only=true, we don't regenerate the individual typed clients.
	if customArgs.ClientsetOnly {
		return generator.Packages(packageList)
	}

	orderer := namer.Orderer{namer.NewPrivateNamer(0)}
	for group, types := range groupToTypes {
		packageList = append(packageList, packageForGroup(group, "unversioned", orderer.OrderTypes(types), arguments.OutputPackagePath, arguments.OutputBase, boilerplate))
		if customArgs.FakeClient {
			packageList = append(packageList, fake.PackageForGroup(group, "unversioned", orderer.OrderTypes(types), arguments.OutputPackagePath, arguments.OutputBase, boilerplate))
		}
	}

	return generator.Packages(packageList)
}
示例#13
0
func PackageForGroup(gv unversioned.GroupVersion, typeList []*types.Type, packageBasePath string, srcTreePath string, inputPath string, boilerplate []byte, generatedBy string) generator.Package {
	outputPackagePath := filepath.Join(packageBasePath, gv.Group, gv.Version, "fake")
	// TODO: should make this a function, called by here and in client-generator.go
	realClientPath := filepath.Join(packageBasePath, gv.Group, gv.Version)
	return &generator.DefaultPackage{
		PackageName: "fake",
		PackagePath: outputPackagePath,
		HeaderText:  boilerplate,
		PackageDocumentation: []byte(
			generatedBy +
				`// Package fake has the automatically generated clients.
`),
		// 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"},
			}
			// Since we want a file per type that we generate a client for, we
			// have to provide a function for this.
			for _, t := range typeList {
				generators = append(generators, &genFakeForType{
					DefaultGen: generator.DefaultGen{
						OptionalName: "fake_" + strings.ToLower(c.Namers["private"].Name(t)),
					},
					outputPackage: outputPackagePath,
					group:         normalization.BeforeFirstDot(gv.Group),
					inputPackage:  inputPath,
					version:       gv.Version,
					typeToMatch:   t,
					imports:       generator.NewImportTracker(),
				})
			}

			generators = append(generators, &genFakeForGroup{
				DefaultGen: generator.DefaultGen{
					OptionalName: "fake_" + normalization.BeforeFirstDot(gv.Group) + "_client",
				},
				outputPackage:  outputPackagePath,
				realClientPath: realClientPath,
				group:          normalization.BeforeFirstDot(gv.Group),
				types:          typeList,
				imports:        generator.NewImportTracker(),
			})
			return generators
		},
		FilterFunc: func(c *generator.Context, t *types.Type) bool {
			return types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] == "true"
		},
	}
}
示例#14
0
// Packages makes the client package definition.
func Packages(context *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: "unversioned",
		PackagePath: arguments.OutputPackagePath,
		HeaderText: append(boilerplate, []byte(
			`
// This file was autogenerated by the command:
// $ `+strings.Join(os.Args, " ")+`
// Do not edit it manually!

`)...),
		PackageDocumentation: []byte(
			`// Package unversioned has the automatically generated clients for unversioned resources.
`),
		// 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"},
			}
			// Since we want a file per type that we generate a client for, we
			// have to provide a function for this.
			for _, t := range c.Order {
				generators = append(generators, &genClientForType{
					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 {
			return types.ExtractCommentTags("+", t.CommentLines)["genclient"] == "true"
		},
	}}
}
示例#15
0
func copyableWithinPackage(t *types.Type) bool {
	if types.ExtractCommentTags("+", t.CommentLines)["gencopy"] == "false" {
		return false
	}
	// TODO: Consider generating functions for other kinds too.
	if t.Kind != types.Struct {
		return false
	}
	// Also, filter out private types.
	if namer.IsPrivateGoName(t.Name.Name) {
		return false
	}
	return true
}
示例#16
0
// Filter ignores types that are identified as not exportable.
func (g *genProtoIDL) Filter(c *generator.Context, t *types.Type) bool {
	flags := types.ExtractCommentTags("+", t.CommentLines)
	switch {
	case flags["protobuf"] == "false":
		return false
	case flags["protobuf"] == "true":
		return true
	case !g.generateAll:
		return false
	}
	seen := map[*types.Type]bool{}
	ok := isProtoable(seen, t)
	return ok
}
示例#17
0
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	customArgs, ok := arguments.CustomArgs.(ClientGenArgs)
	if !ok {
		glog.Fatalf("cannot convert arguments.CustomArgs to ClientGenArgs")
	}

	gvToTypes := map[unversioned.GroupVersion][]*types.Type{}
	for gv, inputDir := range customArgs.GroupVersionToInputPath {
		p := context.Universe.Package(inputDir)
		for _, t := range p.Types {
			if types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] != "true" {
				continue
			}
			if _, found := gvToTypes[gv]; !found {
				gvToTypes[gv] = []*types.Type{}
			}
			gvToTypes[gv] = append(gvToTypes[gv], t)
		}
	}

	var packageList []generator.Package

	packageList = append(packageList, packageForClientset(customArgs, arguments.OutputPackagePath, boilerplate))
	if customArgs.FakeClient {
		packageList = append(packageList, fake.PackageForClientset(arguments.OutputPackagePath, customArgs.GroupVersions, boilerplate))
	}

	// If --clientset-only=true, we don't regenerate the individual typed clients.
	if customArgs.ClientsetOnly {
		return generator.Packages(packageList)
	}

	orderer := namer.Orderer{namer.NewPrivateNamer(0)}
	for _, gv := range customArgs.GroupVersions {
		types := gvToTypes[gv]
		packageList = append(packageList, packageForGroup(normalization.GroupVersion(gv), orderer.OrderTypes(types), arguments.OutputPackagePath, arguments.OutputBase, boilerplate))
		if customArgs.FakeClient {
			packageList = append(packageList, fake.PackageForGroup(normalization.GroupVersion(gv), orderer.OrderTypes(types), arguments.OutputPackagePath, arguments.OutputBase, boilerplate))
		}
	}

	return generator.Packages(packageList)
}
示例#18
0
func (g *genDeepCopy) copyableWithinPackage(t *types.Type) bool {
	// TODO: We should generate public DeepCopy functions per directory, instead
	// of generating everything everywhere.
	// This is done that way only to minimize number of changes per PR.
	// Once this is done, we should replace HasPrefix with:
	//if t.Name.Package != g.targetPackage {
	//	return false
	//}
	if !strings.HasPrefix(t.Name.Package, "k8s.io/kubernetes/") {
		return false
	}
	if types.ExtractCommentTags("+", t.CommentLines)["gencopy"] == "false" {
		return false
	}
	// TODO: Consider generating functions for other kinds too.
	return t.Kind == types.Struct
}
示例#19
0
func copyableWithinPackage(t *types.Type, explicitCopyRequired bool) bool {
	tag := types.ExtractCommentTags("+", t.CommentLines)["gencopy"]
	if tag == "false" {
		return false
	}
	if explicitCopyRequired && tag != "true" {
		return false
	}
	// TODO: Consider generating functions for other kinds too.
	if t.Kind != types.Struct {
		return false
	}
	// Also, filter out private types.
	if namer.IsPrivateGoName(t.Name.Name) {
		return false
	}
	return true
}
示例#20
0
// 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
}
示例#21
0
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
}
示例#22
0
func (g *genDeepCopy) copyableWithinPackage(t *types.Type) bool {
	// TODO: We should generate public DeepCopy functions per directory, instead
	// of generating everything everywhere.
	// This is done that way only to minimize number of changes per PR.
	// Once this is done, we should replace HasPrefix with:
	//if t.Name.Package != g.targetPackage {
	//	return false
	//}
	if !strings.HasPrefix(t.Name.Package, "k8s.io/kubernetes/") {
		return false
	}
	if types.ExtractCommentTags("+", t.CommentLines)["gencopy"] == "false" {
		return false
	}
	// TODO: Consider generating functions for other kinds too.
	if t.Kind != types.Struct {
		return false
	}
	// TODO: This should be removed once we start generating public DeepCopy
	// functions per directory.
	if t.Name.Package != g.targetPackage {
		// We won't be able to access private fields.
		// Thus, this type cannot have private fields.
		for _, member := range t.Members {
			if strings.ToLower(member.Name[:1]) == member.Name[:1] {
				return false
			}
			// TODO: This is a temporary hack, to make avoid generating function
			// for conversion.Equalities. We should get rid of it.
			if member.Embedded {
				return false
			}
		}
	}
	return true
}
示例#23
0
func extractTag(comments []string) []string {
	return types.ExtractCommentTags("+", comments)[tagName]
}
示例#24
0
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	groupToTypes := map[string][]*types.Type{}
	for _, inputDir := range arguments.InputDirs {
		p := context.Universe.Package(inputDir)
		for _, t := range p.Types {
			if types.ExtractCommentTags("+", t.CommentLines)["genclient"] != "true" {
				continue
			}
			group := filepath.Base(t.Name.Package)
			// Special case for the legacy API.
			if group == "api" {
				group = ""
			}
			if _, found := groupToTypes[group]; !found {
				groupToTypes[group] = []*types.Type{}
			}
			groupToTypes[group] = append(groupToTypes[group], t)
		}
	}

	return generator.Packages{&generator.DefaultPackage{
		PackageName: filepath.Base(arguments.OutputPackagePath),
		PackagePath: arguments.OutputPackagePath,
		HeaderText:  boilerplate,
		PackageDocumentation: []byte(
			`// Package unversioned has the automatically generated clients for unversioned resources.
`),
		// 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"},
			}
			// Since we want a file per type that we generate a client for, we
			// have to provide a function for this.
			for _, t := range c.Order {
				generators = append(generators, &genClientForType{
					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(),
				})
			}

			for group, types := range groupToTypes {
				generators = append(generators, &genGroup{
					DefaultGen: generator.DefaultGen{
						OptionalName: group,
					},
					outputPackage: arguments.OutputPackagePath,
					group:         group,
					types:         types,
					imports:       generator.NewImportTracker(),
				})
			}
			return generators
		},
		FilterFunc: func(c *generator.Context, t *types.Type) bool {
			return types.ExtractCommentTags("+", t.CommentLines)["genclient"] == "true"
		},
	}}
}
示例#25
0
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	customArgs, ok := arguments.CustomArgs.(clientgenargs.Args)
	if !ok {
		glog.Fatalf("cannot convert arguments.CustomArgs to clientgenargs.Args")
	}
	includedTypesOverrides := customArgs.IncludedTypesOverrides

	generatedBy := generatedBy(customArgs)

	gvToTypes := map[unversioned.GroupVersion][]*types.Type{}
	for gv, inputDir := range customArgs.GroupVersionToInputPath {
		p := context.Universe.Package(inputDir)
		for n, t := range p.Types {
			// filter out types which are not included in user specified overrides.
			typesOverride, ok := includedTypesOverrides[gv]
			if ok {
				found := false
				for _, typeStr := range typesOverride {
					if typeStr == n {
						found = true
					}
				}
				if !found {
					continue
				}
			} else {
				// User has not specified any override for this group version.
				// filter out types which dont have genclient=true.
				if types.ExtractCommentTags("+", t.SecondClosestCommentLines)["genclient"] != "true" {
					continue
				}
			}
			if _, found := gvToTypes[gv]; !found {
				gvToTypes[gv] = []*types.Type{}
			}
			gvToTypes[gv] = append(gvToTypes[gv], t)
		}
	}

	var packageList []generator.Package
	typedClientBasePath := filepath.Join(customArgs.ClientsetOutputPath, customArgs.ClientsetName, "typed")

	packageList = append(packageList, packageForClientset(customArgs, typedClientBasePath, boilerplate, generatedBy))
	if customArgs.FakeClient {
		packageList = append(packageList, fake.PackageForClientset(customArgs, typedClientBasePath, boilerplate, generatedBy))
	}

	// If --clientset-only=true, we don't regenerate the individual typed clients.
	if customArgs.ClientsetOnly {
		return generator.Packages(packageList)
	}

	orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
	for _, gv := range customArgs.GroupVersions {
		types := gvToTypes[gv]
		inputPath := customArgs.GroupVersionToInputPath[gv]
		packageList = append(packageList, packageForGroup(normalization.GroupVersion(gv), orderer.OrderTypes(types), typedClientBasePath, arguments.OutputBase, inputPath, boilerplate, generatedBy))
		if customArgs.FakeClient {
			packageList = append(packageList, fake.PackageForGroup(normalization.GroupVersion(gv), orderer.OrderTypes(types), typedClientBasePath, arguments.OutputBase, inputPath, boilerplate, generatedBy))
		}
	}

	return generator.Packages(packageList)
}
示例#26
0
文件: sets.go 项目: Rushit/kubernetes
// 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: append(boilerplate, []byte(
			`
// This file was autogenerated by set-gen. Do not edit it manually!

`)...),
		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 types.ExtractCommentTags("+", t.CommentLines)["genset"] == "true"
			}
			return false
		},
	}}
}
示例#27
0
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 == "false" {
					if !b.omitGogo {
						options = append(options,
							"(gogoproto.marshaler) = false",
							"(gogoproto.unmarshaler) = false",
							"(gogoproto.sizer) = false",
						)
					}
				}
			default:
				if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") {
					options = append(options, fmt.Sprintf("%s = %s", key, v))
				}
			}
		// 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}); alias == nil {
				return fmt.Errorf("type %v references alias %q which does not exist", b.t, v)
			}
		// 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,
					Type: &types.Type{
						Name: types.Name{
							Name:    v,
							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
}
示例#28
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(arguments.InputDirs...)
	packages := generator.Packages{}
	header := append([]byte(
		`// +build !ignore_autogenerated

`), boilerplate...)
	header = append(header, []byte(
		`
// This file was autogenerated by conversion-gen. Do not edit it manually!

`)...)

	// Compute all pre-existing conversion functions.
	preexisting := existingConversionFunctions(context)
	preexistingDefaults := existingDefaultingFunctions(context)

	// We are generating conversions only for packages that are explicitly
	// passed as InputDir, and only for those that have a corresponding type
	// (in the directory one above) and can be automatically converted to.
	for _, p := range context.Universe {
		path := p.Path
		if !inputs.Has(path) {
			continue
		}
		// Only generate conversions for package which explicitly requested it
		// byt setting "+genversion=true" in their doc.go file.
		filtered := false
		for _, comment := range p.DocComments {
			comment := strings.Trim(comment, "//")
			if types.ExtractCommentTags("+", comment)["genconversion"] == "true" {
				filtered = true
			}
		}
		if !filtered {
			continue
		}

		convertibleType := false
		for _, t := range p.Types {
			// Check whether this type can be auto-converted to the internal
			// version.
			internalType, exists := getInternalTypeFor(context, t)
			if !exists {
				// There is no corresponding type in the internal package.
				continue
			}
			// We won't be able to convert to private type.
			if namer.IsPrivateGoName(internalType.Name.Name) {
				continue
			}
			// If we can generate conversion in any direction, we should
			// generate this package.
			if isConvertible(t, internalType, preexisting) || isConvertible(internalType, t, preexisting) {
				convertibleType = true
			}
		}

		if convertibleType {
			packages = append(packages,
				&generator.DefaultPackage{
					PackageName: filepath.Base(path),
					PackagePath: path,
					HeaderText:  header,
					GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
						generators = []generator.Generator{}
						generators = append(
							generators, NewGenConversion("conversion_generated", path, preexisting, preexistingDefaults))
						return generators
					},
					FilterFunc: func(c *generator.Context, t *types.Type) bool {
						return t.Name.Package == path
					},
				})
		}
	}
	return packages
}
// GenerateType makes the body of a file implementing the individual typed client for type t.
func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	pkg := filepath.Base(t.Name.Package)
	const pkgTestingCore = "k8s.io/kubernetes/pkg/client/testing/core"
	namespaced := !(types.ExtractCommentTags("+", t.SecondClosestCommentLines)["nonNamespaced"] == "true")
	canonicalGroup := g.group
	if canonicalGroup == "core" {
		canonicalGroup = ""
	}
	canonicalVersion := g.version
	if canonicalVersion == "unversioned" {
		canonicalVersion = ""
	}

	groupName := g.group
	if g.group == "core" {
		groupName = ""
	}

	// allow user to define a group name that's different from the one parsed from the directory.
	for _, comment := range c.Universe.Package(g.inputPackage).DocComments {
		comment = strings.TrimLeft(comment, "//")
		if override, ok := types.ExtractCommentTags("+", comment)["groupName"]; ok {
			groupName = override
		}
	}

	m := map[string]interface{}{
		"type":                 t,
		"package":              pkg,
		"Package":              namer.IC(pkg),
		"namespaced":           namespaced,
		"Group":                namer.IC(g.group),
		"group":                canonicalGroup,
		"groupName":            groupName,
		"version":              canonicalVersion,
		"watchInterface":       c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/watch", Name: "Interface"}),
		"apiDeleteOptions":     c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "DeleteOptions"}),
		"apiListOptions":       c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "ListOptions"}),
		"GroupVersionResource": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api/unversioned", Name: "GroupVersionResource"}),
		"PatchType":            c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "PatchType"}),
		"Everything":           c.Universe.Function(types.Name{Package: "k8s.io/kubernetes/pkg/labels", Name: "Everything"}),

		"NewRootListAction":              c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootListAction"}),
		"NewListAction":                  c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewListAction"}),
		"NewRootGetAction":               c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootGetAction"}),
		"NewGetAction":                   c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewGetAction"}),
		"NewRootDeleteAction":            c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootDeleteAction"}),
		"NewDeleteAction":                c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewDeleteAction"}),
		"NewRootDeleteCollectionAction":  c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootDeleteCollectionAction"}),
		"NewDeleteCollectionAction":      c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewDeleteCollectionAction"}),
		"NewRootUpdateAction":            c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootUpdateAction"}),
		"NewUpdateAction":                c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewUpdateAction"}),
		"NewRootCreateAction":            c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootCreateAction"}),
		"NewCreateAction":                c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewCreateAction"}),
		"NewRootWatchAction":             c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootWatchAction"}),
		"NewWatchAction":                 c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewWatchAction"}),
		"NewUpdateSubresourceAction":     c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewUpdateSubresourceAction"}),
		"NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootUpdateSubresourceAction"}),
		"NewRootPatchAction":             c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewRootPatchAction"}),
		"NewPatchAction":                 c.Universe.Function(types.Name{Package: pkgTestingCore, Name: "NewPatchAction"}),
	}

	noMethods := types.ExtractCommentTags("+", t.SecondClosestCommentLines)["noMethods"] == "true"

	if namespaced {
		sw.Do(structNamespaced, m)
	} else {
		sw.Do(structNonNamespaced, m)
	}

	if !noMethods {
		sw.Do(resource, m)
		sw.Do(createTemplate, m)
		sw.Do(updateTemplate, m)
		// Generate the UpdateStatus method if the type has a status
		if hasStatus(t) {
			sw.Do(updateStatusTemplate, m)
		}
		sw.Do(deleteTemplate, m)
		sw.Do(deleteCollectionTemplate, m)
		sw.Do(getTemplate, m)
		if hasObjectMeta(t) {
			sw.Do(listUsingOptionsTemplate, m)
		} else {
			sw.Do(listTemplate, m)
		}
		sw.Do(watchTemplate, m)
		sw.Do(patchTemplate, m)
	}

	return sw.Error()
}
示例#30
0
func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	const pkgRESTClient = "k8s.io/kubernetes/pkg/client/restclient"
	const pkgRegistered = "k8s.io/kubernetes/pkg/apimachinery/registered"
	const pkgAPI = "k8s.io/kubernetes/pkg/api"
	const pkgSerializer = "k8s.io/kubernetes/pkg/runtime/serializer"
	apiPath := func(group string) string {
		if group == "core" {
			return `"/api"`
		}
		return `"/apis"`
	}

	groupName := g.group
	if g.group == "core" {
		groupName = ""
	}
	// allow user to define a group name that's different from the one parsed from the directory.
	for _, comment := range c.Universe.Package(g.inputPacakge).DocComments {
		comment = strings.TrimLeft(comment, "//")
		if override, ok := types.ExtractCommentTags("+", comment)["groupName"]; ok && override != "" {
			groupName = override
		}
	}

	m := map[string]interface{}{
		"group":                      normalization.BeforeFirstDot(g.group),
		"Group":                      namer.IC(normalization.BeforeFirstDot(g.group)),
		"groupName":                  groupName,
		"types":                      g.types,
		"Config":                     c.Universe.Type(types.Name{Package: pkgRESTClient, Name: "Config"}),
		"DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: pkgRESTClient, Name: "DefaultKubernetesUserAgent"}),
		"RESTClient":                 c.Universe.Type(types.Name{Package: pkgRESTClient, Name: "RESTClient"}),
		"RESTClientFor":              c.Universe.Function(types.Name{Package: pkgRESTClient, Name: "RESTClientFor"}),
		"latestGroup":                c.Universe.Variable(types.Name{Package: pkgRegistered, Name: "Group"}),
		"GroupOrDie":                 c.Universe.Variable(types.Name{Package: pkgRegistered, Name: "GroupOrDie"}),
		"apiPath":                    apiPath(g.group),
		"codecs":                     c.Universe.Variable(types.Name{Package: pkgAPI, Name: "Codecs"}),
		"directCodecFactory":         c.Universe.Variable(types.Name{Package: pkgSerializer, Name: "DirectCodecFactory"}),
		"Errorf":                     c.Universe.Variable(types.Name{Package: "fmt", Name: "Errorf"}),
	}
	sw.Do(groupInterfaceTemplate, m)
	sw.Do(groupClientTemplate, m)
	for _, t := range g.types {
		wrapper := map[string]interface{}{
			"type":  t,
			"Group": namer.IC(normalization.BeforeFirstDot(g.group)),
		}
		namespaced := !(types.ExtractCommentTags("+", t.SecondClosestCommentLines)["nonNamespaced"] == "true")
		if namespaced {
			sw.Do(getterImplNamespaced, wrapper)
		} else {
			sw.Do(getterImplNonNamespaced, wrapper)

		}
	}
	sw.Do(newClientForConfigTemplate, m)
	sw.Do(newClientForConfigOrDieTemplate, m)
	sw.Do(newClientForRESTClientTemplate, m)
	if g.version == "unversioned" {
		sw.Do(setInternalVersionClientDefaultsTemplate, m)
	} else {
		sw.Do(setClientDefaultsTemplate, m)
	}
	sw.Do(getRESTClient, m)

	return sw.Error()
}