From e9310b6627a302d7bf6f275cdedc8e5cc3888779 Mon Sep 17 00:00:00 2001 From: Amund Tenstad Date: Thu, 24 Mar 2022 14:17:29 +0100 Subject: [PATCH] Only inline inlined types; remove inline ignore config --- config.yaml | 5 +- processor/config.go | 22 ------- processor/config_test.go | 5 -- processor/processor.go | 26 +++----- test/api/v1/zz_generated.deepcopy.go | 88 ++++++++++++++++++++++++++++ test/config.yaml | 5 +- test/expected.asciidoc | 4 ++ test/expected.md | 2 + types/types.go | 43 +++++++------- 9 files changed, 125 insertions(+), 75 deletions(-) diff --git a/config.yaml b/config.yaml index 1e48e9b..e0fe966 100644 --- a/config.yaml +++ b/config.yaml @@ -5,12 +5,9 @@ processor: - "(Elasticsearch|Kibana|ApmServer|Reconciler)Status$" - "ElasticsearchSettings$" - "Associa(ted|tor|tionStatus|tionConf)$" - embeddedIgnoreTypes: - - "TypeMeta$" - - "ObjectMeta$" - - "ListMeta$" ignoreFields: - "status$" + - "TypeMeta$" render: kubernetesVersion: 1.22 diff --git a/processor/config.go b/processor/config.go index 2dbefc3..5fa03a5 100644 --- a/processor/config.go +++ b/processor/config.go @@ -30,7 +30,6 @@ func compileConfig(conf *config.Config) (cc *compiledConfig, err error) { cc = &compiledConfig{ ignoreTypes: make([]*regexp.Regexp, len(conf.Processor.IgnoreTypes)), - embeddedIgnoreTypes: make([]*regexp.Regexp, len(conf.Processor.EmbeddedIgnoreTypes)), ignoreFields: make([]*regexp.Regexp, len(conf.Processor.IgnoreFields)), ignoreGroupVersions: make([]*regexp.Regexp, len(conf.Processor.IgnoreGroupVersions)), } @@ -41,12 +40,6 @@ func compileConfig(conf *config.Config) (cc *compiledConfig, err error) { } } - for i, f := range conf.Processor.EmbeddedIgnoreTypes { - if cc.embeddedIgnoreTypes[i], err = regexp.Compile(f); err != nil { - return nil, fmt.Errorf("failed to compile type regex '%s': %w", f, err) - } - } - for i, f := range conf.Processor.IgnoreFields { if cc.ignoreFields[i], err = regexp.Compile(f); err != nil { return nil, fmt.Errorf("failed to compile field regex '%s': %w", f, err) @@ -64,7 +57,6 @@ func compileConfig(conf *config.Config) (cc *compiledConfig, err error) { type compiledConfig struct { ignoreTypes []*regexp.Regexp - embeddedIgnoreTypes []*regexp.Regexp ignoreFields []*regexp.Regexp ignoreGroupVersions []*regexp.Regexp } @@ -97,20 +89,6 @@ func (cc *compiledConfig) shouldIgnoreType(fqn string) bool { return false } -func (cc *compiledConfig) shouldIgnoreEmbeddedType(fqn string) bool { - if cc == nil { - return false - } - - for _, re := range cc.embeddedIgnoreTypes { - if re.MatchString(fqn) { - return true - } - } - - return false -} - func (cc *compiledConfig) shouldIgnoreField(typeName, fieldName string) bool { if cc == nil { return false diff --git a/processor/config_test.go b/processor/config_test.go index 50c1f27..e22aaec 100644 --- a/processor/config_test.go +++ b/processor/config_test.go @@ -25,11 +25,6 @@ func TestCompiledConfig(t *testing.T) { require.False(t, cc.shouldIgnoreType("typexyz")) }) - t.Run("imbeddedIgnoreTypes", func(t *testing.T) { - require.True(t, cc.shouldIgnoreEmbeddedType("mytypex")) - require.False(t, cc.shouldIgnoreEmbeddedType("typexyz")) - }) - t.Run("ignoreField", func(t *testing.T) { require.True(t, cc.shouldIgnoreField("mytype", "Fieldy")) require.False(t, cc.shouldIgnoreField("mytype", "Fieldyz")) diff --git a/processor/processor.go b/processor/processor.go index 48b4721..9b24280 100644 --- a/processor/processor.go +++ b/processor/processor.go @@ -61,7 +61,7 @@ func Process(config *config.Config) ([]types.GroupVersionDetails, error) { return nil, fmt.Errorf("failed to find API types in directory %s:%w", config.SourcePath, err) } - p.types.InlineEmbeddedFields() + p.types.InlineTypes() // collect references between types for typeName, refs := range p.references { @@ -274,11 +274,6 @@ func (p *processor) processType(pkg *loader.Package, info *markers.TypeInfo, dep Doc: info.Doc, } - if p.shouldIgnoreType(types.Key(typeDef)) && p.shouldIgnoreEmbeddedType(types.Key(typeDef)) { - zap.S().Debugw("Skipping excluded type", "type", typeDef.String()) - return nil - } - // if the field list is non-empty, this is a struct if len(info.Fields) > 0 { typeDef.Kind = types.StructKind @@ -335,17 +330,14 @@ func (p *processor) processStructFields(parentType *types.Type, pkg *loader.Pack continue } - if fieldDef.Embedded && fieldDef.Name == "" { - fieldDef.Name = fieldDef.Type.Name - } - if fieldDef.Embedded { - if p.shouldIgnoreEmbeddedType(types.Key(fieldDef.Type)) { - zap.S().Debugw("Skipping excluded embedded type", - "type", parentType.String(), "embeddedType", fieldDef.Type.Name) - continue + fieldDef.Inlined = fieldDef.Name == "" + if fieldDef.Name == "" { + fieldDef.Name = fieldDef.Type.Name } - } else if p.shouldIgnoreField(parentTypeKey, fieldDef.Name) { + } + + if p.shouldIgnoreField(parentTypeKey, fieldDef.Name) { zap.S().Debugw("Skipping excluded field", "type", parentType.String(), "field", fieldDef.Name) continue } @@ -366,10 +358,6 @@ func (p *processor) loadType(pkg *loader.Package, t gotypes.Type, depth int) *ty } typeDef := mkType(pkg, t) - if p.shouldIgnoreType(types.Key(typeDef)) && p.shouldIgnoreEmbeddedType(types.Key(typeDef)) { - zap.S().Debugw("Skipping excluded type", "type", t.String()) - return nil - } zap.S().Debugw("Load", "package", typeDef.Package, "name", typeDef.Name) diff --git a/test/api/v1/zz_generated.deepcopy.go b/test/api/v1/zz_generated.deepcopy.go index bde5968..2ef8b0a 100644 --- a/test/api/v1/zz_generated.deepcopy.go +++ b/test/api/v1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated // Licensed to Elasticsearch B.V. under one or more contributor @@ -25,6 +26,93 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Embedded) DeepCopyInto(out *Embedded) { + *out = *in + out.Embedded1 = in.Embedded1 +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Embedded. +func (in *Embedded) DeepCopy() *Embedded { + if in == nil { + return nil + } + out := new(Embedded) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Embedded) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Embedded1) DeepCopyInto(out *Embedded1) { + *out = *in + out.Embedded2 = in.Embedded2 +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Embedded1. +func (in *Embedded1) DeepCopy() *Embedded1 { + if in == nil { + return nil + } + out := new(Embedded1) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Embedded2) DeepCopyInto(out *Embedded2) { + *out = *in + out.Embedded3 = in.Embedded3 +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Embedded2. +func (in *Embedded2) DeepCopy() *Embedded2 { + if in == nil { + return nil + } + out := new(Embedded2) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Embedded3) DeepCopyInto(out *Embedded3) { + *out = *in + out.Embedded4 = in.Embedded4 +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Embedded3. +func (in *Embedded3) DeepCopy() *Embedded3 { + if in == nil { + return nil + } + out := new(Embedded3) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Embedded4) DeepCopyInto(out *Embedded4) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Embedded4. +func (in *Embedded4) DeepCopy() *Embedded4 { + if in == nil { + return nil + } + out := new(Embedded4) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Guestbook) DeepCopyInto(out *Guestbook) { *out = *in diff --git a/test/config.yaml b/test/config.yaml index ea5721f..11060fe 100644 --- a/test/config.yaml +++ b/test/config.yaml @@ -3,12 +3,9 @@ processor: - "GVK" ignoreTypes: - "Embedded[0-9]$" - embeddedIgnoreTypes: - - "TypeMeta$" - - "ObjectMeta$" - - "ListMeta$" ignoreFields: - "status$" + - "TypeMeta$" render: kubernetesVersion: 1.22 diff --git a/test/expected.asciidoc b/test/expected.asciidoc index 779e629..2076a27 100644 --- a/test/expected.asciidoc +++ b/test/expected.asciidoc @@ -55,6 +55,8 @@ Guestbook is the Schema for the guestbooks API. | Field | Description | *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` | *`kind`* __string__ | `Guestbook` +| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. + | *`spec`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookspec[$$GuestbookSpec$$]__ | |=== @@ -103,6 +105,8 @@ GuestbookList contains a list of Guestbook. | Field | Description | *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` | *`kind`* __string__ | `GuestbookList` +| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#listmeta-v1-meta[$$ListMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. + | *`items`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbook[$$Guestbook$$] array__ | |=== diff --git a/test/expected.md b/test/expected.md index 48afa1c..1471acb 100644 --- a/test/expected.md +++ b/test/expected.md @@ -47,6 +47,7 @@ _Appears in:_ | --- | --- | | `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` | `kind` _string_ | `Guestbook` +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | `spec` _[GuestbookSpec](#guestbookspec)_ | | @@ -90,6 +91,7 @@ GuestbookList contains a list of Guestbook. | --- | --- | | `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` | `kind` _string_ | `GuestbookList` +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | `items` _[Guestbook](#guestbook) array_ | | diff --git a/types/types.go b/types/types.go index dd0a980..b1d3d98 100644 --- a/types/types.go +++ b/types/types.go @@ -211,9 +211,9 @@ func (t *Type) SortedReferences() []*Type { return t.References } -func (t *Type) ContainsEmbeddedField() bool { +func (t *Type) ContainsInlinedTypes() bool { for _, f := range t.Members() { - if f.Embedded { + if f.Inlined { return true } } @@ -223,23 +223,23 @@ func (t *Type) ContainsEmbeddedField() bool { // TypeMap is a map of Type elements type TypeMap map[string]*Type -func (types TypeMap) InlineEmbeddedFields() { - // If C is embedded in B, and B is embedded in A; the fields in C are - // inlined in B before the fields in B is inlined in A. The ideal order of - // iterating and embedding types is NOT known. Worst-case, only one type's +func (types TypeMap) InlineTypes() { + // If C is inlined in B, and B is inlined in A; the fields of C are copied + // into B before the fields of B is copied into A. The ideal order of + // iterating and inlining fields is NOT known. Worst-case, only one type's // fields are inlined in its parent type in each iteration. maxDepth := 100 - var numEmbeddedFields int + var numFieldsToBeInlined int for iteration := 0; iteration < maxDepth; iteration++ { - numEmbeddedFields = 0 + numFieldsToBeInlined = 0 for _, t := range types { // By iterating backwards, it is safe to delete field at current index - // and append the embedded fields it contains. + // and inline the fields it contains. for i := len(t.Fields) - 1; i >= 0; i-- { - if !t.Fields[i].Embedded { + if !t.Fields[i].Inlined { continue } - numEmbeddedFields += 1 + numFieldsToBeInlined += 1 embeddedType, ok := types[Key(t.Fields[i].Type)] if !ok { @@ -248,37 +248,38 @@ func (types TypeMap) InlineEmbeddedFields() { continue } - // Only inline embedded type's fields if the embedded type - // itself has no embedded types yet to be inlined. - if !embeddedType.ContainsEmbeddedField() { + // Only inline type's fields if the inlined type itself has no + // types yet to be inlined. + if !embeddedType.ContainsInlinedTypes() { zap.S().Debugw("Inlining embedded type", "type", t, "embeddedType", t.Fields[i].Type) - t.Fields.inlineEmbedded(i, embeddedType) + t.Fields.inlineType(i, embeddedType) } } } - if numEmbeddedFields == 0 { + if numFieldsToBeInlined == 0 { return } } - zap.S().Warnw("Failed to inline all embedded types", "remaining", numEmbeddedFields) + zap.S().Warnw("Failed to inline all embedded types", "remaining", numFieldsToBeInlined) } // Field describes a field in a struct. type Field struct { Name string Embedded bool + Inlined bool Doc string Type *Type } type Fields []*Field -// inlineEmbedded replaces field at index i with the fields of provided type. -func (fields *Fields) inlineEmbedded(i int, embedded *Type) { - new := make([]*Field, 0, len(*fields)+len(embedded.Fields)-1) +// inlineType replaces field at index i with the fields of provided type. +func (fields *Fields) inlineType(i int, t *Type) { + new := make([]*Field, 0, len(*fields)+len(t.Fields)-1) new = append(new, (*fields)[:i]...) - new = append(new, embedded.Fields...) + new = append(new, t.Fields...) *fields = append(new, (*fields)[i+1:]...) }