client-gen: separate input-base logic from CustomArgs

This commit is contained in:
Dr. Stefan Schimanski 2017-11-25 11:38:10 +01:00
parent 81a5ca68a7
commit 536522bb1e
14 changed files with 229 additions and 200 deletions

View File

@ -27,12 +27,6 @@ type CustomArgs struct {
// A sorted list of group versions to generate. For each of them the package path is found // A sorted list of group versions to generate. For each of them the package path is found
// in GroupVersionToInputPath. // in GroupVersionToInputPath.
Groups []types.GroupVersions Groups []types.GroupVersions
// GroupVersionToInputPath is a map between GroupVersion and the path to the respective
// types.go, relative to InputBasePath. We still need GroupVersions in the
// struct because we need an order.
GroupVersionToInputPath map[types.GroupVersion]string
// The base for the path of GroupVersionToInputPath.
InputBasePath string
// Overrides for which types should be included in the client. // Overrides for which types should be included in the client.
IncludedTypesOverrides map[types.GroupVersion][]string IncludedTypesOverrides map[types.GroupVersion][]string
@ -54,12 +48,24 @@ type CustomArgs struct {
} }
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
pflag.Var(NewGVPackagesValue(&ca.GroupVersionToInputPath, &ca.Groups, nil), "input", "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".") gvsBuilder := NewGroupVersionsBuilder(&ca.Groups)
pflag.Var(NewGVPackagesValue(gvsBuilder, nil), "input", "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".")
pflag.Var(NewGVTypesValue(&ca.IncludedTypesOverrides, []string{}), "included-types-overrides", "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.") pflag.Var(NewGVTypesValue(&ca.IncludedTypesOverrides, []string{}), "included-types-overrides", "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.")
pflag.StringVar(&ca.InputBasePath, "input-base", "k8s.io/kubernetes/pkg/apis", "base path to look for the api group.") pflag.Var(NewInputBasePathValue(gvsBuilder, "k8s.io/kubernetes/pkg/apis"), "input-base", "base path to look for the api group.")
pflag.StringVarP(&ca.ClientsetName, "clientset-name", "n", "internalclientset", "the name of the generated clientset package.") pflag.StringVarP(&ca.ClientsetName, "clientset-name", "n", "internalclientset", "the name of the generated clientset package.")
pflag.StringVarP(&ca.ClientsetAPIPath, "clientset-api-path", "", "/apis", "the value of default API HTTP path, starting with / and without trailing /.") pflag.StringVarP(&ca.ClientsetAPIPath, "clientset-api-path", "", "/apis", "the value of default API HTTP path, starting with / and without trailing /.")
pflag.StringVar(&ca.ClientsetOutputPath, "clientset-path", "k8s.io/kubernetes/pkg/client/clientset_generated/", "the generated clientset will be output to <clientset-path>/<clientset-name>.") pflag.StringVar(&ca.ClientsetOutputPath, "clientset-path", "k8s.io/kubernetes/pkg/client/clientset_generated/", "the generated clientset will be output to <clientset-path>/<clientset-name>.")
pflag.BoolVar(&ca.ClientsetOnly, "clientset-only", false, "when set, client-gen only generates the clientset shell, without generating the individual typed clients") pflag.BoolVar(&ca.ClientsetOnly, "clientset-only", false, "when set, client-gen only generates the clientset shell, without generating the individual typed clients")
pflag.BoolVar(&ca.FakeClient, "fake-clientset", true, "when set, client-gen will generate the fake clientset that can be used in tests") pflag.BoolVar(&ca.FakeClient, "fake-clientset", true, "when set, client-gen will generate the fake clientset that can be used in tests")
} }
// GroupVersionPackages returns a map from GroupVersion to the package with the types.go.
func (ca *CustomArgs) GroupVersionPackages() map[types.GroupVersion]string {
res := map[types.GroupVersion]string{}
for _, pkg := range ca.Groups {
for _, v := range pkg.Versions {
res[types.GroupVersion{Group: pkg.Group, Version: v.Version}] = v.Package
}
}
return res
}

View File

