mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +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{
|
||||
ExternalApplyConfigurations: map[types.Name]string{
|
||||
// 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: "ObjectMeta"}: "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: "OwnerReference"}: "k8s.io/client-go/applyconfigurations/meta/v1",
|
||||
},
|
||||
}
|
||||
genericArgs.CustomArgs = customArgs
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
|
||||
type externalApplyConfigurationValue struct {
|
||||
externals *map[types.Name]string
|
||||
changed bool
|
||||
}
|
||||
|
||||
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{}
|
||||
|
||||
func (s *externalApplyConfigurationValue) set(vs []string) error {
|
||||
if !s.changed {
|
||||
*s.externals = map[types.Name]string{}
|
||||
}
|
||||
|
||||
for _, input := range vs {
|
||||
typ, pkg, err := parseExternalMapping(input)
|
||||
if err != nil {
|
||||
@ -71,6 +66,7 @@ func (s *externalApplyConfigurationValue) Set(val string) error {
|
||||
if err := s.set(vs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -114,12 +110,13 @@ func parseExternalMapping(mapping string) (typ types.Name, pkg string, err error
|
||||
}
|
||||
packageTypeStr := parts[0]
|
||||
pkg = parts[1]
|
||||
ptParts := strings.Split(packageTypeStr, ".")
|
||||
if len(ptParts) != 2 {
|
||||
return types.Name{}, "", fmt.Errorf("expected package and type of the form <package>#<typeName> but got %s", packageTypeStr)
|
||||
// need to split on the *last* dot, since k8s.io (and other valid packages) have a dot in it
|
||||
lastDot := strings.LastIndex(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]
|
||||
structType := ptParts[1]
|
||||
structPkg := packageTypeStr[:lastDot]
|
||||
structType := packageTypeStr[lastDot+1:]
|
||||
|
||||
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 {
|
||||
for _, member := range t.Members {
|
||||
if typeMeta.Name == member.Type.Name {
|
||||
if typeMeta.Name == member.Type.Name && member.Embedded {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -157,7 +157,6 @@ func (g *applyConfigurationGenerator) generateWithFuncs(t *types.Type, typeParam
|
||||
EmbeddedIn: embed,
|
||||
}
|
||||
if memberParams.Member.Embedded {
|
||||
|
||||
g.generateWithFuncs(member.Type, typeParams, sw, &memberParams)
|
||||
if !jsonTags.inline {
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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:
|
||||
// WithFoos(Foo().WithName("x"), Foo().WithName("y"))
|
||||
if t := deref(member.Type); t.Kind == types.Slice && g.refGraph.isApplyConfig(t.Elem) {
|
||||
memberParams.ArgType = &types.Type{Kind: types.Pointer, Elem: memberType.Elem}
|
||||
g.generateMemberWithForSlice(sw, memberParams)
|
||||
g.generateMemberWithForSlice(sw, member, memberParams)
|
||||
continue
|
||||
}
|
||||
// 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 {
|
||||
case types.Slice:
|
||||
memberParams.ArgType = memberType.Elem
|
||||
g.generateMemberWithForSlice(sw, memberParams)
|
||||
g.generateMemberWithForSlice(sw, member, memberParams)
|
||||
case types.Map:
|
||||
g.generateMemberWithForMap(sw, memberParams)
|
||||
default:
|
||||
@ -252,20 +252,39 @@ func (g *applyConfigurationGenerator) generateMemberWith(sw *generator.SnippetWr
|
||||
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("// 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("func (b *$.ApplyConfig.ApplyConfiguration|public$) With$.Member.Name$(values ...$.ArgType|raw$) *$.ApplyConfig.ApplyConfiguration|public$ {\n", 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)
|
||||
if memberParams.ArgType.Kind == types.Pointer {
|
||||
sw.Do("if values[i] == nil {\n", memberParams)
|
||||
sw.Do(" panic(\"nil value passed to With$.Member.Name$\")\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 {
|
||||
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(" 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 = `
|
||||
// $.ApplyConfig.Type|public$ constructs an declarative configuration of the $.ApplyConfig.Type|public$ type for use with
|
||||
// apply.
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
@ -81,6 +82,13 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
|
||||
|
||||
var toGenerate []applyConfig
|
||||
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 {
|
||||
toGenerate = append(toGenerate, applyConfig{
|
||||
Type: t,
|
||||
@ -236,8 +244,12 @@ func packageTypesForInputDirs(context *generator.Context, inputDirs []string, ou
|
||||
klog.Warningf("Skipping internal package: %s", p.Path)
|
||||
continue
|
||||
}
|
||||
gv := groupVersion(p)
|
||||
pkg := filepath.Join(outputPath, gv.Group.PackageName(), strings.ToLower(gv.Version.NonEmpty()))
|
||||
// This is how the client generator finds the package we are creating. It uses the API package name, not the group name.
|
||||
// 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
|
||||
}
|
||||
return pkgTypes
|
||||
@ -274,3 +286,12 @@ func isInternal(m types.Member) bool {
|
||||
_, ok := lookupJSONTags(m)
|
||||
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