knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/codegen/cmd/injection-gen/generators/duck/duck.go (about)

     1  /*
     2  Copyright 2019 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package duck
    18  
    19  import (
    20  	"io"
    21  
    22  	clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
    23  	"k8s.io/gengo/v2/generator"
    24  	"k8s.io/gengo/v2/namer"
    25  	"k8s.io/gengo/v2/types"
    26  	"k8s.io/klog/v2"
    27  
    28  	gennamer "knative.dev/pkg/codegen/cmd/injection-gen/namer"
    29  )
    30  
    31  // duckGenerator produces logic to register a duck.InformerFactory for a particular
    32  // type onto context.
    33  type duckGenerator struct {
    34  	generator.GoGenerator
    35  	outputPackage  string
    36  	groupVersion   clientgentypes.GroupVersion
    37  	groupGoName    string
    38  	typeToGenerate *types.Type
    39  	imports        namer.ImportTracker
    40  }
    41  
    42  var _ generator.Generator = (*duckGenerator)(nil)
    43  
    44  func (g *duckGenerator) Filter(c *generator.Context, t *types.Type) bool {
    45  	// Only process the type for this informer generator.
    46  	return t == g.typeToGenerate
    47  }
    48  
    49  func (g *duckGenerator) Namers(c *generator.Context) namer.NameSystems {
    50  	publicPluralNamer := &gennamer.ExceptionNamer{
    51  		Exceptions: map[string]string{
    52  			// these exceptions are used to deconflict the generated code
    53  			// you can put your fully qualified package like
    54  			// to generate a name that doesn't conflict with your group.
    55  			// "k8s.io/apis/events/v1beta1.Event": "EventResource"
    56  		},
    57  		KeyFunc: func(t *types.Type) string {
    58  			return t.Name.Package + "." + t.Name.Name
    59  		},
    60  		Delegate: namer.NewPublicPluralNamer(map[string]string{
    61  			"Endpoints": "Endpoints",
    62  		}),
    63  	}
    64  
    65  	return namer.NameSystems{
    66  		"raw":          namer.NewRawNamer(g.outputPackage, g.imports),
    67  		"publicPlural": publicPluralNamer,
    68  	}
    69  }
    70  
    71  func (g *duckGenerator) Imports(c *generator.Context) (imports []string) {
    72  	imports = append(imports, g.imports.ImportLines()...)
    73  	return imports
    74  }
    75  
    76  func (g *duckGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
    77  	sw := generator.NewSnippetWriter(w, c, "{{", "}}")
    78  
    79  	klog.V(5).Info("processing type ", t)
    80  
    81  	m := map[string]interface{}{
    82  		"group":                     namer.IC(g.groupGoName),
    83  		"type":                      t,
    84  		"version":                   namer.IC(g.groupVersion.Version.String()),
    85  		"injectionRegisterDuck":     c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterDuck"}),
    86  		"getResyncPeriod":           c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}),
    87  		"dynamicGet":                c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection/clients/dynamicclient", Name: "Get"}),
    88  		"duckTypedInformerFactory":  c.Universe.Type(types.Name{Package: "knative.dev/pkg/apis/duck", Name: "TypedInformerFactory"}),
    89  		"duckCachedInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/apis/duck", Name: "CachedInformerFactory"}),
    90  		"duckInformerFactory":       c.Universe.Type(types.Name{Package: "knative.dev/pkg/apis/duck", Name: "InformerFactory"}),
    91  		"loggingFromContext": c.Universe.Function(types.Name{
    92  			Package: "knative.dev/pkg/logging",
    93  			Name:    "FromContext",
    94  		}),
    95  		"contextContext": c.Universe.Type(types.Name{
    96  			Package: "context",
    97  			Name:    "Context",
    98  		}),
    99  	}
   100  
   101  	sw.Do(duckFactory, m)
   102  
   103  	return sw.Error()
   104  }
   105  
   106  var duckFactory = `
   107  func init() {
   108  	{{.injectionRegisterDuck|raw}}(WithDuck)
   109  }
   110  
   111  // Key is used for associating the Informer inside the context.Context.
   112  type Key struct{}
   113  
   114  func WithDuck(ctx {{.contextContext|raw}}) {{.contextContext|raw}} {
   115  	dc := {{.dynamicGet|raw}}(ctx)
   116  	dif := &{{.duckCachedInformerFactory|raw}}{
   117  		Delegate: &{{.duckTypedInformerFactory|raw}}{
   118  			Client:       dc,
   119  			Type:         (&{{.type|raw}}{}).GetFullType(),
   120  			ResyncPeriod: {{.getResyncPeriod|raw}}(ctx),
   121  			StopChannel:  ctx.Done(),
   122  		},
   123  	}
   124  	return context.WithValue(ctx, Key{}, dif)
   125  }
   126  
   127  // Get extracts the typed informer from the context.
   128  func Get(ctx {{.contextContext|raw}}) {{.duckInformerFactory|raw}} {
   129  	untyped := ctx.Value(Key{})
   130  	if untyped == nil {
   131  		{{.loggingFromContext|raw}}(ctx).Panic(
   132  			"Unable to fetch {{.duckInformerFactory}} from context.")
   133  	}
   134  	return untyped.({{.duckInformerFactory|raw}})
   135  }
   136  `