// 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)
}
// Packages makes the sets package definition.
func Packages(c *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	pkgs := generator.Packages{}
	c.FileTypes = map[string]generator.FileType{
		importBossFileType: importRuleFile{},
	}

	for _, p := range c.Universe {
		if !arguments.InputIncludes(p) {
			// Don't run on e.g. third party dependencies.
			continue
		}
		savedPackage := p
		pkgs = append(pkgs, &generator.DefaultPackage{
			PackageName: p.Name,
			PackagePath: p.Path,
			// GeneratorFunc returns a list of generators. Each generator makes a
			// single file.
			GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
				return []generator.Generator{&importRules{
					myPackage: savedPackage,
				}}
			},
			FilterFunc: func(c *generator.Context, t *types.Type) bool {
				return false
			},
		})
	}

	return pkgs
}
Beispiel #3
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)
}
// 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)
}
Beispiel #5
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"
		},
	}}
}
Beispiel #6
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 deepcopy-gen. Do not edit it manually!

`)...)
	for _, p := range context.Universe {
		copyableType := false
		for _, t := range p.Types {
			if copyableWithinPackage(t) {
				copyableType = true
			}
		}
		if copyableType {
			path := p.Path
			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, NewGenDeepCopy("deep_copy_generated", path, inputs.Has(path)))
						return generators
					},
					FilterFunc: func(c *generator.Context, t *types.Type) bool {
						if t.Name.Package != path {
							return false
						}
						return copyableWithinPackage(t)
					},
				})
		}
	}
	return packages
}
Beispiel #7
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)
}
Beispiel #8
0
func Packages(_ *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
	boilerplate, err := arguments.LoadGoBoilerplate()
	if err != nil {
		glog.Fatalf("Failed loading boilerplate: %v", err)
	}

	packages := generator.Packages{}
	for _, inputDir := range arguments.InputDirs {
		packages = append(packages,
			&generator.DefaultPackage{
				PackageName: filepath.Base(inputDir),
				PackagePath: inputDir,
				HeaderText: append(boilerplate, []byte(
					`
// This file was autogenerated by the command:
// $ `+strings.Join(os.Args, " ")+`
// Do not edit it manually!

`)...),
				GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
					generators = []generator.Generator{}
					// TODO: Check whether anything will be generated.
					generators = append(generators, NewGenDeepCopy("deep_copy_generated", inputDir))
					return generators
				},
				FilterFunc: func(c *generator.Context, t *types.Type) bool {
					switch t.Kind {
					case types.Func, types.Chan:
						// These types can't be copied.
						return false
					case types.Unknown, types.Unsupported:
						// These types are explicitly ignored.
						return false
					case types.Array:
						// We don't support arrays.
						return false
					}
					// Also, filter out private types.
					if strings.ToLower(t.Name.Name[:1]) == t.Name.Name[:1] {
						return false
					}
					return true
				},
			})
	}
	return packages
}
// 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)
}
Beispiel #10
0
// 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
		},
	}}
}
Beispiel #11
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(
		`
// This file was autogenerated by deepcopy-gen. Do not edit it manually!

`)...)

	boundingDirs := []string{}
	if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
		for i := range customArgs.BoundingDirs {
			// Strip any trailing slashes - they are not exactly "correct" but
			// this is friendlier.
			boundingDirs = append(boundingDirs, strings.TrimRight(customArgs.BoundingDirs[i], "/"))
		}
	}

	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
		}

		ptag := extractTag(pkg.Comments)
		ptagValue := ""
		ptagRegister := false
		if ptag != nil {
			ptagValue = ptag.value
			if ptagValue != tagValuePackage {
				glog.Fatalf("Package %v: unsupported %s value: %q", i, tagName, ptagValue)
			}
			ptagRegister = ptag.register
			glog.V(5).Infof("  tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
		} else {
			glog.V(5).Infof("  no tag")
		}

		// If the pkg-scoped tag says to generate, we can skip scanning types.
		pkgNeedsGeneration := (ptagValue == tagValuePackage)
		if !pkgNeedsGeneration {
			// If the pkg-scoped tag did not exist, scan all types for one that
			// explicitly wants generation.
			for _, t := range pkg.Types {
				glog.V(5).Infof("  considering type %q", t.Name.String())
				ttag := extractTag(t.CommentLines)
				if ttag != nil && ttag.value == "true" {
					glog.V(5).Infof("    tag=true")
					if !copyableType(t) {
						glog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
					}
					pkgNeedsGeneration = true
					break
				}
			}
		}

		if pkgNeedsGeneration {
			packages = append(packages,
				&generator.DefaultPackage{
					PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0],
					PackagePath: pkg.Path,
					HeaderText:  header,
					GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
						generators = []generator.Generator{}
						generators = append(
							generators, NewGenDeepCopy(arguments.OutputFileBaseName, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister))
						return generators
					},
					FilterFunc: func(c *generator.Context, t *types.Type) bool {
						return t.Name.Package == pkg.Path
					},
				})
		}
	}
	return packages
}
Beispiel #12
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)
	}

	initInputs := sets.NewString()
	explicitInputs := sets.NewString()
	inputs := sets.NewString()
	for _, s := range arguments.InputDirs {
		switch {
		case strings.HasPrefix(s, "+"):
			// packages with '+' prefix get functions generated for everything except gencopy=false, but
			// no init function
			s = strings.TrimPrefix(s, "+")
			inputs.Insert(s)
		case strings.HasPrefix(s, "-"):
			// packages with '-' prefix only get functions generated for those with gencopy=true
			s = strings.TrimPrefix(s, "-")
			inputs.Insert(s)
			explicitInputs.Insert(s)
		default:
			inputs.Insert(s)
			initInputs.Insert(s)
		}
	}

	var restrictRange []string
	if c, ok := arguments.CustomArgs.(Constraints); ok {
		restrictRange = c.PackageConstraints
	}

	packages := generator.Packages{}
	header := append([]byte(
		`// +build !ignore_autogenerated

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

