mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #111934 from deads2k/apply-gen
make applyconfiguration-gen work in non-kube repositiories
This commit is contained in:
commit
5f57708c88
@ -50,8 +50,9 @@ func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
|
|||||||
customArgs := &CustomArgs{
|
customArgs := &CustomArgs{
|
||||||
ExternalApplyConfigurations: map[types.Name]string{
|
ExternalApplyConfigurations: map[types.Name]string{
|
||||||
// Always include TypeMeta and ObjectMeta. They are sufficient for the vast majority of use cases.
|
// Always include TypeMeta and ObjectMeta. They are sufficient for the vast majority of use cases.
|
||||||
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "TypeMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1",
|
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "TypeMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1",
|
||||||
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ObjectMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1",
|
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ObjectMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1",
|
||||||
|
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "OwnerReference"}: "k8s.io/client-go/applyconfigurations/meta/v1",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genericArgs.CustomArgs = customArgs
|
genericArgs.CustomArgs = customArgs
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
|
|
||||||
type externalApplyConfigurationValue struct {
|
type externalApplyConfigurationValue struct {
|
||||||
externals *map[types.Name]string
|
externals *map[types.Name]string
|
||||||
changed bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExternalApplyConfigurationValue(externals *map[types.Name]string, def []string) *externalApplyConfigurationValue {
|
func NewExternalApplyConfigurationValue(externals *map[types.Name]string, def []string) *externalApplyConfigurationValue {
|
||||||
@ -45,10 +44,6 @@ func NewExternalApplyConfigurationValue(externals *map[types.Name]string, def []
|
|||||||
var _ flag.Value = &externalApplyConfigurationValue{}
|
var _ flag.Value = &externalApplyConfigurationValue{}
|
||||||
|
|
||||||
func (s *externalApplyConfigurationValue) set(vs []string) error {
|
func (s *externalApplyConfigurationValue) set(vs []string) error {
|
||||||
if !s.changed {
|
|
||||||
*s.externals = map[types.Name]string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, input := range vs {
|
for _, input := range vs {
|
||||||
typ, pkg, err := parseExternalMapping(input)
|
typ, pkg, err := parseExternalMapping(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -71,6 +66,7 @@ func (s *externalApplyConfigurationValue) Set(val string) error {
|
|||||||
if err := s.set(vs); err != nil {
|
if err := s.set(vs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,12 +110,13 @@ func parseExternalMapping(mapping string) (typ types.Name, pkg string, err error
|
|||||||
}
|
}
|
||||||
packageTypeStr := parts[0]
|
packageTypeStr := parts[0]
|
||||||
pkg = parts[1]
|
pkg = parts[1]
|
||||||
ptParts := strings.Split(packageTypeStr, ".")
|
// need to split on the *last* dot, since k8s.io (and other valid packages) have a dot in it
|
||||||
if len(ptParts) != 2 {
|
lastDot := strings.LastIndex(packageTypeStr, ".")
|
||||||
return types.Name{}, "", fmt.Errorf("expected package and type of the form <package>#<typeName> but got %s", packageTypeStr)
|
if lastDot == -1 || lastDot == len(packageTypeStr)-1 {
|
||||||
|
return types.Name{}, "", fmt.Errorf("expected package and type of the form <package>.<typeName> but got %s", packageTypeStr)
|
||||||
}
|
}
|
||||||
structPkg := ptParts[0]
|
structPkg := packageTypeStr[:lastDot]
|
||||||
structType := ptParts[1]
|
structType := packageTypeStr[lastDot+1:]
|
||||||
|
|
||||||
return types.Name{Package: structPkg, Name: structType}, pkg, nil
|
return types.Name{Package: structPkg, Name: structType}, pkg, nil
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ func (g *applyConfigurationGenerator) GenerateType(c *generator.Context, t *type
|
|||||||
|
|
||||||
func hasTypeMetaField(t *types.Type) bool {
|
func hasTypeMetaField(t *types.Type) bool {
|
||||||
for _, member := range t.Members {
|
for _, member := range t.Members {
|
||||||
if typeMeta.Name == member.Type.Name {
|
if typeMeta.Name == member.Type.Name && member.Embedded {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +157,6 @@ func (g *applyConfigurationGenerator) generateWithFuncs(t *types.Type, typeParam
|
|||||||
EmbeddedIn: embed,
|
EmbeddedIn: embed,
|
||||||
}
|
}
|
||||||
if memberParams.Member.Embedded {
|
if memberParams.Member.Embedded {
|
||||||
|
|
||||||
g.generateWithFuncs(member.Type, typeParams, sw, &memberParams)
|
g.generateWithFuncs(member.Type, typeParams, sw, &memberParams)
|
||||||
if !jsonTags.inline {
|
if !jsonTags.inline {
|
||||||
// non-inlined embeds are nillable and need a "ensure exists" utility function
|
// non-inlined embeds are nillable and need a "ensure exists" utility function
|
||||||
@ -165,12 +164,13 @@ func (g *applyConfigurationGenerator) generateWithFuncs(t *types.Type, typeParam
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// For slices where the items are generated apply configuration types, accept varargs of
|
// For slices where the items are generated apply configuration types, accept varargs of
|
||||||
// pointers of the type as "with" function arguments so the "with" function can be used like so:
|
// pointers of the type as "with" function arguments so the "with" function can be used like so:
|
||||||
// WithFoos(Foo().WithName("x"), Foo().WithName("y"))
|
// WithFoos(Foo().WithName("x"), Foo().WithName("y"))
|
||||||
if t := deref(member.Type); t.Kind == types.Slice && g.refGraph.isApplyConfig(t.Elem) {
|
if t := deref(member.Type); t.Kind == types.Slice && g.refGraph.isApplyConfig(t.Elem) {
|
||||||
memberParams.ArgType = &types.Type{Kind: types.Pointer, Elem: memberType.Elem}
|
memberParams.ArgType = &types.Type{Kind: types.Pointer, Elem: memberType.Elem}
|
||||||
g.generateMemberWithForSlice(sw, memberParams)
|
g.generateMemberWithForSlice(sw, member, memberParams)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Note: There are no maps where the values are generated apply configurations (because
|
// Note: There are no maps where the values are generated apply configurations (because
|
||||||
@ -182,7 +182,7 @@ func (g *applyConfigurationGenerator) generateWithFuncs(t *types.Type, typeParam
|
|||||||
switch memberParams.Member.Type.Kind {
|
switch memberParams.Member.Type.Kind {
|
||||||
case types.Slice:
|
case types.Slice:
|
||||||
memberParams.ArgType = memberType.Elem
|
memberParams.ArgType = memberType.Elem
|
||||||
g.generateMemberWithForSlice(sw, memberParams)
|
g.generateMemberWithForSlice(sw, member, memberParams)
|
||||||
case types.Map:
|
case types.Map:
|
||||||
g.generateMemberWithForMap(sw, memberParams)
|
g.generateMemberWithForMap(sw, memberParams)
|
||||||
default:
|
default:
|
||||||
@ -252,20 +252,39 @@ func (g *applyConfigurationGenerator) generateMemberWith(sw *generator.SnippetWr
|
|||||||
sw.Do("}\n", memberParams)
|
sw.Do("}\n", memberParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *applyConfigurationGenerator) generateMemberWithForSlice(sw *generator.SnippetWriter, memberParams memberParams) {
|
func (g *applyConfigurationGenerator) generateMemberWithForSlice(sw *generator.SnippetWriter, member types.Member, memberParams memberParams) {
|
||||||
|
memberIsPointerToSlice := member.Type.Kind == types.Pointer
|
||||||
|
if memberIsPointerToSlice {
|
||||||
|
sw.Do(ensureNonEmbedSliceExists, memberParams)
|
||||||
|
}
|
||||||
|
|
||||||
sw.Do("// With$.Member.Name$ adds the given value to the $.Member.Name$ field in the declarative configuration\n", memberParams)
|
sw.Do("// With$.Member.Name$ adds the given value to the $.Member.Name$ field in the declarative configuration\n", memberParams)
|
||||||
sw.Do("// and returns the receiver, so that objects can be build by chaining \"With\" function invocations.\n", memberParams)
|
sw.Do("// and returns the receiver, so that objects can be build by chaining \"With\" function invocations.\n", memberParams)
|
||||||
sw.Do("// If called multiple times, values provided by each call will be appended to the $.Member.Name$ field.\n", memberParams)
|
sw.Do("// If called multiple times, values provided by each call will be appended to the $.Member.Name$ field.\n", memberParams)
|
||||||
sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) With$.Member.Name$(values ...$.ArgType|raw$) *$.ApplyConfig.ApplyConfiguration|public$ {\n", memberParams)
|
sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) With$.Member.Name$(values ...$.ArgType|raw$) *$.ApplyConfig.ApplyConfiguration|public$ {\n", memberParams)
|
||||||
g.ensureEnbedExistsIfApplicable(sw, memberParams)
|
g.ensureEnbedExistsIfApplicable(sw, memberParams)
|
||||||
|
|
||||||
|
if memberIsPointerToSlice {
|
||||||
|
sw.Do("b.ensure$.MemberType.Elem|public$Exists()\n", memberParams)
|
||||||
|
}
|
||||||
|
|
||||||
sw.Do(" for i := range values {\n", memberParams)
|
sw.Do(" for i := range values {\n", memberParams)
|
||||||
if memberParams.ArgType.Kind == types.Pointer {
|
if memberParams.ArgType.Kind == types.Pointer {
|
||||||
sw.Do("if values[i] == nil {\n", memberParams)
|
sw.Do("if values[i] == nil {\n", memberParams)
|
||||||
sw.Do(" panic(\"nil value passed to With$.Member.Name$\")\n", memberParams)
|
sw.Do(" panic(\"nil value passed to With$.Member.Name$\")\n", memberParams)
|
||||||
sw.Do("}\n", memberParams)
|
sw.Do("}\n", memberParams)
|
||||||
sw.Do("b.$.Member.Name$ = append(b.$.Member.Name$, *values[i])\n", memberParams)
|
|
||||||
|
if memberIsPointerToSlice {
|
||||||
|
sw.Do("*b.$.Member.Name$ = append(*b.$.Member.Name$, *values[i])\n", memberParams)
|
||||||
|
} else {
|
||||||
|
sw.Do("b.$.Member.Name$ = append(b.$.Member.Name$, *values[i])\n", memberParams)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sw.Do("b.$.Member.Name$ = append(b.$.Member.Name$, values[i])\n", memberParams)
|
if memberIsPointerToSlice {
|
||||||
|
sw.Do("*b.$.Member.Name$ = append(*b.$.Member.Name$, values[i])\n", memberParams)
|
||||||
|
} else {
|
||||||
|
sw.Do("b.$.Member.Name$ = append(b.$.Member.Name$, values[i])\n", memberParams)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sw.Do(" }\n", memberParams)
|
sw.Do(" }\n", memberParams)
|
||||||
sw.Do(" return b\n", memberParams)
|
sw.Do(" return b\n", memberParams)
|
||||||
@ -305,6 +324,14 @@ func (b *$.ApplyConfig.ApplyConfiguration|public$) ensure$.MemberType.Elem|publi
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
var ensureNonEmbedSliceExists = `
|
||||||
|
func (b *$.ApplyConfig.ApplyConfiguration|public$) ensure$.MemberType.Elem|public$Exists() {
|
||||||
|
if b.$.Member.Name$ == nil {
|
||||||
|
b.$.Member.Name$ = &[]$.MemberType.Elem|raw${}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
var clientgenTypeConstructorNamespaced = `
|
var clientgenTypeConstructorNamespaced = `
|
||||||
// $.ApplyConfig.Type|public$ constructs an declarative configuration of the $.ApplyConfig.Type|public$ type for use with
|
// $.ApplyConfig.Type|public$ constructs an declarative configuration of the $.ApplyConfig.Type|public$ type for use with
|
||||||
// apply.
|
// apply.
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
applygenargs "k8s.io/code-generator/cmd/applyconfiguration-gen/args"
|
applygenargs "k8s.io/code-generator/cmd/applyconfiguration-gen/args"
|
||||||
|
"k8s.io/code-generator/cmd/client-gen/generators/util"
|
||||||
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
|
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,6 +82,13 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
|
|||||||
|
|
||||||
var toGenerate []applyConfig
|
var toGenerate []applyConfig
|
||||||
for _, t := range p.Types {
|
for _, t := range p.Types {
|
||||||
|
// If we don't have an ObjectMeta field, we lack the information required to make the Apply or ApplyStatus call
|
||||||
|
// to the kube-apiserver, so we don't need to generate the type at all
|
||||||
|
clientTags := genclientTags(t)
|
||||||
|
if clientTags.GenerateClient && !hasObjectMetaField(t) {
|
||||||
|
klog.V(5).Infof("skipping type %v because does not have ObjectMeta", t)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if typePkg, ok := refs[t.Name]; ok {
|
if typePkg, ok := refs[t.Name]; ok {
|
||||||
toGenerate = append(toGenerate, applyConfig{
|
toGenerate = append(toGenerate, applyConfig{
|
||||||
Type: t,
|
Type: t,
|
||||||
@ -236,8 +244,12 @@ func packageTypesForInputDirs(context *generator.Context, inputDirs []string, ou
|
|||||||
klog.Warningf("Skipping internal package: %s", p.Path)
|
klog.Warningf("Skipping internal package: %s", p.Path)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
gv := groupVersion(p)
|
// This is how the client generator finds the package we are creating. It uses the API package name, not the group name.
|
||||||
pkg := filepath.Join(outputPath, gv.Group.PackageName(), strings.ToLower(gv.Version.NonEmpty()))
|
// This matches the approach of the client-gen, so the two generator can work together.
|
||||||
|
// For example, if openshift/api/cloudnetwork/v1 contains an apigroup cloud.network.openshift.io, the client-gen
|
||||||
|
// builds a package called cloudnetwork/v1 to contain it. This change makes the applyconfiguration-gen use the same.
|
||||||
|
_, gvPackageString := util.ParsePathGroupVersion(p.Path)
|
||||||
|
pkg := filepath.Join(outputPath, strings.ToLower(gvPackageString))
|
||||||
pkgTypes[pkg] = p
|
pkgTypes[pkg] = p
|
||||||
}
|
}
|
||||||
return pkgTypes
|
return pkgTypes
|
||||||
@ -274,3 +286,12 @@ func isInternal(m types.Member) bool {
|
|||||||
_, ok := lookupJSONTags(m)
|
_, ok := lookupJSONTags(m)
|
||||||
return !ok
|
return !ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasObjectMetaField(t *types.Type) bool {
|
||||||
|
for _, member := range t.Members {
|
||||||
|
if objectMeta.Name == member.Type.Name && member.Embedded {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user