1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package generators 18 19import ( 20 "fmt" 21 "io" 22 "strings" 23 24 "k8s.io/gengo/generator" 25 "k8s.io/gengo/namer" 26 "k8s.io/gengo/types" 27 28 "k8s.io/code-generator/cmd/client-gen/generators/util" 29 clientgentypes "k8s.io/code-generator/cmd/client-gen/types" 30 31 "k8s.io/klog" 32) 33 34// informerGenerator produces a file of listers for a given GroupVersion and 35// type. 36type informerGenerator struct { 37 generator.DefaultGen 38 outputPackage string 39 groupPkgName string 40 groupVersion clientgentypes.GroupVersion 41 groupGoName string 42 typeToGenerate *types.Type 43 imports namer.ImportTracker 44 clientSetPackage string 45 listersPackage string 46 internalInterfacesPackage string 47} 48 49var _ generator.Generator = &informerGenerator{} 50 51func (g *informerGenerator) Filter(c *generator.Context, t *types.Type) bool { 52 return t == g.typeToGenerate 53} 54 55func (g *informerGenerator) Namers(c *generator.Context) namer.NameSystems { 56 return namer.NameSystems{ 57 "raw": namer.NewRawNamer(g.outputPackage, g.imports), 58 } 59} 60 61func (g *informerGenerator) Imports(c *generator.Context) (imports []string) { 62 imports = append(imports, g.imports.ImportLines()...) 63 return 64} 65 66func (g *informerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { 67 sw := generator.NewSnippetWriter(w, c, "$", "$") 68 69 klog.V(5).Infof("processing type %v", t) 70 71 listerPackage := fmt.Sprintf("%s/%s/%s", g.listersPackage, g.groupPkgName, strings.ToLower(g.groupVersion.Version.NonEmpty())) 72 clientSetInterface := c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}) 73 informerFor := "InformerFor" 74 75 tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) 76 if err != nil { 77 return err 78 } 79 80 m := map[string]interface{}{ 81 "apiScheme": c.Universe.Type(apiScheme), 82 "cacheIndexers": c.Universe.Type(cacheIndexers), 83 "cacheListWatch": c.Universe.Type(cacheListWatch), 84 "cacheMetaNamespaceIndexFunc": c.Universe.Function(cacheMetaNamespaceIndexFunc), 85 "cacheNamespaceIndex": c.Universe.Variable(cacheNamespaceIndex), 86 "cacheNewSharedIndexInformer": c.Universe.Function(cacheNewSharedIndexInformer), 87 "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), 88 "clientSetInterface": clientSetInterface, 89 "group": namer.IC(g.groupGoName), 90 "informerFor": informerFor, 91 "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), 92 "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), 93 "listOptions": c.Universe.Type(listOptions), 94 "lister": c.Universe.Type(types.Name{Package: listerPackage, Name: t.Name.Name + "Lister"}), 95 "namespaceAll": c.Universe.Type(metav1NamespaceAll), 96 "namespaced": !tags.NonNamespaced, 97 "newLister": c.Universe.Function(types.Name{Package: listerPackage, Name: "New" + t.Name.Name + "Lister"}), 98 "runtimeObject": c.Universe.Type(runtimeObject), 99 "timeDuration": c.Universe.Type(timeDuration), 100 "type": t, 101 "v1ListOptions": c.Universe.Type(v1ListOptions), 102 "version": namer.IC(g.groupVersion.Version.String()), 103 "watchInterface": c.Universe.Type(watchInterface), 104 } 105 106 sw.Do(typeInformerInterface, m) 107 sw.Do(typeInformerStruct, m) 108 sw.Do(typeInformerPublicConstructor, m) 109 sw.Do(typeFilteredInformerPublicConstructor, m) 110 sw.Do(typeInformerConstructor, m) 111 sw.Do(typeInformerInformer, m) 112 sw.Do(typeInformerLister, m) 113 114 return sw.Error() 115} 116 117var typeInformerInterface = ` 118// $.type|public$Informer provides access to a shared informer and lister for 119// $.type|publicPlural$. 120type $.type|public$Informer interface { 121 Informer() $.cacheSharedIndexInformer|raw$ 122 Lister() $.lister|raw$ 123} 124` 125 126var typeInformerStruct = ` 127type $.type|private$Informer struct { 128 factory $.interfacesSharedInformerFactory|raw$ 129 tweakListOptions $.interfacesTweakListOptionsFunc|raw$ 130 $if .namespaced$namespace string$end$ 131} 132` 133 134var typeInformerPublicConstructor = ` 135// New$.type|public$Informer constructs a new informer for $.type|public$ type. 136// Always prefer using an informer factory to get a shared informer instead of getting an independent 137// one. This reduces memory footprint and number of connections to the server. 138func New$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$) $.cacheSharedIndexInformer|raw$ { 139 return NewFiltered$.type|public$Informer(client$if .namespaced$, namespace$end$, resyncPeriod, indexers, nil) 140} 141` 142 143var typeFilteredInformerPublicConstructor = ` 144// NewFiltered$.type|public$Informer constructs a new informer for $.type|public$ type. 145// Always prefer using an informer factory to get a shared informer instead of getting an independent 146// one. This reduces memory footprint and number of connections to the server. 147func NewFiltered$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) $.cacheSharedIndexInformer|raw$ { 148 return $.cacheNewSharedIndexInformer|raw$( 149 &$.cacheListWatch|raw${ 150 ListFunc: func(options $.v1ListOptions|raw$) ($.runtimeObject|raw$, error) { 151 if tweakListOptions != nil { 152 tweakListOptions(&options) 153 } 154 return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).List(options) 155 }, 156 WatchFunc: func(options $.v1ListOptions|raw$) ($.watchInterface|raw$, error) { 157 if tweakListOptions != nil { 158 tweakListOptions(&options) 159 } 160 return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).Watch(options) 161 }, 162 }, 163 &$.type|raw${}, 164 resyncPeriod, 165 indexers, 166 ) 167} 168` 169 170var typeInformerConstructor = ` 171func (f *$.type|private$Informer) defaultInformer(client $.clientSetInterface|raw$, resyncPeriod $.timeDuration|raw$) $.cacheSharedIndexInformer|raw$ { 172 return NewFiltered$.type|public$Informer(client$if .namespaced$, f.namespace$end$, resyncPeriod, $.cacheIndexers|raw${$.cacheNamespaceIndex|raw$: $.cacheMetaNamespaceIndexFunc|raw$}, f.tweakListOptions) 173} 174` 175 176var typeInformerInformer = ` 177func (f *$.type|private$Informer) Informer() $.cacheSharedIndexInformer|raw$ { 178 return f.factory.$.informerFor$(&$.type|raw${}, f.defaultInformer) 179} 180` 181 182var typeInformerLister = ` 183func (f *$.type|private$Informer) Lister() $.lister|raw$ { 184 return $.newLister|raw$(f.Informer().GetIndexer()) 185} 186` 187