`)...)
	for _, p := range context.Universe {
		copyableType := false
		for _, t := range p.Types {
			if copyableWithinPackage(t, explicitInputs.Has(t.Name.Package)) && inputs.Has(t.Name.Package) {
				copyableType = true
			}
		}
		if copyableType {
			// TODO: replace this with a more sophisticated algorithm that generates private copy methods
			// (like auto_DeepCopy_...) for any type that is outside of the PackageConstraints. That would
			// avoid having to make a reflection call.
			canInlineTypeFn := func(c *generator.Context, t *types.Type) bool {
				// types must be public structs or have a custom DeepCopy_<method> already defined
				if !copyableWithinPackage(t, explicitInputs.Has(t.Name.Package)) && !publicCopyFunctionDefined(c, t) {
					return false
				}

				// only packages within the restricted range can be inlined
				for _, s := range restrictRange {
					if strings.HasPrefix(t.Name.Package, s) {
						return true
					}
				}
				return false
			}

			path := p.Path
			packages = append(packages,
				&generator.DefaultPackage{
					PackageName: strings.Split(filepath.Base(path), ".")[0],
					PackagePath: path,
					HeaderText:  header,
					GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
						generators = []generator.Generator{}
						generators = append(
							generators, NewGenDeepCopy("deep_copy_generated", path, initInputs.Has(path), explicitInputs.Has(path), canInlineTypeFn))
						return generators
					},
					FilterFunc: func(c *generator.Context, t *types.Type) bool {
						return t.Name.Package == path
					},
				})
		}
	}
	return packages
}
Beispiel #13
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
}
Beispiel #14
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)

	// 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
		// TODO: Only a subset of InputDirs is actually where we would like
		// to generate conversions, the rest of files are added, because either
		// conversion methods are generated there or they contain types
		// necessary for conversions.
		if !inputs.Has(path) {
			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
			}
			// 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))
						return generators
					},
					FilterFunc: func(c *generator.Context, t *types.Type) bool {
						return t.Name.Package == path
					},
				})
		}
	}
	return packages
}
Beispiel #15
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"
		},
	}}
}
Beispiel #16
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(
		`
// This file was autogenerated by conversion-gen. Do not edit it manually!

`)...)

	// 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)
		}

		pkgNeedsGeneration := false
		for _, t := range pkg.Types {
			// Check whether this type can be auto-converted to the peer
			// package type.
			peerType := getPeerTypeFor(context, t, peerPkgs)
			if peerType == nil {
				// We did not find a corresponding type.
				continue
			}
			if namer.IsPrivateGoName(peerType.Name.Name) {
				// We won't be able to convert to a private type.
				glog.V(5).Infof("  found a peer type %v, but it is a private name", t)
				continue
			}

			// If we can generate conversion in any direction, we should
			// generate this package.
			if isConvertible(t, peerType, manualConversions) || isConvertible(peerType, t, manualConversions) {
				pkgNeedsGeneration = true
				break
			}
		}
		if !pkgNeedsGeneration {
			glog.V(5).Infof("  no viable conversions, not generating for this package")
			continue
		}

		packages = append(packages,
			&generator.DefaultPackage{
				PackageName: filepath.Base(pkg.Path),
				PackagePath: pkg.Path,
				HeaderText:  header,
				GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
					generators = []generator.Generator{}
					generators = append(
						generators, NewGenConversion(arguments.OutputFileBaseName, pkg.Path, manualConversions, manualDefaults, peerPkgs))
					return generators
				},
				FilterFunc: func(c *generator.Context, t *types.Type) bool {
					return t.Name.Package == pkg.Path
				},
			})
	}
	return packages
}
Beispiel #17
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...)
	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!

`)...)

	targets := []*types.Type{}
	for i := range inputs {
		glog.V(5).Infof("considering pkg %q", i)
		pkg, ok := context.Universe[i]
		if !ok {
			// If the input had no Go files, for example.
			continue
		}
		for _, t := range pkg.Types {
			if hasOpenAPITagValue(t.CommentLines, tagTargetType) {
				glog.V(5).Infof("target type : %q", t)
				targets = append(targets, t)
			}
		}
	}
	switch len(targets) {
	case 0:
		// If no target package found, that means the generated file in target package is up to date
		// and build excluded the target package.
		return generator.Packages{}
	case 1:
		pkg := context.Universe[targets[0].Name.Package]
		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, targets[0], 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
			},
		},
		}
	default:
		glog.Fatalf("Duplicate target type found: %v", targets)
	}
	return generator.Packages{}
}