@ -21,24 +21,48 @@ import (
"encoding/csv" "encoding/csv"
"flag" "flag"
"path" "path"
"strings"
"path/filepath"
"sort" "sort"
"strings"
"k8s.io/code-generator/cmd/client-gen/types" "k8s.io/code-generator/cmd/client-gen/types"
) )
type inputBasePathValue struct {
builder *groupVersionsBuilder
}
var _ flag.Value = &inputBasePathValue{}
func NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue {
v := &inputBasePathValue{
builder: builder,
}
v.Set(def)
return v
}
func (s *inputBasePathValue) Set(val string) error {
s.builder.importBasePath = val
return s.builder.update()
}
func (s *inputBasePathValue) Type() string {
return "string"
}
func (s *inputBasePathValue) String() string {
return s.builder.importBasePath
}
type gvPackagesValue struct { type gvPackagesValue struct {
gvToPath *map[types.GroupVersion]string builder *groupVersionsBuilder
groups *[]types.GroupVersions groups []string
changed bool changed bool
} }
func NewGVPackagesValue(gvToPath *map[types.GroupVersion]string, groups *[]types.GroupVersions, def []string) *gvPackagesValue { func NewGVPackagesValue(builder *groupVersionsBuilder, def []string) *gvPackagesValue {
gvp := new(gvPackagesValue) gvp := new(gvPackagesValue)
gvp.gvToPath = gvToPath gvp.builder = builder
gvp.groups = groups
if def != nil { if def != nil {
if err := gvp.set(def); err != nil { if err := gvp.set(def); err != nil {
panic(err) panic(err)
@ -49,6 +73,95 @@ func NewGVPackagesValue(gvToPath *map[types.GroupVersion]string, groups *[]types
var _ flag.Value = &gvPackagesValue{} var _ flag.Value = &gvPackagesValue{}
func (s *gvPackagesValue) set(vs []string) error {
if s.changed {
s.groups = append(s.groups, vs...)
} else {
s.groups = append([]string(nil), vs...)
}
s.builder.groups = s.groups
return s.builder.update()
}
func (s *gvPackagesValue) Set(val string) error {
vs, err := readAsCSV(val)
if err != nil {
return err
}
if err := s.set(vs); err != nil {
return err
}
s.changed = true
return nil
}
func (s *gvPackagesValue) Type() string {
return "stringSlice"
}
func (s *gvPackagesValue) String() string {
str, _ := writeAsCSV(s.groups)
return "[" + str + "]"
}
type groupVersionsBuilder struct {
value *[]types.GroupVersions
groups []string
importBasePath string
}
func NewGroupVersionsBuilder(groups *[]types.GroupVersions) *groupVersionsBuilder {
return &groupVersionsBuilder{
value: groups,
}
}
func (p *groupVersionsBuilder) update() error {
var seenGroups = make(map[types.Group]*types.GroupVersions)
for _, v := range p.groups {
pth, gvString := parsePathGroupVersion(v)
gv, err := types.ToGroupVersion(gvString)
if err != nil {
return err
}
versionPkg := types.PackageVersion{Package: path.Join(p.importBasePath, pth, gv.Group.NonEmpty(), gv.Version.String()), Version: gv.Version}
if group, ok := seenGroups[gv.Group]; ok {
seenGroups[gv.Group].Versions = append(group.Versions, versionPkg)
} else {
seenGroups[gv.Group] = &types.GroupVersions{
PackageName: gv.Group.NonEmpty(),
Group: gv.Group,
Versions: []types.PackageVersion{versionPkg},
}
}
}
var groupNames []string
for groupName := range seenGroups {
groupNames = append(groupNames, groupName.String())
}
sort.Strings(groupNames)
*p.value = []types.GroupVersions{}
for _, groupName := range groupNames {
*p.value = append(*p.value, *seenGroups[types.Group(groupName)])
}
return nil
}
func parsePathGroupVersion(pgvString string) (gvPath string, gvString string) {
subs := strings.Split(pgvString, "/")
length := len(subs)
switch length {
case 0, 1, 2:
return "", pgvString
default:
return strings.Join(subs[:length-2], "/"), strings.Join(subs[length-2:], "/")
}
}
func readAsCSV(val string) ([]string, error) { func readAsCSV(val string) ([]string, error) {
if val == "" { if val == "" {
return []string{}, nil return []string{}, nil
@ -68,93 +181,3 @@ func writeAsCSV(vals []string) (string, error) {
w.Flush() w.Flush()
return strings.TrimSuffix(b.String(), "\n"), nil return strings.TrimSuffix(b.String(), "\n"), nil
} }
func (s *gvPackagesValue) set(vs []string) error {
if !s.changed {
*s.gvToPath = map[types.GroupVersion]string{}
*s.groups = []types.GroupVersions{}
}
var seenGroups = make(map[types.Group]*types.GroupVersions)
for _, g := range *s.groups {
seenGroups[g.Group] = &g
}
for _, v := range vs {
pth, gvString := parsePathGroupVersion(v)
gv, err := types.ToGroupVersion(gvString)
if err != nil {
return err
}
if group, ok := seenGroups[gv.Group]; ok {
seenGroups[gv.Group].Versions = append(group.Versions, gv.Version)
} else {
seenGroups[gv.Group] = &types.GroupVersions{
PackageName: gv.Group.NonEmpty(),
Group: gv.Group,
Versions: []types.Version{gv.Version},
}
}
(*s.gvToPath)[gv] = groupVersionPath(pth, gv.Group.String(), gv.Version.String())
}
var groupNames []string
for groupName := range seenGroups {
groupNames = append(groupNames, groupName.String())
}
sort.Strings(groupNames)
*s.groups = []types.GroupVersions{}
for _, groupName := range groupNames {
*s.groups = append(*s.groups, *seenGroups[types.Group(groupName)])
}
return nil
}
func (s *gvPackagesValue) Set(val string) error {
vs, err := readAsCSV(val)
if err != nil {
return err
}
if err := s.set(vs); err != nil {
return err
}
s.changed = true
return nil
}
func (s *gvPackagesValue) Type() string {
return "stringSlice"
}
func (s *gvPackagesValue) String() string {
strs := make([]string, 0, len(*s.gvToPath))
for gv, pth := range *s.gvToPath {
strs = append(strs, path.Join(pth, gv.Group.String(), gv.Version.String()))
}
str, _ := writeAsCSV(strs)
return "[" + str + "]"
}
func parsePathGroupVersion(pgvString string) (gvPath string, gvString string) {
subs := strings.Split(pgvString, "/")
length := len(subs)
switch length {
case 0, 1, 2:
return "", pgvString
default:
return strings.Join(subs[:length-2], "/"), strings.Join(subs[length-2:], "/")
}
}
func groupVersionPath(gvPath string, group string, version string) (path string) {
// special case for the core group
if group == "api" {
path = filepath.Join("core", version)
} else {
path = filepath.Join(gvPath, group, version)
}
return
}

View File

@ -31,6 +31,7 @@ func TestGVPackageFlag(t *testing.T) {
tests := []struct { tests := []struct {
args []string args []string
def []string def []string
importBasePath string
expected map[types.GroupVersion]string expected map[types.GroupVersion]string
expectedGroups []types.GroupVersions expectedGroups []types.GroupVersions
parseError string parseError string
@ -42,47 +43,55 @@ func TestGVPackageFlag(t *testing.T) {
}, },
{ {
args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"}, args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"},
expected: map[types.GroupVersion]string{
{Group: "bar", Version: ""}: "foo/bar",
{Group: "bar", Version: "v1"}: "foo/bar/v1",
{Group: "bar", Version: "v2"}: "foo/bar/v2",
{Group: "foo", Version: "v1"}: "foo/v1",
},
expectedGroups: []types.GroupVersions{ expectedGroups: []types.GroupVersions{
{PackageName: "bar", Group: types.Group("bar"), Versions: []types.Version{types.Version("v1"), types.Version("v2"), types.Version("")}}, {PackageName: "bar", Group: types.Group("bar"), Versions: []types.PackageVersion{
{PackageName: "foo", Group: types.Group("foo"), Versions: []types.Version{types.Version("v1")}}, {"foo/bar/v1", types.Version("v1")},
{"foo/bar/v2", types.Version("v2")},
{"foo/bar", types.Version("")},
}},
{PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{
{"foo/v1", types.Version("v1")},
}},
}, },
}, },
{ {
args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"}, args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"},
def: []string{"foo/bar/v1alpha1", "foo/v1"}, def: []string{"foo/bar/v1alpha1", "foo/v1"},
expected: map[types.GroupVersion]string{
{Group: "bar", Version: ""}: "foo/bar",
{Group: "bar", Version: "v1"}: "foo/bar/v1",
{Group: "bar", Version: "v2"}: "foo/bar/v2",
{Group: "foo", Version: "v1"}: "foo/v1",
},
expectedGroups: []types.GroupVersions{ expectedGroups: []types.GroupVersions{
{PackageName: "bar", Group: types.Group("bar"), Versions: []types.Version{types.Version("v1"), types.Version("v2"), types.Version("")}}, {PackageName: "bar", Group: types.Group("bar"), Versions: []types.PackageVersion{
{PackageName: "foo", Group: types.Group("foo"), Versions: []types.Version{types.Version("v1")}}, {"foo/bar/v1", types.Version("v1")},
{"foo/bar/v2", types.Version("v2")},
{"foo/bar", types.Version("")},
}},
{PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{
{"foo/v1", types.Version("v1")},
}},
}, },
}, },
{ {
args: []string{"api/v1", "api"}, args: []string{"api/v1", "api"},
expected: map[types.GroupVersion]string{
{Group: "api", Version: "v1"}: "core/v1",
{Group: "api", Version: ""}: "core",
},
expectedGroups: []types.GroupVersions{ expectedGroups: []types.GroupVersions{
{PackageName: "core", Group: types.Group("api"), Versions: []types.Version{types.Version("v1"), types.Version("")}}, {PackageName: "core", Group: types.Group("api"), Versions: []types.PackageVersion{
{"core/v1", types.Version("v1")},
{"core", types.Version("")},
}},
},
},
{
args: []string{"foo/v1"},
importBasePath: "k8s.io/api",
expectedGroups: []types.GroupVersions{
{PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{
{"k8s.io/api/foo/v1", types.Version("v1")},
}},
}, },
}, },
} }
for i, test := range tests { for i, test := range tests {
fs := pflag.NewFlagSet("testGVPackage", pflag.ContinueOnError) fs := pflag.NewFlagSet("testGVPackage", pflag.ContinueOnError)
gvp := map[types.GroupVersion]string{}
groups := []types.GroupVersions{} groups := []types.GroupVersions{}
fs.Var(NewGVPackagesValue(&gvp, &groups, test.def), "input", "usage") importBasePath := test.importBasePath
fs.Var(NewGVPackagesValue(NewGroupVersionsBuilder(&groups, &importBasePath), test.def), "input", "usage")
args := []string{} args := []string{}
for _, a := range test.args { for _, a := range test.args {
@ -99,9 +108,6 @@ func TestGVPackageFlag(t *testing.T) {
} else if err != nil { } else if err != nil {
t.Errorf("%d: expected nil error, got %v", i, err) t.Errorf("%d: expected nil error, got %v", i, err)
} }
if !reflect.DeepEqual(gvp, test.expected) {
t.Errorf("%d: expected %+v, got %+v", i, test.expected, gvp)
}
if !reflect.DeepEqual(groups, test.expectedGroups) { if !reflect.DeepEqual(groups, test.expectedGroups) {
t.Errorf("%d: expected groups %+v, got groups %+v", i, test.expectedGroups, groups) t.Errorf("%d: expected groups %+v, got groups %+v", i, test.expectedGroups, groups)
} }

View File

@ -233,7 +233,7 @@ func packageForScheme(customArgs *clientgenargs.CustomArgs, clientsetPackage str
NextGroup: NextGroup:
for _, group := range customArgs.Groups { for _, group := range customArgs.Groups {
for _, v := range group.Versions { for _, v := range group.Versions {
if v == "" { if v.String() == "" {
internalClient = true internalClient = true
break NextGroup break NextGroup
} }
@ -258,7 +258,7 @@ NextGroup:
DefaultGen: generator.DefaultGen{ DefaultGen: generator.DefaultGen{
OptionalName: "register", OptionalName: "register",
}, },
InputPackages: customArgs.GroupVersionToInputPath, InputPackages: customArgs.GroupVersionPackages(),
OutputPackage: schemePackage, OutputPackage: schemePackage,
OutputPath: filepath.Join(srcTreePath, schemePackage), OutputPath: filepath.Join(srcTreePath, schemePackage),
Groups: customArgs.Groups, Groups: customArgs.Groups,
@ -274,13 +274,13 @@ NextGroup:
// applyGroupOverrides applies group name overrides to each package, if applicable. If there is a // applyGroupOverrides applies group name overrides to each package, if applicable. If there is a
// comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", use the // comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", use the
// first field (somegroup) as the name of the group when generating. // first field (somegroup) as the name of the group in Go code, e.g. as the func name in a clientset.
// //
// If the first field of the groupName is not unique within the clientset, use "// +groupName=unique // If the first field of the groupName is not unique within the clientset, use "// +groupName=unique
func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.CustomArgs) { func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.CustomArgs) {
// Create a map from "old GV" to "new GV" so we know what changes we need to make. // Create a map from "old GV" to "new GV" so we know what changes we need to make.
changes := make(map[clientgentypes.GroupVersion]clientgentypes.GroupVersion) changes := make(map[clientgentypes.GroupVersion]clientgentypes.GroupVersion)
for gv, inputDir := range customArgs.GroupVersionToInputPath { for gv, inputDir := range customArgs.GroupVersionPackages() {
p := universe.Package(inputDir) p := universe.Package(inputDir)
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
newGV := clientgentypes.GroupVersion{ newGV := clientgentypes.GroupVersion{
@ -296,7 +296,7 @@ func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.Cust
for _, gvs := range customArgs.Groups { for _, gvs := range customArgs.Groups {
gv := clientgentypes.GroupVersion{ gv := clientgentypes.GroupVersion{
Group: gvs.Group, Group: gvs.Group,
Version: gvs.Versions[0], // we only need a version, and the first will do Version: gvs.Versions[0].Version, // we only need a version, and the first will do
} }
if newGV, ok := changes[gv]; ok { if newGV, ok := changes[gv]; ok {
// There's an override, so use it. // There's an override, so use it.
@ -312,19 +312,6 @@ func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.Cust
} }
} }
customArgs.Groups = newGroups customArgs.Groups = newGroups
// Modify customArgs.GroupVersionToInputPath based on the groupName overrides.
newGVToInputPath := make(map[clientgentypes.GroupVersion]string)
for gv, inputDir := range customArgs.GroupVersionToInputPath {
if newGV, ok := changes[gv]; ok {
// There's an override, so use it.
newGVToInputPath[newGV] = inputDir
} else {
// No override.
newGVToInputPath[gv] = inputDir
}
}
customArgs.GroupVersionToInputPath = newGVToInputPath
} }
// Packages makes the client package definition. // Packages makes the client package definition.
@ -344,7 +331,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
gvToTypes := map[clientgentypes.GroupVersion][]*types.Type{} gvToTypes := map[clientgentypes.GroupVersion][]*types.Type{}
groupGoNames := make(map[clientgentypes.GroupVersion]string) groupGoNames := make(map[clientgentypes.GroupVersion]string)
for gv, inputDir := range customArgs.GroupVersionToInputPath { for gv, inputDir := range customArgs.GroupVersionPackages() {
p := context.Universe.Package(path.Vendorless(inputDir)) p := context.Universe.Package(path.Vendorless(inputDir))
// If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as
@ -398,11 +385,12 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
} }
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
gvPackages := customArgs.GroupVersionPackages()
for _, group := range customArgs.Groups { for _, group := range customArgs.Groups {
for _, version := range group.Versions { for _, version := range group.Versions {
gv := clientgentypes.GroupVersion{Group: group.Group, Version: version} gv := clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}
types := gvToTypes[gv] types := gvToTypes[gv]
inputPath := customArgs.GroupVersionToInputPath[gv] inputPath := gvPackages[gv]
packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, boilerplate)) packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, boilerplate))
if customArgs.FakeClient { if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, boilerplate)) packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, boilerplate))

View File

@ -116,7 +116,7 @@ func PackageForClientset(customArgs *clientgenargs.CustomArgs, fakeClientsetPack
DefaultGen: generator.DefaultGen{ DefaultGen: generator.DefaultGen{
OptionalName: "register", OptionalName: "register",
}, },
InputPackages: customArgs.GroupVersionToInputPath, InputPackages: customArgs.GroupVersionPackages(),
OutputPackage: fakeClientsetPackage, OutputPackage: fakeClientsetPackage,
Groups: customArgs.Groups, Groups: customArgs.Groups,
GroupGoNames: groupGoNames, GroupGoNames: groupGoNames,

View File

@ -63,7 +63,7 @@ func (g *genClientset) Imports(c *generator.Context) (imports []string) {
groupClientPackage := filepath.Join(g.fakeClientsetPackage, "typed", group.PackageName, version.NonEmpty()) groupClientPackage := filepath.Join(g.fakeClientsetPackage, "typed", group.PackageName, version.NonEmpty())
fakeGroupClientPackage := filepath.Join(groupClientPackage, "fake") fakeGroupClientPackage := filepath.Join(groupClientPackage, "fake")
groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{group.Group, version}]) groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{group.Group, version.Version}])
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), groupClientPackage))) imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), groupClientPackage)))
imports = append(imports, strings.ToLower(fmt.Sprintf("fake%s%s \"%s\"", groupAlias, version.NonEmpty(), fakeGroupClientPackage))) imports = append(imports, strings.ToLower(fmt.Sprintf("fake%s%s \"%s\"", groupAlias, version.NonEmpty(), fakeGroupClientPackage)))
} }
@ -87,7 +87,7 @@ func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Wr
// perhaps we can adapt the go2ild framework to this kind of usage. // perhaps we can adapt the go2ild framework to this kind of usage.
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroups := clientgentypes.ToGroupVersionPackages(g.groups, g.groupGoNames) allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames)
sw.Do(common, nil) sw.Do(common, nil)
sw.Do(checkImpl, nil) sw.Do(checkImpl, nil)

View File

@ -59,7 +59,7 @@ func (g *genClientset) Imports(c *generator.Context) (imports []string) {
for _, group := range g.groups { for _, group := range g.groups {
for _, version := range group.Versions { for _, version := range group.Versions {
typedClientPath := filepath.Join(g.clientsetPackage, "typed", group.PackageName, version.NonEmpty()) typedClientPath := filepath.Join(g.clientsetPackage, "typed", group.PackageName, version.NonEmpty())
groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{group.Group, version}]) groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{group.Group, version.Version}])
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), typedClientPath))) imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), typedClientPath)))
} }
} }
@ -71,7 +71,7 @@ func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Wr
// perhaps we can adapt the go2ild framework to this kind of usage. // perhaps we can adapt the go2ild framework to this kind of usage.
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroups := clientgentypes.ToGroupVersionPackages(g.groups, g.groupGoNames) allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames)
m := map[string]interface{}{ m := map[string]interface{}{
"allGroups": allGroups, "allGroups": allGroups,
"Config": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), "Config": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}),

View File

@ -61,18 +61,18 @@ func (g *GenScheme) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.ImportTracker.ImportLines()...) imports = append(imports, g.ImportTracker.ImportLines()...)
for _, group := range g.Groups { for _, group := range g.Groups {
for _, version := range group.Versions { for _, version := range group.Versions {
packagePath := g.InputPackages[clientgentypes.GroupVersion{Group: group.Group, Version: version}] packagePath := g.InputPackages[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]
groupAlias := strings.ToLower(g.GroupGoNames[clientgentypes.GroupVersion{group.Group, version}]) groupAlias := strings.ToLower(g.GroupGoNames[clientgentypes.GroupVersion{group.Group, version.Version}])
if g.CreateRegistry { if g.CreateRegistry {
// import the install package for internal clientsets instead of the type package with register.go // import the install package for internal clientsets instead of the type package with register.go
if version != "" { if version.Version != "" {
packagePath = filepath.Dir(packagePath) packagePath = filepath.Dir(packagePath)
} }
packagePath = filepath.Join(packagePath, "install") packagePath = filepath.Join(packagePath, "install")
imports = append(imports, strings.ToLower(fmt.Sprintf("%s \"%s\"", groupAlias, path.Vendorless(packagePath)))) imports = append(imports, strings.ToLower(fmt.Sprintf("%s \"%s\"", groupAlias, path.Vendorless(packagePath))))
break break
} else { } else {
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), path.Vendorless(packagePath)))) imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.Version.NonEmpty(), path.Vendorless(packagePath))))
} }
} }
} }
@ -82,7 +82,7 @@ func (g *GenScheme) Imports(c *generator.Context) (imports []string) {
func (g *GenScheme) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { func (g *GenScheme) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroupVersions := clientgentypes.ToGroupVersionPackages(g.Groups, g.GroupGoNames) allGroupVersions := clientgentypes.ToGroupVersionInfo(g.Groups, g.GroupGoNames)
allInstallGroups := clientgentypes.ToGroupInstallPackages(g.Groups, g.GroupGoNames) allInstallGroups := clientgentypes.ToGroupInstallPackages(g.Groups, g.GroupGoNames)
m := map[string]interface{}{ m := map[string]interface{}{

View File

@ -19,7 +19,6 @@ package main
import ( import (
"flag" "flag"
"path"
"path/filepath" "path/filepath"
"github.com/golang/glog" "github.com/golang/glog"
@ -53,12 +52,11 @@ func main() {
pflag.CommandLine.AddGoFlagSet(flag.CommandLine) pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse() pflag.Parse()
// Prefix with InputBaseDir and add client dirs as input dirs. // add group version package as input dirs for gengo
for gv, pth := range customArgs.GroupVersionToInputPath { for _, pkg := range customArgs.Groups {
customArgs.GroupVersionToInputPath[gv] = path.Join(customArgs.InputBasePath, pth) for _, v := range pkg.Versions {
arguments.InputDirs = append(arguments.InputDirs, v.Package)
} }
for _, pkg := range customArgs.GroupVersionToInputPath {
arguments.InputDirs = append(arguments.InputDirs, pkg)
} }
if err := arguments.Execute( if err := arguments.Execute(

View File

@ -75,27 +75,27 @@ func (a sortableSliceOfVersions) Less(i, j int) bool {
// Determine the default version among versions. If a user calls a group client // Determine the default version among versions. If a user calls a group client
// without specifying the version (e.g., c.Core(), instead of c.CoreV1()), the // without specifying the version (e.g., c.Core(), instead of c.CoreV1()), the
// default version will be returned. // default version will be returned.
func defaultVersion(versions []Version) Version { func defaultVersion(versions []PackageVersion) Version {
var versionStrings []string var versionStrings []string
for _, version := range versions { for _, version := range versions {
versionStrings = append(versionStrings, string(version)) versionStrings = append(versionStrings, version.Version.String())
} }
sort.Sort(sortableSliceOfVersions(versionStrings)) sort.Sort(sortableSliceOfVersions(versionStrings))
return Version(versionStrings[len(versionStrings)-1]) return Version(versionStrings[len(versionStrings)-1])
} }
// ToGroupVersionPackages is a helper function used by generators for groups. // ToGroupVersionInfo is a helper function used by generators for groups.
func ToGroupVersionPackages(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupVersionPackage { func ToGroupVersionInfo(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupVersionInfo {
var groupVersionPackages []GroupVersionPackage var groupVersionPackages []GroupVersionInfo
for _, group := range groups { for _, group := range groups {
defaultVersion := defaultVersion(group.Versions) defaultVersion := defaultVersion(group.Versions)
for _, version := range group.Versions { for _, version := range group.Versions {
groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: version}] groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: version.Version}]
groupVersionPackages = append(groupVersionPackages, GroupVersionPackage{ groupVersionPackages = append(groupVersionPackages, GroupVersionInfo{
Group: Group(namer.IC(group.Group.NonEmpty())), Group: Group(namer.IC(group.Group.NonEmpty())),
Version: Version(namer.IC(version.String())), Version: Version(namer.IC(version.Version.String())),
PackageAlias: strings.ToLower(groupGoName + version.NonEmpty()), PackageAlias: strings.ToLower(groupGoName + version.Version.NonEmpty()),
IsDefaultVersion: version == defaultVersion && version != "", IsDefaultVersion: version.Version == defaultVersion && version.Version != "",
GroupGoName: groupGoName, GroupGoName: groupGoName,
LowerCaseGroupGoName: namer.IL(groupGoName), LowerCaseGroupGoName: namer.IL(groupGoName),
}) })

View File

@ -42,20 +42,26 @@ func (g Group) NonEmpty() string {
return string(g) return string(g)
} }
type PackageVersion struct {
Version
// The fully qualified package, e.g. k8s.io/kubernetes/pkg/apis/apps, where the types.go is found.
Package string
}
type GroupVersion struct { type GroupVersion struct {
Group Group Group Group
Version Version Version Version
} }
type GroupVersions struct { type GroupVersions struct {
// The package name of the group, e.g. extensions or networking // The name of the package for this group, e.g. apps.
PackageName string PackageName string
Group Group Group Group
Versions []Version Versions []PackageVersion
} }
// GroupVersionPackage contains group name, version name, and the package name client-gen will generate for this group version. // GroupVersionInfo contains all the info around a group version.
type GroupVersionPackage struct { type GroupVersionInfo struct {
Group Group Group Group
Version Version Version Version
// If a user calls a group client without specifying the version (e.g., // If a user calls a group client without specifying the version (e.g.,

View File

@ -105,10 +105,10 @@ func (g *genericGenerator) GenerateType(c *generator.Context, t *types.Type, w i
Versions: []*version{}, Versions: []*version{},
} }
for _, v := range groupVersions.Versions { for _, v := range groupVersions.Versions {
gv := clientgentypes.GroupVersion{Group: groupVersions.Group, Version: v} gv := clientgentypes.GroupVersion{Group: groupVersions.Group, Version: v.Version}
version := &version{ version := &version{
Name: v.NonEmpty(), Name: v.Version.NonEmpty(),
GoName: namer.IC(v.NonEmpty()), GoName: namer.IC(v.Version.NonEmpty()),
Resources: orderer.OrderTypes(g.typesForGroupVersion[gv]), Resources: orderer.OrderTypes(g.typesForGroupVersion[gv]),
} }
schemeGVs[version] = c.Universe.Variable(types.Name{Package: g.typesForGroupVersion[gv][0].Name.Package, Name: "SchemeGroupVersion"}) schemeGVs[version] = c.Universe.Variable(types.Name{Package: g.typesForGroupVersion[gv][0].Name.Package, Name: "SchemeGroupVersion"})

View File

@ -69,11 +69,11 @@ func (g *groupInterfaceGenerator) GenerateType(c *generator.Context, t *types.Ty
versions := make([]versionData, 0, len(g.groupVersions.Versions)) versions := make([]versionData, 0, len(g.groupVersions.Versions))
for _, version := range g.groupVersions.Versions { for _, version := range g.groupVersions.Versions {
gv := clientgentypes.GroupVersion{Group: g.groupVersions.Group, Version: version} gv := clientgentypes.GroupVersion{Group: g.groupVersions.Group, Version: version.Version}
versionPackage := filepath.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty())) versionPackage := filepath.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty()))
iface := c.Universe.Type(types.Name{Package: versionPackage, Name: "Interface"}) iface := c.Universe.Type(types.Name{Package: versionPackage, Name: "Interface"})
versions = append(versions, versionData{ versions = append(versions, versionData{
Name: namer.IC(version.NonEmpty()), Name: namer.IC(version.Version.NonEmpty()),
Interface: iface, Interface: iface,
New: c.Universe.Function(types.Name{Package: versionPackage, Name: "New"}), New: c.Universe.Function(types.Name{Package: versionPackage, Name: "New"}),
}) })

View File

@ -18,6 +18,7 @@ package generators
import ( import (
"fmt" "fmt"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
@ -158,7 +159,8 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
gv.Version = clientgentypes.Version(parts[len(parts)-1]) gv.Version = clientgentypes.Version(parts[len(parts)-1])
targetGroupVersions = externalGroupVersions targetGroupVersions = externalGroupVersions
} }
groupPkgName := strings.ToLower(gv.Group.NonEmpty()) groupPackageName := gv.Group.NonEmpty()
gvPackage := path.Clean(p.Path)
// If there's a comment of the form "// +groupName=somegroup" or // If there's a comment of the form "// +groupName=somegroup" or
// "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the // "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the
@ -169,9 +171,9 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as
// the Go group identifier in CamelCase. It defaults // the Go group identifier in CamelCase. It defaults
groupGoNames[groupPkgName] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0]) groupGoNames[groupPackageName] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0])
if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
groupGoNames[groupPkgName] = namer.IC(override[0]) groupGoNames[groupPackageName] = namer.IC(override[0])
} }
var typesToGenerate []*types.Type var typesToGenerate []*types.Type
@ -192,23 +194,23 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
continue continue
} }
groupVersionsEntry, ok := targetGroupVersions[groupPkgName] groupVersionsEntry, ok := targetGroupVersions[groupPackageName]
if !ok { if !ok {
groupVersionsEntry = clientgentypes.GroupVersions{ groupVersionsEntry = clientgentypes.GroupVersions{
PackageName: groupPkgName, PackageName: groupPackageName,
Group: gv.Group, Group: gv.Group,
} }
} }
groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, gv.Version) groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, clientgentypes.PackageVersion{Version: gv.Version, Package: gvPackage})
targetGroupVersions[groupPkgName] = groupVersionsEntry targetGroupVersions[groupPackageName] = groupVersionsEntry
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
typesToGenerate = orderer.OrderTypes(typesToGenerate) typesToGenerate = orderer.OrderTypes(typesToGenerate)
if internal { if internal {
packageList = append(packageList, versionPackage(internalVersionPackagePath, groupPkgName, gv, groupGoNames[groupPkgName], boilerplate, typesToGenerate, customArgs.InternalClientSetPackage, customArgs.ListersPackage)) packageList = append(packageList, versionPackage(internalVersionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs.InternalClientSetPackage, customArgs.ListersPackage))
} else { } else {
packageList = append(packageList, versionPackage(externalVersionPackagePath, groupPkgName, gv, groupGoNames[groupPkgName], boilerplate, typesToGenerate, customArgs.VersionedClientSetPackage, customArgs.ListersPackage)) packageList = append(packageList, versionPackage(externalVersionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs.VersionedClientSetPackage, customArgs.ListersPackage))
} }
} }