From 2d44ce89e8c3256f02adc10362dc90c05f294e5f Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 3 Dec 2020 02:45:08 -0800 Subject: [PATCH] Integrate the gopath hacks to allow for codegen anywhere. (#1161) --- hack/tools.go | 1 + hack/update-codegen.sh | 18 +- .../codegen/cmd/injection-gen/args/args.go | 65 ++ .../cmd/injection-gen/generators/client.go | 111 +++ .../generators/comment_parser.go | 75 ++ .../cmd/injection-gen/generators/duck.go | 134 ++++ .../cmd/injection-gen/generators/factory.go | 118 ++++ .../injection-gen/generators/fakeclient.go | 115 +++ .../cmd/injection-gen/generators/fakeduck.go | 104 +++ .../injection-gen/generators/fakefactory.go | 109 +++ .../injection-gen/generators/fakeinformer.go | 117 ++++ .../cmd/injection-gen/generators/informer.go | 127 ++++ .../injection-gen/generators/namesystems.go | 101 +++ .../cmd/injection-gen/generators/packages.go | 635 +++++++++++++++++ .../generators/reconciler_controller.go | 286 ++++++++ .../generators/reconciler_controller_stub.go | 147 ++++ .../generators/reconciler_reconciler.go | 662 ++++++++++++++++++ .../generators/reconciler_reconciler_stub.go | 165 +++++ .../generators/reconciler_state.go | 179 +++++ .../pkg/codegen/cmd/injection-gen/main.go | 59 ++ .../knative.dev/pkg/hack/generate-knative.sh | 92 +++ vendor/knative.dev/pkg/hack/tools.go | 32 + vendor/knative.dev/pkg/hack/update-codegen.sh | 86 +++ vendor/knative.dev/pkg/hack/update-deps.sh | 23 + .../knative.dev/pkg/hack/update-k8s-deps.sh | 29 + vendor/knative.dev/pkg/hack/verify-codegen.sh | 84 +++ vendor/modules.txt | 4 + 27 files changed, 3673 insertions(+), 5 deletions(-) create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/duck.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/factory.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/informer.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_state.go create mode 100644 vendor/knative.dev/pkg/codegen/cmd/injection-gen/main.go create mode 100644 vendor/knative.dev/pkg/hack/generate-knative.sh create mode 100644 vendor/knative.dev/pkg/hack/tools.go create mode 100644 vendor/knative.dev/pkg/hack/update-codegen.sh create mode 100644 vendor/knative.dev/pkg/hack/update-deps.sh create mode 100644 vendor/knative.dev/pkg/hack/update-k8s-deps.sh create mode 100644 vendor/knative.dev/pkg/hack/verify-codegen.sh diff --git a/hack/tools.go b/hack/tools.go index ad3b64f94..51c10516f 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -18,6 +18,7 @@ package tools // This package imports things required by this repository, to force `go mod` to see them as dependencies import ( _ "knative.dev/hack" + _ "knative.dev/pkg/hack" _ "k8s.io/code-generator" _ "k8s.io/code-generator/cmd/deepcopy-gen" diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 3c264ae7d..31fdb054f 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -18,18 +18,26 @@ set -o errexit set -o nounset set -o pipefail -SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} +source $(dirname $0)/../vendor/knative.dev/hack/codegen-library.sh + +# If we run with -mod=vendor here, then generate-groups.sh looks for vendor files in the wrong place. +export GOFLAGS=-mod= + +echo "=== Update Codegen for $MODULE_NAME" + +group "Kubernetes Codegen" # generate the code with: # --output-base because this script should also be able to run inside the vendor dir of # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir # instead of the $GOPATH directly. For normal projects this can be dropped. -bash "${CODEGEN_PKG}"/generate-groups.sh "deepcopy" \ +"${CODEGEN_PKG}"/generate-groups.sh "deepcopy" \ knative.dev/client/pkg/apis/client/v1alpha1/generated knative.dev/client/pkg/apis \ client:v1alpha1 \ --output-base "$(dirname "${BASH_SOURCE[0]}")/../../.." \ - --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt + --go-header-file "${REPO_ROOT_DIR}"/hack/boilerplate.go.txt + +group "Update deps post-codegen" # Make sure our dependencies are up-to-date -${SCRIPT_ROOT}/hack/update-deps.sh +${REPO_ROOT_DIR}/hack/update-deps.sh diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go new file mode 100644 index 000000000..720477077 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go @@ -0,0 +1,65 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs struct { + VersionedClientSetPackage string + ExternalVersionsInformersPackage string + ListersPackage string + ForceKinds string +} + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{} + genericArgs.CustomArgs = customArgs + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&ca.VersionedClientSetPackage, "versioned-clientset-package", ca.VersionedClientSetPackage, "the full package name for the versioned injection clientset to use") + fs.StringVar(&ca.ExternalVersionsInformersPackage, "external-versions-informers-package", ca.ExternalVersionsInformersPackage, "the full package name for the external versions injection informer to use") + fs.StringVar(&ca.ListersPackage, "listers-package", ca.ListersPackage, "the full package name for client listers to use") + fs.StringVar(&ca.ForceKinds, "force-genreconciler-kinds", ca.ForceKinds, `force kinds will override the genreconciler tag setting for the given set of kinds, comma separated: "Foo,Bar,Baz"`) +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + customArgs := genericArgs.CustomArgs.(*CustomArgs) + + if len(genericArgs.OutputPackagePath) == 0 { + return fmt.Errorf("output package cannot be empty") + } + if len(customArgs.VersionedClientSetPackage) == 0 { + return fmt.Errorf("versioned clientset package cannot be empty") + } + if len(customArgs.ExternalVersionsInformersPackage) == 0 { + return fmt.Errorf("external versions informers package cannot be empty") + } + + return nil +} diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go new file mode 100644 index 000000000..317e12a44 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go @@ -0,0 +1,111 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// clientGenerator produces a file of listers for a given GroupVersion and +// type. +type clientGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + clientSetPackage string + filtered bool +} + +var _ generator.Generator = (*clientGenerator)(nil) + +func (g *clientGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single client, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *clientGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *clientGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *clientGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "clientSetNewForConfigOrDie": c.Universe.Function(types.Name{Package: g.clientSetPackage, Name: "NewForConfigOrDie"}), + "clientSetInterface": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}), + "injectionRegisterClient": c.Universe.Function(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterClient"}), + "restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(injectionClient, m) + + return sw.Error() +} + +var injectionClient = ` +func init() { + {{.injectionRegisterClient|raw}}(withClient) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withClient(ctx {{.contextContext|raw}}, cfg *{{.restConfig|raw}}) context.Context { + return context.WithValue(ctx, Key{}, {{.clientSetNewForConfigOrDie|raw}}(cfg)) +} + +// Get extracts the {{.clientSetInterface|raw}} client from the context. +func Get(ctx {{.contextContext|raw}}) {{.clientSetInterface|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + if injection.GetConfig(ctx) == nil { + {{.loggingFromContext|raw}}(ctx).Panic( + "Unable to fetch {{.clientSetInterface}} from context. This context is not the application context (which is typically given to constructors via sharedmain).") + } else { + {{.loggingFromContext|raw}}(ctx).Panic( + "Unable to fetch {{.clientSetInterface}} from context.") + } + } + return untyped.({{.clientSetInterface|raw}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go new file mode 100644 index 000000000..ada0dff3e --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go @@ -0,0 +1,75 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package generators + +import "strings" + +// Adapted from the k8s.io comment parser https://github.com/kubernetes/gengo/blob/master/types/comments.go + +// ExtractCommentTags parses comments for lines of the form: +// +// 'marker' + ':' "key=value,key2=value2". +// +// Values are optional; empty map is the default. A tag can be specified more than +// one time and all values are returned. If the resulting map has an entry for +// a key, the value (a slice) is guaranteed to have at least 1 element. +// +// Example: if you pass "+" for 'marker', and the following lines are in +// the comments: +// +foo:key=value1,key2=value2 +// +bar +// +// Then this function will return: +// map[string]map[string]string{"foo":{"key":value1","key2":"value2"}, "bar": nil} +// +// Users are not expected to repeat values. +func ExtractCommentTags(marker string, lines []string) map[string]map[string]string { + out := map[string]map[string]string{} + for _, line := range lines { + line = strings.TrimSpace(line) + if len(line) == 0 || !strings.HasPrefix(line, marker) { + continue + } + + options := strings.SplitN(line[len(marker):], ":", 2) + if len(options) == 2 { + vals := strings.Split(options[1], ",") + + opts := out[options[0]] + if opts == nil { + opts = make(map[string]string, len(vals)) + } + + for _, pair := range vals { + if kv := strings.SplitN(pair, "=", 2); len(kv) == 2 { + opts[kv[0]] = kv[1] + } else if kv[0] != "" { + opts[kv[0]] = "" + } + } + if len(opts) == 0 { + out[options[0]] = nil + } else { + out[options[0]] = opts + } + } else if len(options) == 1 && options[0] != "" { + if _, has := out[options[0]]; !has { + out[options[0]] = nil + } + } + } + return out +} diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/duck.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/duck.go new file mode 100644 index 000000000..678ddcc7d --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/duck.go @@ -0,0 +1,134 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// duckGenerator produces logic to register a duck.InformerFactory for a particular +// type onto context. +type duckGenerator struct { + generator.DefaultGen + outputPackage string + groupVersion clientgentypes.GroupVersion + groupGoName string + typeToGenerate *types.Type + imports namer.ImportTracker +} + +var _ generator.Generator = (*duckGenerator)(nil) + +func (g *duckGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this informer generator. + return t == g.typeToGenerate +} + +func (g *duckGenerator) Namers(c *generator.Context) namer.NameSystems { + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(map[string]string{ + "Endpoints": "Endpoints", + }), + } + + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicPlural": publicPluralNamer, + } +} + +func (g *duckGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *duckGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "group": namer.IC(g.groupGoName), + "type": t, + "version": namer.IC(g.groupVersion.Version.String()), + "injectionRegisterDuck": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterDuck"}), + "getResyncPeriod": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}), + "dynamicGet": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection/clients/dynamicclient", Name: "Get"}), + "duckTypedInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/apis/duck", Name: "TypedInformerFactory"}), + "duckCachedInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/apis/duck", Name: "CachedInformerFactory"}), + "duckInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/apis/duck", Name: "InformerFactory"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(duckFactory, m) + + return sw.Error() +} + +var duckFactory = ` +func init() { + {{.injectionRegisterDuck|raw}}(WithDuck) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func WithDuck(ctx {{.contextContext|raw}}) {{.contextContext|raw}} { + dc := {{.dynamicGet|raw}}(ctx) + dif := &{{.duckCachedInformerFactory|raw}}{ + Delegate: &{{.duckTypedInformerFactory|raw}}{ + Client: dc, + Type: (&{{.type|raw}}{}).GetFullType(), + ResyncPeriod: {{.getResyncPeriod|raw}}(ctx), + StopChannel: ctx.Done(), + }, + } + return context.WithValue(ctx, Key{}, dif) +} + +// Get extracts the typed informer from the context. +func Get(ctx {{.contextContext|raw}}) {{.duckInformerFactory|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Panic( + "Unable to fetch {{.duckInformerFactory}} from context.") + } + return untyped.({{.duckInformerFactory|raw}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/factory.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/factory.go new file mode 100644 index 000000000..55a0db18c --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/factory.go @@ -0,0 +1,118 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// factoryTestGenerator produces a file of factory injection of a given type. +type factoryGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + cachingClientSetPackage string + sharedInformerFactoryPackage string + filtered bool +} + +var _ generator.Generator = (*factoryGenerator)(nil) + +func (g *factoryGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single factory, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *factoryGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *factoryGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *factoryGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "cachingClientGet": c.Universe.Type(types.Name{Package: g.cachingClientSetPackage, Name: "Get"}), + "informersNewSharedInformerFactoryWithOptions": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactoryWithOptions"}), + "informersSharedInformerOption": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerOption"}), + "informersWithNamespace": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "WithNamespace"}), + "informersSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerFactory"}), + "injectionRegisterInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterInformerFactory"}), + "injectionHasNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "HasNamespaceScope"}), + "injectionGetNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "GetNamespaceScope"}), + "controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(injectionFactory, m) + + return sw.Error() +} + +var injectionFactory = ` +func init() { + {{.injectionRegisterInformerFactory|raw}}(withInformerFactory) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withInformerFactory(ctx {{.contextContext|raw}}) {{.contextContext|raw}} { + c := {{.cachingClientGet|raw}}(ctx) + opts := make([]{{.informersSharedInformerOption|raw}}, 0, 1) + if {{.injectionHasNamespace|raw}}(ctx) { + opts = append(opts, {{.informersWithNamespace|raw}}({{.injectionGetNamespace|raw}}(ctx))) + } + return context.WithValue(ctx, Key{}, + {{.informersNewSharedInformerFactoryWithOptions|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx), opts...)) +} + +// Get extracts the InformerFactory from the context. +func Get(ctx {{.contextContext|raw}}) {{.informersSharedInformerFactory|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Panic( + "Unable to fetch {{.informersSharedInformerFactory}} from context.") + } + return untyped.({{.informersSharedInformerFactory|raw}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go new file mode 100644 index 000000000..3e98ce381 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go @@ -0,0 +1,115 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeClientGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeClientGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + filtered bool + + fakeClientPkg string + clientInjectionPkg string +} + +var _ generator.Generator = (*fakeClientGenerator)(nil) + +func (g *fakeClientGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single client, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *fakeClientGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *fakeClientGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeClientGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "clientKey": c.Universe.Type(types.Name{Package: g.clientInjectionPkg, Name: "Key"}), + "fakeClient": c.Universe.Type(types.Name{Package: g.fakeClientPkg, Name: "Clientset"}), + "injectionRegisterClient": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/injection", + Name: "Fake.RegisterClient", + }), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + "restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "runtimeObject": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Object"}), + } + + sw.Do(injectionFakeClient, m) + + return sw.Error() +} + +var injectionFakeClient = ` +func init() { + {{.injectionRegisterClient|raw}}(withClient) +} + +func withClient(ctx {{.contextContext|raw}}, cfg *{{.restConfig|raw}}) {{.contextContext|raw}} { + ctx, _ = With(ctx) + return ctx +} + +func With(ctx {{.contextContext|raw}}, objects ...{{.runtimeObject|raw}}) ({{.contextContext|raw}}, *{{.fakeClient|raw}}) { + cs := fake.NewSimpleClientset(objects...) + return context.WithValue(ctx, {{.clientKey|raw}}{}, cs), cs +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx {{.contextContext|raw}}) *{{.fakeClient|raw}} { + untyped := ctx.Value({{.clientKey|raw}}{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Panic( + "Unable to fetch {{.fakeClient}} from context.") + } + return untyped.(*fake.Clientset) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go new file mode 100644 index 000000000..8d7616a39 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go @@ -0,0 +1,104 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeDuckGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeDuckGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + + typeToGenerate *types.Type + groupVersion clientgentypes.GroupVersion + groupGoName string + duckInjectionPkg string +} + +var _ generator.Generator = (*fakeDuckGenerator)(nil) + +func (g *fakeDuckGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this duck generator. + return t == g.typeToGenerate +} + +func (g *fakeDuckGenerator) Namers(c *generator.Context) namer.NameSystems { + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(map[string]string{ + "Endpoints": "Endpoints", + }), + } + + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicPlural": publicPluralNamer, + } +} + +func (g *fakeDuckGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeDuckGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "withDuck": c.Universe.Type(types.Name{Package: g.duckInjectionPkg, Name: "WithDuck"}), + "duckGet": c.Universe.Function(types.Name{Package: g.duckInjectionPkg, Name: "Get"}), + "group": namer.IC(g.groupGoName), + "type": t, + "version": namer.IC(g.groupVersion.Version.String()), + "injectionRegisterDuck": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/injection", + Name: "Fake.RegisterDuck", + }), + } + + sw.Do(injectionFakeDuck, m) + + return sw.Error() +} + +var injectionFakeDuck = ` +var Get = {{.duckGet|raw}} + +func init() { + {{.injectionRegisterDuck|raw}}({{.withDuck|raw}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go new file mode 100644 index 000000000..63fbdc379 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go @@ -0,0 +1,109 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeFactoryGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeFactoryGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + filtered bool + + factoryInjectionPkg string + fakeClientInjectionPkg string + sharedInformerFactoryPackage string +} + +var _ generator.Generator = (*fakeFactoryGenerator)(nil) + +func (g *fakeFactoryGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single factory, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *fakeFactoryGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *fakeFactoryGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeFactoryGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "factoryKey": c.Universe.Type(types.Name{Package: g.factoryInjectionPkg, Name: "Key"}), + "factoryGet": c.Universe.Function(types.Name{Package: g.factoryInjectionPkg, Name: "Get"}), + "clientGet": c.Universe.Function(types.Name{Package: g.fakeClientInjectionPkg, Name: "Get"}), + "informersNewSharedInformerFactoryWithOptions": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactoryWithOptions"}), + "informersSharedInformerOption": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerOption"}), + "informersWithNamespace": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "WithNamespace"}), + "injectionRegisterInformerFactory": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/injection", + Name: "Fake.RegisterInformerFactory", + }), + "injectionHasNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "HasNamespaceScope"}), + "injectionGetNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "GetNamespaceScope"}), + "controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(injectionFakeInformerFactory, m) + + return sw.Error() +} + +var injectionFakeInformerFactory = ` +var Get = {{.factoryGet|raw}} + +func init() { + {{.injectionRegisterInformerFactory|raw}}(withInformerFactory) +} + +func withInformerFactory(ctx {{.contextContext|raw}}) {{.contextContext|raw}} { + c := {{.clientGet|raw}}(ctx) + opts := make([]{{.informersSharedInformerOption|raw}}, 0, 1) + if {{.injectionHasNamespace|raw}}(ctx) { + opts = append(opts, {{.informersWithNamespace|raw}}({{.injectionGetNamespace|raw}}(ctx))) + } + return context.WithValue(ctx, {{.factoryKey|raw}}{}, + {{.informersNewSharedInformerFactoryWithOptions|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx), opts...)) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go new file mode 100644 index 000000000..6be8a1b69 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go @@ -0,0 +1,117 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeInformerGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeInformerGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + + typeToGenerate *types.Type + groupVersion clientgentypes.GroupVersion + groupGoName string + informerInjectionPkg string + fakeFactoryInjectionPkg string +} + +var _ generator.Generator = (*fakeInformerGenerator)(nil) + +func (g *fakeInformerGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this informer generator. + return t == g.typeToGenerate +} + +func (g *fakeInformerGenerator) Namers(c *generator.Context) namer.NameSystems { + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(map[string]string{ + "Endpoints": "Endpoints", + }), + } + + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicPlural": publicPluralNamer, + } +} + +func (g *fakeInformerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeInformerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "informerKey": c.Universe.Type(types.Name{Package: g.informerInjectionPkg, Name: "Key"}), + "informerGet": c.Universe.Function(types.Name{Package: g.informerInjectionPkg, Name: "Get"}), + "factoryGet": c.Universe.Function(types.Name{Package: g.fakeFactoryInjectionPkg, Name: "Get"}), + "group": namer.IC(g.groupGoName), + "type": t, + "version": namer.IC(g.groupVersion.Version.String()), + "controllerInformer": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "Informer"}), + "injectionRegisterInformer": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/injection", + Name: "Fake.RegisterInformer", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(injectionFakeInformer, m) + + return sw.Error() +} + +var injectionFakeInformer = ` +var Get = {{.informerGet|raw}} + +func init() { + {{.injectionRegisterInformer|raw}}(withInformer) +} + +func withInformer(ctx {{.contextContext|raw}}) ({{.contextContext|raw}}, {{.controllerInformer|raw}}) { + f := {{.factoryGet|raw}}(ctx) + inf := f.{{.group}}().{{.version}}().{{.type|publicPlural}}() + return context.WithValue(ctx, {{.informerKey|raw}}{}, inf), inf.Informer() +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/informer.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/informer.go new file mode 100644 index 000000000..e696873fd --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/informer.go @@ -0,0 +1,127 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// injectionTestGenerator produces a file of listers for a given GroupVersion and +// type. +type injectionGenerator struct { + generator.DefaultGen + outputPackage string + groupVersion clientgentypes.GroupVersion + groupGoName string + typeToGenerate *types.Type + imports namer.ImportTracker + typedInformerPackage string + groupInformerFactoryPackage string +} + +var _ generator.Generator = (*injectionGenerator)(nil) + +func (g *injectionGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this informer generator. + return t == g.typeToGenerate +} + +func (g *injectionGenerator) Namers(c *generator.Context) namer.NameSystems { + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(map[string]string{ + "Endpoints": "Endpoints", + }), + } + + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicPlural": publicPluralNamer, + } +} + +func (g *injectionGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *injectionGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "group": namer.IC(g.groupGoName), + "type": t, + "version": namer.IC(g.groupVersion.Version.String()), + "injectionRegisterInformer": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterInformer"}), + "controllerInformer": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "Informer"}), + "informersTypedInformer": c.Universe.Type(types.Name{Package: g.typedInformerPackage, Name: t.Name.Name + "Informer"}), + "factoryGet": c.Universe.Type(types.Name{Package: g.groupInformerFactoryPackage, Name: "Get"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(injectionInformer, m) + + return sw.Error() +} + +var injectionInformer = ` +func init() { + {{.injectionRegisterInformer|raw}}(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx {{.contextContext|raw}}) ({{.contextContext|raw}}, {{.controllerInformer|raw}}) { + f := {{.factoryGet|raw}}(ctx) + inf := f.{{.group}}().{{.version}}().{{.type|publicPlural}}() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx {{.contextContext|raw}}) {{.informersTypedInformer|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Panic( + "Unable to fetch {{.informersTypedInformer}} from context.") + } + return untyped.({{.informersTypedInformer|raw}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go new file mode 100644 index 000000000..a99e1957c --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go @@ -0,0 +1,101 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "strings" + + codegennamer "k8s.io/code-generator/pkg/namer" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + pluralExceptions := map[string]string{ + "Endpoints": "Endpoints", + } + + publicPluralNamer := namer.NewPublicPluralNamer(pluralExceptions) + + publicNamer := &ExceptionNamer{ + Exceptions: map[string]string{}, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicNamer(0), + } + + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + "publicPlural": publicPluralNamer, + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "lowercaseSingular": &lowercaseSingularNamer{}, + "apiGroup": codegennamer.NewTagOverrideNamer("publicPlural", publicPluralNamer), + "versionedClientset": &versionedClientsetNamer{public: publicNamer}, + } +} + +// lowercaseSingularNamer implements Namer +type lowercaseSingularNamer struct{} + +// Name returns t's name in all lowercase. +func (n *lowercaseSingularNamer) Name(t *types.Type) string { + return strings.ToLower(t.Name.Name) +} + +type versionedClientsetNamer struct { + public *ExceptionNamer +} + +func (r *versionedClientsetNamer) Name(t *types.Type) string { + // Turns type into a GroupVersion type string based on package. + parts := strings.Split(t.Name.Package, "/") + group := parts[len(parts)-2] + version := parts[len(parts)-1] + + g := r.public.Name(&types.Type{Name: types.Name{Name: group, Package: t.Name.Package}}) + v := r.public.Name(&types.Type{Name: types.Name{Name: version, Package: t.Name.Package}}) + + return g + v +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// ExceptionNamer allows you specify exceptional cases with exact names. This allows you to have control +// for handling various conflicts, like group and resource names for instance. +type ExceptionNamer struct { + Exceptions map[string]string + KeyFunc func(*types.Type) string + + Delegate namer.Namer +} + +// Name provides the requested name for a type. +func (n *ExceptionNamer) Name(t *types.Type) string { + key := n.KeyFunc(t) + if exception, ok := n.Exceptions[key]; ok { + return exception + } + return n.Delegate.Name(t) +} diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go new file mode 100644 index 000000000..d1fa91e09 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go @@ -0,0 +1,635 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "path" + "path/filepath" + "strings" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" + + informergenargs "knative.dev/pkg/codegen/cmd/injection-gen/args" +) + +// Packages makes the client package definition. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatal("Failed loading boilerplate: ", err) + } + + customArgs, ok := arguments.CustomArgs.(*informergenargs.CustomArgs) + if !ok { + klog.Fatalf("Wrong CustomArgs type: %T", arguments.CustomArgs) + } + + versionPackagePath := filepath.Join(arguments.OutputPackagePath) + + var packageList generator.Packages + + groupVersions := make(map[string]clientgentypes.GroupVersions) + groupGoNames := make(map[string]string) + for _, inputDir := range arguments.InputDirs { + p := context.Universe.Package(vendorless(inputDir)) + + var gv clientgentypes.GroupVersion + var targetGroupVersions map[string]clientgentypes.GroupVersions + + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + targetGroupVersions = groupVersions + + groupPackageName := gv.Group.NonEmpty() + gvPackage := path.Clean(p.Path) + + // If there's a comment of the form "// +groupName=somegroup" or + // "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the + // group when generating. + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + gv.Group = clientgentypes.Group(override[0]) + } + + // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as + // the Go group identifier in CamelCase. It defaults + groupGoNames[groupPackageName] = namer.IC(strings.SplitN(gv.Group.NonEmpty(), ".", 2)[0]) + if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + groupGoNames[groupPackageName] = namer.IC(override[0]) + } + + // Generate the client and fake. + packageList = append(packageList, versionClientsPackages(versionPackagePath, boilerplate, customArgs)...) + + // Generate the informer factory and fake. + packageList = append(packageList, versionFactoryPackages(versionPackagePath, boilerplate, customArgs)...) + + var typesWithInformers []*types.Type + var duckTypes []*types.Type + var reconcilerTypes []*types.Type + for _, t := range p.Types { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if tags.NeedsInformerInjection() { + typesWithInformers = append(typesWithInformers, t) + } + if tags.NeedsDuckInjection() { + duckTypes = append(duckTypes, t) + } + if tags.NeedsReconciler(t, customArgs) { + reconcilerTypes = append(reconcilerTypes, t) + } + } + + groupVersionsEntry, ok := targetGroupVersions[groupPackageName] + if !ok { + groupVersionsEntry = clientgentypes.GroupVersions{ + PackageName: groupPackageName, + Group: gv.Group, + } + } + groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, clientgentypes.PackageVersion{Version: gv.Version, Package: gvPackage}) + targetGroupVersions[groupPackageName] = groupVersionsEntry + + if len(typesWithInformers) != 0 { + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + typesWithInformers = orderer.OrderTypes(typesWithInformers) + + // Generate the informer and fake, for each type. + packageList = append(packageList, versionInformerPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesWithInformers, customArgs)...) + } + + if len(duckTypes) != 0 { + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + duckTypes = orderer.OrderTypes(duckTypes) + + // Generate a duck-typed informer for each type. + packageList = append(packageList, versionDuckPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, duckTypes, customArgs)...) + } + + if len(reconcilerTypes) != 0 { + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + reconcilerTypes = orderer.OrderTypes(reconcilerTypes) + + // Generate a reconciler and controller for each type. + packageList = append(packageList, reconcilerPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, reconcilerTypes, customArgs)...) + } + } + + return packageList +} + +// Tags represents a genclient configuration for a single type. +type Tags struct { + util.Tags + + GenerateDuck bool + GenerateReconciler bool +} + +func (t Tags) NeedsInformerInjection() bool { + return t.GenerateClient && !t.NoVerbs && t.HasVerb("list") && t.HasVerb("watch") +} + +func (t Tags) NeedsDuckInjection() bool { + return t.GenerateDuck +} + +func (t Tags) NeedsReconciler(kind *types.Type, args *informergenargs.CustomArgs) bool { + // Overrides + kinds := strings.Split(args.ForceKinds, ",") + for _, k := range kinds { + if kind.Name.Name == k { + klog.V(5).Infof("Kind %s was forced to generate reconciler.", k) + return true + } + } + // Normal + return t.GenerateReconciler +} + +// MustParseClientGenTags calls ParseClientGenTags but instead of returning error it panics. +func MustParseClientGenTags(lines []string) Tags { + ret := Tags{ + Tags: util.MustParseClientGenTags(lines), + } + + values := ExtractCommentTags("+", lines) + + _, ret.GenerateDuck = values["genduck"] + + _, ret.GenerateReconciler = values["genreconciler"] + + return ret +} + +func extractCommentTags(t *types.Type) map[string]map[string]string { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + return ExtractCommentTags("+", comments) +} + +func extractReconcilerClassTag(tags map[string]map[string]string) (string, bool) { + vals, ok := tags["genreconciler"] + if !ok { + return "", false + } + classname, has := vals["class"] + return classname, has +} + +func isKRShaped(tags map[string]map[string]string) bool { + vals, has := tags["genreconciler"] + if !has { + return false + } + return vals["krshapedlogic"] != "false" +} + +func isNonNamespaced(tags map[string]map[string]string) bool { + vals, has := tags["genclient"] + if !has { + return false + } + _, has = vals["nonNamespaced"] + return has +} + +func stubs(tags map[string]map[string]string) bool { + vals, has := tags["genreconciler"] + if !has { + return false + } + _, has = vals["stubs"] + return has +} + +func vendorless(p string) string { + if pos := strings.LastIndex(p, "/vendor/"); pos != -1 { + return p[pos+len("/vendor/"):] + } + return p +} + +func typedInformerPackage(groupPkgName string, gv clientgentypes.GroupVersion, externalVersionsInformersPackage string) string { + return filepath.Join(externalVersionsInformersPackage, groupPkgName, gv.Version.String()) +} + +func versionClientsPackages(basePackage string, boilerplate []byte, customArgs *informergenargs.CustomArgs) []generator.Package { + packagePath := filepath.Join(basePackage, "client") + + return []generator.Package{ + // Impl + &generator.DefaultPackage{ + PackageName: "client", + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &clientGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "client", + }, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + clientSetPackage: customArgs.VersionedClientSetPackage, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsInformerInjection() + }, + }, + // Fake + &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: filepath.Join(packagePath, "fake"), + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &fakeClientGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: filepath.Join(packagePath, "fake"), + imports: generator.NewImportTracker(), + fakeClientPkg: filepath.Join(customArgs.VersionedClientSetPackage, "fake"), + clientInjectionPkg: packagePath, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsInformerInjection() + }, + }, + } +} + +func versionFactoryPackages(basePackage string, boilerplate []byte, customArgs *informergenargs.CustomArgs) []generator.Package { + packagePath := filepath.Join(basePackage, "informers", "factory") + + return []generator.Package{ + // Impl + &generator.DefaultPackage{ + PackageName: "factory", + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &factoryGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "factory", + }, + outputPackage: packagePath, + cachingClientSetPackage: filepath.Join(basePackage, "client"), + sharedInformerFactoryPackage: customArgs.ExternalVersionsInformersPackage, + imports: generator.NewImportTracker(), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsInformerInjection() + }, + }, + // Fake + &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: filepath.Join(packagePath, "fake"), + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &fakeFactoryGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: filepath.Join(packagePath, "fake"), + factoryInjectionPkg: packagePath, + fakeClientInjectionPkg: filepath.Join(basePackage, "client", "fake"), + sharedInformerFactoryPackage: customArgs.ExternalVersionsInformersPackage, + imports: generator.NewImportTracker(), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsInformerInjection() + }, + }, + } +} + +func versionInformerPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package { + factoryPackagePath := filepath.Join(basePackage, "informers", "factory") + packagePath := filepath.Join(basePackage, "informers", groupPkgName, strings.ToLower(gv.Version.NonEmpty())) + + vers := make([]generator.Package, 0, 2*len(typesToGenerate)) + + for _, t := range typesToGenerate { + // Fix for golang iterator bug. + t := t + packagePath := packagePath + "/" + strings.ToLower(t.Name.Name) + typedInformerPackage := typedInformerPackage(groupPkgName, gv, customArgs.ExternalVersionsInformersPackage) + + // Impl + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &injectionGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: strings.ToLower(t.Name.Name), + }, + outputPackage: packagePath, + groupVersion: gv, + groupGoName: groupGoName, + typeToGenerate: t, + imports: generator.NewImportTracker(), + typedInformerPackage: typedInformerPackage, + groupInformerFactoryPackage: factoryPackagePath, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsInformerInjection() + }, + }) + + // Fake + vers = append(vers, &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: filepath.Join(packagePath, "fake"), + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &fakeInformerGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: filepath.Join(packagePath, "fake"), + imports: generator.NewImportTracker(), + typeToGenerate: t, + groupVersion: gv, + groupGoName: groupGoName, + informerInjectionPkg: packagePath, + fakeFactoryInjectionPkg: filepath.Join(factoryPackagePath, "fake"), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsInformerInjection() + }, + }) + } + return vers +} + +func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package { + packagePath := filepath.Join(basePackage, "reconciler", groupPkgName, strings.ToLower(gv.Version.NonEmpty())) + clientPackagePath := filepath.Join(basePackage, "client") + + vers := make([]generator.Package, 0, 4*len(typesToGenerate)) + + for _, t := range typesToGenerate { + // Fix for golang iterator bug. + t := t + extracted := extractCommentTags(t) + reconcilerClass, hasReconcilerClass := extractReconcilerClassTag(extracted) + nonNamespaced := isNonNamespaced(extracted) + isKRShaped := isKRShaped(extracted) + stubs := stubs(extracted) + + packagePath := filepath.Join(packagePath, strings.ToLower(t.Name.Name)) + + informerPackagePath := filepath.Join(basePackage, "informers", groupPkgName, strings.ToLower(gv.Version.NonEmpty()), strings.ToLower(t.Name.Name)) + listerPackagePath := filepath.Join(customArgs.ListersPackage, groupPkgName, strings.ToLower(gv.Version.NonEmpty())) + + // Controller + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &reconcilerControllerGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "controller", + }, + typeToGenerate: t, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + groupName: gv.Group.String(), + clientPkg: clientPackagePath, + informerPackagePath: informerPackagePath, + schemePkg: filepath.Join(customArgs.VersionedClientSetPackage, "scheme"), + reconcilerClass: reconcilerClass, + hasReconcilerClass: hasReconcilerClass, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsReconciler(t, customArgs) + }, + }) + + if stubs { + // Controller Stub + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: filepath.Join(packagePath, "stub"), + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &reconcilerControllerStubGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "controller", + }, + typeToGenerate: t, + reconcilerPkg: packagePath, + outputPackage: filepath.Join(packagePath, "stub"), + imports: generator.NewImportTracker(), + informerPackagePath: informerPackagePath, + reconcilerClass: reconcilerClass, + hasReconcilerClass: hasReconcilerClass, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsReconciler(t, customArgs) + }, + }) + } + + // Reconciler + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &reconcilerReconcilerGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "reconciler", + }, + typeToGenerate: t, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + clientsetPkg: customArgs.VersionedClientSetPackage, + listerName: t.Name.Name + "Lister", + listerPkg: listerPackagePath, + groupGoName: groupGoName, + groupVersion: gv, + reconcilerClass: reconcilerClass, + hasReconcilerClass: hasReconcilerClass, + nonNamespaced: nonNamespaced, + isKRShaped: isKRShaped, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsReconciler(t, customArgs) + }, + }) + + if stubs { + // Reconciler Stub + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: filepath.Join(packagePath, "stub"), + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &reconcilerReconcilerStubGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "reconciler", + }, + typeToGenerate: t, + reconcilerPkg: packagePath, + outputPackage: filepath.Join(packagePath, "stub"), + imports: generator.NewImportTracker(), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsReconciler(t, customArgs) + }, + }) + } + + // Reconciler State + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // state + generators = append(generators, &reconcilerStateGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "state", + }, + typeToGenerate: t, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsReconciler(t, customArgs) + }, + }) + } + return vers +} + +func versionDuckPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, _ *informergenargs.CustomArgs) []generator.Package { + packagePath := filepath.Join(basePackage, "ducks", groupPkgName, strings.ToLower(gv.Version.NonEmpty())) + + vers := make([]generator.Package, 0, 2*len(typesToGenerate)) + + for _, t := range typesToGenerate { + // Fix for golang iterator bug. + t := t + packagePath := filepath.Join(packagePath, strings.ToLower(t.Name.Name)) + + // Impl + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &duckGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: strings.ToLower(t.Name.Name), + }, + outputPackage: packagePath, + groupVersion: gv, + groupGoName: groupGoName, + typeToGenerate: t, + imports: generator.NewImportTracker(), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsDuckInjection() + }, + }) + + // Fake + vers = append(vers, &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: filepath.Join(packagePath, "fake"), + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &fakeDuckGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: filepath.Join(packagePath, "fake"), + imports: generator.NewImportTracker(), + typeToGenerate: t, + groupVersion: gv, + groupGoName: groupGoName, + duckInjectionPkg: packagePath, + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.NeedsDuckInjection() + }, + }) + } + return vers +} diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go new file mode 100644 index 000000000..9260fe87f --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go @@ -0,0 +1,286 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// reconcilerControllerGenerator produces a file for setting up the reconciler +// with injection. +type reconcilerControllerGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + typeToGenerate *types.Type + + groupName string + clientPkg string + schemePkg string + informerPackagePath string + + reconcilerClass string + hasReconcilerClass bool +} + +var _ generator.Generator = (*reconcilerControllerGenerator)(nil) + +func (g *reconcilerControllerGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this generator. + return t == g.typeToGenerate +} + +func (g *reconcilerControllerGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *reconcilerControllerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *reconcilerControllerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "type": t, + "group": g.groupName, + "class": g.reconcilerClass, + "hasClass": g.hasReconcilerClass, + "controllerImpl": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "Impl", + }), + "controllerReconciler": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "Reconciler", + }), + "controllerNewImpl": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "NewImpl", + }), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "ptrString": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/ptr", + Name: "String", + }), + "corev1EventSource": c.Universe.Function(types.Name{ + Package: "k8s.io/api/core/v1", + Name: "EventSource", + }), + "clientGet": c.Universe.Function(types.Name{ + Package: g.clientPkg, + Name: "Get", + }), + "informerGet": c.Universe.Function(types.Name{ + Package: g.informerPackagePath, + Name: "Get", + }), + "schemeScheme": c.Universe.Function(types.Name{ + Package: "k8s.io/client-go/kubernetes/scheme", + Name: "Scheme", + }), + "schemeAddToScheme": c.Universe.Function(types.Name{ + Package: g.schemePkg, + Name: "AddToScheme", + }), + "kubeclientGet": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/client/injection/kube/client", + Name: "Get", + }), + "typedcorev1EventSinkImpl": c.Universe.Function(types.Name{ + Package: "k8s.io/client-go/kubernetes/typed/core/v1", + Name: "EventSinkImpl", + }), + "recordNewBroadcaster": c.Universe.Function(types.Name{ + Package: "k8s.io/client-go/tools/record", + Name: "NewBroadcaster", + }), + "watchInterface": c.Universe.Type(types.Name{ + Package: "k8s.io/apimachinery/pkg/watch", + Name: "Interface", + }), + "controllerGetEventRecorder": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "GetEventRecorder", + }), + "controllerOptions": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "Options", + }), + "controllerOptionsFn": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "OptionsFn", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + "reconcilerLeaderAwareFuncs": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "LeaderAwareFuncs", + }), + "reconcilerBucket": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "Bucket", + }), + "typesNamespacedName": c.Universe.Type(types.Name{ + Package: "k8s.io/apimachinery/pkg/types", + Name: "NamespacedName", + }), + "labelsEverything": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/labels", + Name: "Everything", + }), + "stringsReplaceAll": c.Universe.Function(types.Name{ + Package: "strings", + Name: "ReplaceAll", + }), + "reflectTypeOf": c.Universe.Function(types.Name{ + Package: "reflect", + Name: "TypeOf", + }), + "fmtSprintf": c.Universe.Function(types.Name{ + Package: "fmt", + Name: "Sprintf", + }), + } + + sw.Do(reconcilerControllerNewImpl, m) + + return sw.Error() +} + +var reconcilerControllerNewImpl = ` +const ( + defaultControllerAgentName = "{{.type|lowercaseSingular}}-controller" + defaultFinalizerName = "{{.type|allLowercasePlural}}.{{.group}}" + {{if .hasClass}} + // ClassAnnotationKey points to the annotation for the class of this resource. + ClassAnnotationKey = "{{ .class }}" + {{end}} +) + +// NewImpl returns a {{.controllerImpl|raw}} that handles queuing and feeding work from +// the queue through an implementation of {{.controllerReconciler|raw}}, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// {{.controllerOptions|raw}} to be used but the internal reconciler. +func NewImpl(ctx {{.contextContext|raw}}, r Interface{{if .hasClass}}, classValue string{{end}}, optionsFns ...{{.controllerOptionsFn|raw}}) *{{.controllerImpl|raw}} { + logger := {{.loggingFromContext|raw}}(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatal("Up to one options function is supported, found: ", len(optionsFns)) + } + + {{.type|lowercaseSingular}}Informer := {{.informerGet|raw}}(ctx) + + lister := {{.type|lowercaseSingular}}Informer.Lister() + + rec := &reconcilerImpl{ + LeaderAwareFuncs: {{.reconcilerLeaderAwareFuncs|raw}}{ + PromoteFunc: func(bkt {{.reconcilerBucket|raw}}, enq func({{.reconcilerBucket|raw}}, {{.typesNamespacedName|raw}})) error { + all, err := lister.List({{.labelsEverything|raw}}()) + if err != nil { + return err + } + for _, elt := range all { + // TODO: Consider letting users specify a filter in options. + enq(bkt, {{.typesNamespacedName|raw}}{ + Namespace: elt.GetNamespace(), + Name: elt.GetName(), + }) + } + return nil + }, + }, + Client: {{.clientGet|raw}}(ctx), + Lister: lister, + reconciler: r, + finalizerName: defaultFinalizerName, + {{if .hasClass}}classValue: classValue,{{end}} + } + + t := {{.reflectTypeOf|raw}}(r).Elem() + queueName := {{.fmtSprintf|raw}}("%s.%s", {{.stringsReplaceAll|raw}}(t.PkgPath(), "/", "-"), t.Name()) + + impl := {{.controllerNewImpl|raw}}(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + if opts.SkipStatusUpdates { + rec.skipStatusUpdates = true + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := {{.loggingFromContext|raw}}(ctx) + + recorder := {{.controllerGetEventRecorder|raw}}(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := {{.recordNewBroadcaster|raw}}() + watches := []{{.watchInterface|raw}}{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &{{.typedcorev1EventSinkImpl|raw}}{Interface: {{.kubeclientGet|raw}}(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder({{.schemeScheme|raw}}, {{.corev1EventSource|raw}}{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + {{.schemeAddToScheme|raw}}({{.schemeScheme|raw}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go new file mode 100644 index 000000000..37db246c3 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go @@ -0,0 +1,147 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// reconcilerControllerStubGenerator produces a file of the stub of the +// controller for a custom impl with injection. +type reconcilerControllerStubGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + typeToGenerate *types.Type + + reconcilerPkg string + informerPackagePath string + reconcilerClass string + hasReconcilerClass bool +} + +var _ generator.Generator = (*reconcilerControllerStubGenerator)(nil) + +func (g *reconcilerControllerStubGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this generator. + return t == g.typeToGenerate +} + +func (g *reconcilerControllerStubGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *reconcilerControllerStubGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *reconcilerControllerStubGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "type": t, + "class": g.reconcilerClass, + "hasClass": g.hasReconcilerClass, + "informerGet": c.Universe.Function(types.Name{ + Package: g.informerPackagePath, + Name: "Get", + }), + "controllerImpl": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "Impl"}), + "reconcilerNewImpl": c.Universe.Type(types.Name{ + Package: g.reconcilerPkg, + Name: "NewImpl", + }), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + "configmapWatcher": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/configmap", + Name: "Watcher", + }), + "classAnnotationKey": c.Universe.Variable(types.Name{ + Package: g.reconcilerPkg, + Name: "ClassAnnotationKey", + }), + "annotationFilterFunc": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "AnnotationFilterFunc", + }), + "filterHandler": c.Universe.Type(types.Name{ + Package: "k8s.io/client-go/tools/cache", + Name: "FilteringResourceEventHandler", + }), + } + + sw.Do(reconcilerControllerStub, m) + + return sw.Error() +} + +var reconcilerControllerStub = ` +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for {{.type|public}} and returns the result of NewImpl. +func NewController( + ctx {{.contextContext|raw}}, + cmw {{.configmapWatcher|raw}}, +) *{{.controllerImpl|raw}} { + logger := {{.loggingFromContext|raw}}(ctx) + + {{.type|lowercaseSingular}}Informer := {{.informerGet|raw}}(ctx) + + {{if .hasClass}} + classValue := "default" // TODO: update this to the appropriate value. + classFilter := {{.annotationFilterFunc|raw}}({{.classAnnotationKey|raw}}, classValue, false /*allowUnset*/) + {{end}} + + // TODO: setup additional informers here. + {{if .hasClass}}// TODO: remember to use the classFilter from above to filter appropriately.{{end}} + + r := &Reconciler{} + impl := {{.reconcilerNewImpl|raw}}(ctx, r{{if .hasClass}}, classValue{{end}}) + + logger.Info("Setting up event handlers.") + + {{if .hasClass}} + {{.type|lowercaseSingular}}Informer.Informer().AddEventHandler({{.filterHandler|raw}}{ + FilterFunc: classFilter, + Handler: controller.HandleAll(impl.Enqueue), + }) + {{else}} + {{.type|lowercaseSingular}}Informer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + {{end}} + + // TODO: add additional informer event handlers here. + + return impl +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go new file mode 100644 index 000000000..35fd52098 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go @@ -0,0 +1,662 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// reconcilerReconcilerGenerator produces a reconciler struct for the given type. +type reconcilerReconcilerGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + typeToGenerate *types.Type + clientsetPkg string + listerName string + listerPkg string + + reconcilerClass string + hasReconcilerClass bool + nonNamespaced bool + isKRShaped bool + + groupGoName string + groupVersion clientgentypes.GroupVersion +} + +var _ generator.Generator = (*reconcilerReconcilerGenerator)(nil) + +func (g *reconcilerReconcilerGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this generator. + return t == g.typeToGenerate +} + +func (g *reconcilerReconcilerGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *reconcilerReconcilerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "type": t, + "group": namer.IC(g.groupGoName), + "version": namer.IC(g.groupVersion.Version.String()), + "class": g.reconcilerClass, + "hasClass": g.hasReconcilerClass, + "isKRShaped": g.isKRShaped, + "nonNamespaced": g.nonNamespaced, + "controllerImpl": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "Impl", + }), + "controllerReconciler": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "Reconciler", + }), + "controllerWithEventRecorder": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "WithEventRecorder", + }), + "corev1EventSource": c.Universe.Function(types.Name{ + Package: "k8s.io/api/core/v1", + Name: "EventSource", + }), + "corev1EventTypeNormal": c.Universe.Type(types.Name{ + Package: "k8s.io/api/core/v1", + Name: "EventTypeNormal", + }), + "corev1EventTypeWarning": c.Universe.Type(types.Name{ + Package: "k8s.io/api/core/v1", + Name: "EventTypeWarning", + }), + "reconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "Event"}), + "reconcilerReconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "ReconcilerEvent"}), + "reconcilerRetryUpdateConflicts": c.Universe.Function(types.Name{Package: "knative.dev/pkg/reconciler", Name: "RetryUpdateConflicts"}), + "reconcilerConfigStore": c.Universe.Type(types.Name{Name: "ConfigStore", Package: "knative.dev/pkg/reconciler"}), + // Deps + "clientsetInterface": c.Universe.Type(types.Name{Name: "Interface", Package: g.clientsetPkg}), + "resourceLister": c.Universe.Type(types.Name{Name: g.listerName, Package: g.listerPkg}), + // K8s types + "recordEventRecorder": c.Universe.Type(types.Name{Name: "EventRecorder", Package: "k8s.io/client-go/tools/record"}), + // methods + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/logging", + Name: "FromContext", + }), + "cacheSplitMetaNamespaceKey": c.Universe.Function(types.Name{ + Package: "k8s.io/client-go/tools/cache", + Name: "SplitMetaNamespaceKey", + }), + "retryRetryOnConflict": c.Universe.Function(types.Name{ + Package: "k8s.io/client-go/util/retry", + Name: "RetryOnConflict", + }), + "apierrsIsNotFound": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/api/errors", + Name: "IsNotFound", + }), + "metav1GetOptions": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/apis/meta/v1", + Name: "GetOptions", + }), + "metav1PatchOptions": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/apis/meta/v1", + Name: "PatchOptions", + }), + "metav1UpdateOptions": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/apis/meta/v1", + Name: "UpdateOptions", + }), + "zapSugaredLogger": c.Universe.Type(types.Name{ + Package: "go.uber.org/zap", + Name: "SugaredLogger", + }), + "setsNewString": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/util/sets", + Name: "NewString", + }), + "controllerOptions": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/controller", + Name: "Options", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + "kmpSafeDiff": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/kmp", + Name: "SafeDiff", + }), + "fmtErrorf": c.Universe.Package("fmt").Function("Errorf"), + "reflectDeepEqual": c.Universe.Package("reflect").Function("DeepEqual"), + "equalitySemantic": c.Universe.Package("k8s.io/apimachinery/pkg/api/equality").Variable("Semantic"), + "jsonMarshal": c.Universe.Package("encoding/json").Function("Marshal"), + "typesMergePatchType": c.Universe.Package("k8s.io/apimachinery/pkg/types").Constant("MergePatchType"), + "syncRWMutex": c.Universe.Type(types.Name{ + Package: "sync", + Name: "RWMutex", + }), + "reconcilerLeaderAware": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "LeaderAware", + }), + "reconcilerLeaderAwareFuncs": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "LeaderAwareFuncs", + }), + "reconcilerBucket": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "Bucket", + }), + "typesNamespacedName": c.Universe.Type(types.Name{ + Package: "k8s.io/apimachinery/pkg/types", + Name: "NamespacedName", + }), + "labelsEverything": c.Universe.Function(types.Name{ + Package: "k8s.io/apimachinery/pkg/labels", + Name: "Everything", + }), + "doReconcileKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoReconcileKind", + }), + "doObserveKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoObserveKind", + }), + "doFinalizeKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoFinalizeKind", + }), + "doObserveFinalizeKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoObserveFinalizeKind", + }), + } + + sw.Do(reconcilerInterfaceFactory, m) + sw.Do(reconcilerNewReconciler, m) + sw.Do(reconcilerImplFactory, m) + sw.Do(reconcilerStatusFactory, m) + sw.Do(reconcilerFinalizerFactory, m) + + return sw.Error() +} + +var reconcilerInterfaceFactory = ` +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling {{.type|raw}}. +type Interface interface { + // ReconcileKind implements custom logic to reconcile {{.type|raw}}. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing {{.type|raw}}. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize {{.type|raw}}. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type {{.reconcilerEvent|raw}} will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling {{.type|raw}} if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe {{.type|raw}}. + // This method should not write to the API. + ObserveKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing {{.type|raw}} if they want to process tombstoned resources +// even when they are not the leader. Due to the nature of how finalizers are handled +// there are no guarantees that this will be called. +type ReadOnlyFinalizer interface { + // ObserveFinalizeKind implements custom logic to observe the final state of {{.type|raw}}. + // This method should not write to the API. + ObserveFinalizeKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} +} + +type doReconcile func(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} + +// reconcilerImpl implements controller.Reconciler for {{.type|raw}} resources. +type reconcilerImpl struct { + // LeaderAwareFuncs is inlined to help us implement {{.reconcilerLeaderAware|raw}} + {{.reconcilerLeaderAwareFuncs|raw}} + + // Client is used to write back status updates. + Client {{.clientsetInterface|raw}} + + // Listers index properties about resources + Lister {{.resourceLister|raw}} + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder {{.recordEventRecorder|raw}} + + // configStore allows for decorating a context with config maps. + // +optional + configStore {{.reconcilerConfigStore|raw}} + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string + + // skipStatusUpdates configures whether or not this reconciler automatically updates + // the status of the reconciled resource. + skipStatusUpdates bool + + {{if .hasClass}} + // classValue is the resource annotation[{{ .class }}] instance value this reconciler instance filters on. + classValue string + {{end}} +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) +// Check that our generated Reconciler is always LeaderAware. +var _ {{.reconcilerLeaderAware|raw}} = (*reconcilerImpl)(nil) + +` + +var reconcilerNewReconciler = ` +func NewReconciler(ctx {{.contextContext|raw}}, logger *{{.zapSugaredLogger|raw}}, client {{.clientsetInterface|raw}}, lister {{.resourceLister|raw}}, recorder {{.recordEventRecorder|raw}}, r Interface{{if .hasClass}}, classValue string{{end}}, options ...{{.controllerOptions|raw}} ) {{.controllerReconciler|raw}} { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatal("Up to one options struct is supported, found: ", len(options)) + } + + // Fail fast when users inadvertently implement the other LeaderAware interface. + // For the typed reconcilers, Promote shouldn't take any arguments. + if _, ok := r.({{.reconcilerLeaderAware|raw}}); ok { + logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) + } + // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. + + rec := &reconcilerImpl{ + LeaderAwareFuncs: {{.reconcilerLeaderAwareFuncs|raw}}{ + PromoteFunc: func(bkt {{.reconcilerBucket|raw}}, enq func({{.reconcilerBucket|raw}}, {{.typesNamespacedName|raw}})) error { + all, err := lister.List({{.labelsEverything|raw}}()) + if err != nil { + return err + } + for _, elt := range all { + // TODO: Consider letting users specify a filter in options. + enq(bkt, {{.typesNamespacedName|raw}}{ + Namespace: elt.GetNamespace(), + Name: elt.GetName(), + }) + } + return nil + }, + }, + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + {{if .hasClass}}classValue: classValue,{{end}} + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.SkipStatusUpdates { + rec.skipStatusUpdates = true + } + } + + return rec +} +` + +var reconcilerImplFactory = ` +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) error { + logger := {{.loggingFromContext|raw}}(ctx) + + // Initialize the reconciler state. This will convert the namespace/name + // string into a distinct namespace and name, determine if this instance of + // the reconciler is the leader, and any additional interfaces implemented + // by the reconciler. Returns an error is the resource key is invalid. + s, err := newState(key, r) + if err != nil { + logger.Error("Invalid resource key: ", key) + return nil + } + + // If we are not the leader, and we don't implement either ReadOnly + // observer interfaces, then take a fast-path out. + if s.isNotLeaderNorObserver() { + return nil + } + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = {{.controllerWithEventRecorder|raw}}(ctx, r.Recorder) + + // Get the resource with this namespace/name. + {{if .nonNamespaced}} + getter := r.Lister + {{else}} + getter := r.Lister.{{.type|apiGroup}}(s.namespace) + {{end}} + original, err := getter.Get(s.name) + + if {{.apierrsIsNotFound|raw}}(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("Resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + {{if .hasClass}} + if classValue, found := original.GetAnnotations()[ClassAnnotationKey]; !found || classValue != r.classValue { + logger.Debugw("Skip reconciling resource, class annotation value does not match reconciler instance value.", + zap.String("classKey", ClassAnnotationKey), + zap.String("issue", classValue+"!="+r.classValue)) + return nil + } + {{end}} + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent {{.reconcilerEvent|raw}} + + name, do := s.reconcileMethodFor(resource) + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", name)) + switch name { + case {{.doReconcileKind|raw}}: + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return {{.fmtErrorf|raw}}("failed to set finalizers: %w", err) + } + {{if .isKRShaped}} + if !r.skipStatusUpdates { + reconciler.PreProcessReconcile(ctx, resource) + } + {{end}} + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = do(ctx, resource) + + {{if .isKRShaped}} + if !r.skipStatusUpdates { + reconciler.PostProcessReconcile(ctx, resource, original) + } + {{end}} + + case {{.doFinalizeKind|raw}}: + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = do(ctx, resource) + + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return {{.fmtErrorf|raw}}("failed to clear finalizers: %w", err) + } + + case {{.doObserveKind|raw}}, {{.doObserveFinalizeKind|raw}}: + // Observe any changes to this resource, since we are not the leader. + reconcileEvent = do(ctx, resource) + + } + + // Synchronize the status. + switch { + case r.skipStatusUpdates: + // This reconciler implementation is configured to skip resource updates. + // This may mean this reconciler does not observe spec, but reconciles external changes. + case {{.equalitySemantic|raw}}.DeepEqual(original.Status, resource.Status): + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + case !s.isLeader: + // High-availability reconcilers may have many replicas watching the resource, but only + // the elected leader is expected to write modifications. + logger.Warn("Saw status changes when we aren't the leader!") + default: + if err = r.updateStatus(ctx, original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, {{.corev1EventTypeWarning|raw}}, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *{{.reconcilerReconcilerEvent|raw}} + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, {{.corev1EventTypeWarning|raw}}, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} +` + +var reconcilerStatusFactory = ` +func (r *reconcilerImpl) updateStatus(ctx {{.contextContext|raw}}, existing *{{.type|raw}}, desired *{{.type|raw}}) error { + existing = existing.DeepCopy() + return {{.reconcilerRetryUpdateConflicts|raw}}(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + {{if .nonNamespaced}} + getter := r.Client.{{.group}}{{.version}}().{{.type|apiGroup}}() + {{else}} + getter := r.Client.{{.group}}{{.version}}().{{.type|apiGroup}}(desired.Namespace) + {{end}} + existing, err = getter.Get(ctx, desired.Name, {{.metav1GetOptions|raw}}{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if {{.reflectDeepEqual|raw}}(existing.Status, desired.Status) { + return nil + } + + if diff, err := {{.kmpSafeDiff|raw}}(existing.Status, desired.Status); err == nil && diff != "" { + {{.loggingFromContext|raw}}(ctx).Debug("Updating status with: ", diff) + } + + existing.Status = desired.Status + + {{if .nonNamespaced}} + updater := r.Client.{{.group}}{{.version}}().{{.type|apiGroup}}() + {{else}} + updater := r.Client.{{.group}}{{.version}}().{{.type|apiGroup}}(existing.Namespace) + {{end}} + _, err = updater.UpdateStatus(ctx, existing, {{.metav1UpdateOptions|raw}}{}) + return err + }) +} +` + +var reconcilerFinalizerFactory = ` +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx {{.contextContext|raw}}, resource *{{.type|raw}}) (*{{.type|raw}}, error) { + {{if .nonNamespaced}} + getter := r.Lister + {{else}} + getter := r.Lister.{{.type|apiGroup}}(resource.Namespace) + {{end}} + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := {{.setsNewString|raw}}(existing.Finalizers...) + desiredFinalizers := {{.setsNewString|raw}}(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := {{.jsonMarshal|raw}}(mergePatch) + if err != nil { + return resource, err + } + + {{if .nonNamespaced}} + patcher := r.Client.{{.group}}{{.version}}().{{.type|apiGroup}}() + {{else}} + patcher := r.Client.{{.group}}{{.version}}().{{.type|apiGroup}}(resource.Namespace) + {{end}} + resourceName := resource.Name + updated, err := patcher.Patch(ctx, resourceName, {{.typesMergePatchType|raw}}, patch, {{.metav1PatchOptions|raw}}{}) + if err != nil { + r.Recorder.Eventf(existing, {{.corev1EventTypeWarning|raw}}, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(updated, {{.corev1EventTypeNormal|raw}}, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return updated, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx {{.contextContext|raw}}, resource *{{.type|raw}}) (*{{.type|raw}}, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := {{.setsNewString|raw}}(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx {{.contextContext|raw}}, resource *{{.type|raw}}, reconcileEvent {{.reconcilerEvent|raw}}) (*{{.type|raw}}, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := {{.setsNewString|raw}}(resource.Finalizers...) + + if reconcileEvent != nil { + var event *{{.reconcilerReconcilerEvent|raw}} + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == {{.corev1EventTypeNormal|raw}} { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go new file mode 100644 index 000000000..c55ecf806 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go @@ -0,0 +1,165 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// reconcilerReconcilerStubGenerator produces a file of the stub of how to +// implement the reconciler. +type reconcilerReconcilerStubGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + typeToGenerate *types.Type + + reconcilerPkg string +} + +var _ generator.Generator = (*reconcilerReconcilerStubGenerator)(nil) + +func (g *reconcilerReconcilerStubGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this generator. + return t == g.typeToGenerate +} + +func (g *reconcilerReconcilerStubGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *reconcilerReconcilerStubGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *reconcilerReconcilerStubGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "type": t, + "reconcilerEvent": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "Event", + }), + "reconcilerNewEvent": c.Universe.Function(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "NewEvent", + }), + "reconcilerInterface": c.Universe.Type(types.Name{ + Package: g.reconcilerPkg, + Name: "Interface", + }), + "reconcilerFinalizer": c.Universe.Type(types.Name{ + Package: g.reconcilerPkg, + Name: "Finalizer", + }), + "reconcilerReadOnlyInterface": c.Universe.Type(types.Name{ + Package: g.reconcilerPkg, + Name: "ReadOnlyInterface", + }), + "reconcilerReadOnlyFinalizer": c.Universe.Type(types.Name{ + Package: g.reconcilerPkg, + Name: "ReadOnlyFinalizer", + }), + "corev1EventTypeNormal": c.Universe.Type(types.Name{ + Package: "k8s.io/api/core/v1", + Name: "EventTypeNormal", + }), + "contextContext": c.Universe.Type(types.Name{ + Package: "context", + Name: "Context", + }), + } + + sw.Do(reconcilerReconcilerStub, m) + + return sw.Error() +} + +var reconcilerReconcilerStub = ` +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason {{.type|public}}Reconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return {{.reconcilerNewEvent|raw}}({{.corev1EventTypeNormal|raw}}, "{{.type|public}}Reconciled", "{{.type|public}} reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for {{.type|public}} resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ {{.reconcilerInterface|raw}} = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ {{.reconcilerFinalizer|raw}} = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ {{.reconcilerReadOnlyInterface|raw}} = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyFinalizer +// Implement this to observe tombstoned resources even when we are not +// the leader (best effort). +//var _ {{.reconcilerReadOnlyFinalizer|raw}} = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} { + {{if not .isKRShaped}}// TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + {{end}} + + // TODO: add custom reconciliation logic here. + + {{if not .isKRShaped}} + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + {{end}} + return nil +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} { +// // TODO: add custom finalization logic here. +// return nil +//} + +// Optionally, use ObserveKind to observe the resource when we are not the leader. +// func (r *Reconciler) ObserveKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} { +// // TODO: add custom observation logic here. +// return nil +// } + +// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. +//func (r *Reconciler) ObserveFinalizeKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} { +// // TODO: add custom observation logic here. +// return nil +//} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_state.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_state.go new file mode 100644 index 000000000..fb14cd899 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_state.go @@ -0,0 +1,179 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// reconcilerStateGenerator produces a reconciler state object to manage reconciliation runs. +type reconcilerStateGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + typeToGenerate *types.Type +} + +var _ generator.Generator = (*reconcilerStateGenerator)(nil) + +func (g *reconcilerStateGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this generator. + return t == g.typeToGenerate +} + +func (g *reconcilerStateGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *reconcilerStateGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *reconcilerStateGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Info("processing type ", t) + + m := map[string]interface{}{ + "type": t, + // methods + "cacheSplitMetaNamespaceKey": c.Universe.Function(types.Name{ + Package: "k8s.io/client-go/tools/cache", + Name: "SplitMetaNamespaceKey", + }), + "fmtErrorf": c.Universe.Package("fmt").Function("Errorf"), + "reconcilerLeaderAware": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "LeaderAware", + }), + "typesNamespacedName": c.Universe.Type(types.Name{ + Package: "k8s.io/apimachinery/pkg/types", + Name: "NamespacedName", + }), + "doReconcileKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoReconcileKind", + }), + "doObserveKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoObserveKind", + }), + "doFinalizeKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoFinalizeKind", + }), + "doObserveFinalizeKind": c.Universe.Type(types.Name{ + Package: "knative.dev/pkg/reconciler", + Name: "DoObserveFinalizeKind", + }), + } + + sw.Do(reconcilerStateType, m) + sw.Do(reconcilerStateMethods, m) + + return sw.Error() +} + +var reconcilerStateType = ` +// state is used to track the state of a reconciler in a single run. +type state struct { + // Key is the original reconciliation key from the queue. + key string + // Namespace is the namespace split from the reconciliation key. + namespace string + // Namespace is the name split from the reconciliation key. + name string + // reconciler is the reconciler. + reconciler Interface + // rof is the read only interface cast of the reconciler. + roi ReadOnlyInterface + // IsROI (Read Only Interface) the reconciler only observes reconciliation. + isROI bool + // rof is the read only finalizer cast of the reconciler. + rof ReadOnlyFinalizer + // IsROF (Read Only Finalizer) the reconciler only observes finalize. + isROF bool + // IsLeader the instance of the reconciler is the elected leader. + isLeader bool +} + +func newState(key string, r *reconcilerImpl) (*state, error) { + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := {{.cacheSplitMetaNamespaceKey|raw}}(key) + if err != nil { + return nil, {{.fmtErrorf|raw}}("invalid resource key: %s", key) + } + + roi, isROI := r.reconciler.(ReadOnlyInterface) + rof, isROF := r.reconciler.(ReadOnlyFinalizer) + + isLeader := r.IsLeaderFor({{.typesNamespacedName|raw}}{ + Namespace: namespace, + Name: name, + }) + + return &state{ + key: key, + namespace: namespace, + name: name, + reconciler: r.reconciler, + roi: roi, + isROI: isROI, + rof: rof, + isROF: isROF, + isLeader: isLeader, + }, nil +} +` + +var reconcilerStateMethods = ` +// isNotLeaderNorObserver checks to see if this reconciler with the current +// state is enabled to do any work or not. +// isNotLeaderNorObserver returns true when there is no work possible for the +// reconciler. +func (s *state) isNotLeaderNorObserver() bool { + if !s.isLeader && !s.isROI && !s.isROF { + // If we are not the leader, and we don't implement either ReadOnly + // interface, then take a fast-path out. + return true + } + return false +} + +func (s *state) reconcileMethodFor(o *{{.type|raw}}) (string, doReconcile) { + if o.GetDeletionTimestamp().IsZero() { + if s.isLeader { + return {{.doReconcileKind|raw}}, s.reconciler.ReconcileKind + } else if s.isROI { + return {{.doObserveKind|raw}}, s.roi.ObserveKind + } + } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { + return {{.doFinalizeKind|raw}}, fin.FinalizeKind + } else if !s.isLeader && s.isROF { + return {{.doObserveFinalizeKind|raw}}, s.rof.ObserveFinalizeKind + } + return "unknown", nil +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/main.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/main.go new file mode 100644 index 000000000..30f20a0dd --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/main.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "path/filepath" + + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/klog" + + "github.com/spf13/pflag" + generatorargs "knative.dev/pkg/codegen/cmd/injection-gen/args" + "knative.dev/pkg/codegen/cmd/injection-gen/generators" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/injection/informers/informers_generated" + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatal("Error: ", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatal("Error: ", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/knative.dev/pkg/hack/generate-knative.sh b/vendor/knative.dev/pkg/hack/generate-knative.sh new file mode 100644 index 000000000..931e0a425 --- /dev/null +++ b/vendor/knative.dev/pkg/hack/generate-knative.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +# Copyright 2019 The Knative Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# generate-groups generates everything for a project with external types only, e.g. a project based +# on CustomResourceDefinitions. + +if [ "$#" -lt 4 ] || [ "${1}" == "--help" ]; then + cat < ... + + the generators comma separated to run (deepcopy,defaulter,client,lister,informer) or "all". + the client package dir (e.g. github.com/example/project/pkg/clientset). + the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis). + the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative + to . + ... arbitrary flags passed to all generator binaries. + + +Examples: + $(basename $0) all github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" + $(basename $0) injection,foo github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" +EOF + exit 0 +fi + +GENS="$1" +CLIENT_PKG="$2" +APIS_PKG="$3" +GROUPS_WITH_VERSIONS="$4" +shift 4 + +function codegen::join() { local IFS="$1"; shift; echo "$*"; } + +# enumerate group versions +FQ_APIS=() # e.g. k8s.io/api/apps/v1 +for GVs in ${GROUPS_WITH_VERSIONS}; do + IFS=: read G Vs <<<"${GVs}" + + # enumerate versions + for V in ${Vs//,/ }; do + FQ_APIS+=(${APIS_PKG}/${G}/${V}) + done +done + + +if grep -qw "injection" <<<"${GENS}"; then + if [[ -z "${OUTPUT_PKG:-}" ]]; then + OUTPUT_PKG="${CLIENT_PKG}/injection" + fi + + if [[ -z "${VERSIONED_CLIENTSET_PKG:-}" ]]; then + VERSIONED_CLIENTSET_PKG="${CLIENT_PKG}/clientset/versioned" + fi + + if [[ -z "${EXTERNAL_INFORMER_PKG:-}" ]]; then + EXTERNAL_INFORMER_PKG="${CLIENT_PKG}/informers/externalversions" + fi + + if [[ -z "${LISTERS_PKG:-}" ]]; then + LISTERS_PKG="${CLIENT_PKG}/listers" + fi + + echo "Generating injection for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}" + + # Clear old injection + rm -rf ${OUTPUT_PKG} + + go run knative.dev/pkg/codegen/cmd/injection-gen \ + --input-dirs $(codegen::join , "${FQ_APIS[@]}") \ + --versioned-clientset-package ${VERSIONED_CLIENTSET_PKG} \ + --external-versions-informers-package ${EXTERNAL_INFORMER_PKG} \ + --listers-package ${LISTERS_PKG} \ + --output-package ${OUTPUT_PKG} \ + "$@" +fi diff --git a/vendor/knative.dev/pkg/hack/tools.go b/vendor/knative.dev/pkg/hack/tools.go new file mode 100644 index 000000000..60a01af8b --- /dev/null +++ b/vendor/knative.dev/pkg/hack/tools.go @@ -0,0 +1,32 @@ +// +build tools + +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tools + +// This package imports things required by this repository, to force `go mod` to see them as dependencies +import ( + _ "k8s.io/code-generator" + _ "k8s.io/code-generator/cmd/client-gen" + _ "k8s.io/code-generator/cmd/deepcopy-gen" + _ "k8s.io/code-generator/cmd/defaulter-gen" + _ "k8s.io/code-generator/cmd/informer-gen" + _ "k8s.io/code-generator/cmd/lister-gen" + + _ "knative.dev/hack" + _ "knative.dev/pkg/codegen/cmd/injection-gen" +) diff --git a/vendor/knative.dev/pkg/hack/update-codegen.sh b/vendor/knative.dev/pkg/hack/update-codegen.sh new file mode 100644 index 000000000..8ba165d1e --- /dev/null +++ b/vendor/knative.dev/pkg/hack/update-codegen.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash + +# Copyright 2018 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +export GO111MODULE=on +# If we run with -mod=vendor here, then generate-groups.sh looks for vendor files in the wrong place. +export GOFLAGS=-mod= + +if [ -z "${GOPATH:-}" ]; then + export GOPATH=$(go env GOPATH) +fi + +source $(dirname $0)/../vendor/knative.dev/hack/library.sh + +CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 $(dirname $0)/../vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} + +# generate the code with: +# --output-base because this script should also be able to run inside the vendor dir of +# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir +# instead of the $GOPATH directly. For normal projects this can be dropped. + +# Knative Injection +${REPO_ROOT_DIR}/hack/generate-knative.sh "injection" \ + knative.dev/pkg/client knative.dev/pkg/apis \ + "duck:v1alpha1,v1beta1,v1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +OUTPUT_PKG="knative.dev/pkg/client/injection/kube" \ +VERSIONED_CLIENTSET_PKG="k8s.io/client-go/kubernetes" \ +EXTERNAL_INFORMER_PKG="k8s.io/client-go/informers" \ + ${REPO_ROOT_DIR}/hack/generate-knative.sh "injection" \ + k8s.io/client-go \ + k8s.io/api \ + "admissionregistration:v1beta1,v1 apps:v1 autoscaling:v1,v2beta1 batch:v1,v1beta1 core:v1 rbac:v1 coordination:v1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ + --force-genreconciler-kinds "Namespace,Deployment" + +OUTPUT_PKG="knative.dev/pkg/client/injection/apiextensions" \ +VERSIONED_CLIENTSET_PKG="k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" \ + ${REPO_ROOT_DIR}/hack/generate-knative.sh "injection" \ + k8s.io/apiextensions-apiserver/pkg/client \ + k8s.io/apiextensions-apiserver/pkg/apis \ + "apiextensions:v1beta1,v1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ + --force-genreconciler-kinds "CustomResourceDefinition" + +# Only deepcopy the Duck types, as they are not real resources. +chmod +x ${CODEGEN_PKG}/generate-groups.sh +${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ + knative.dev/pkg/client knative.dev/pkg/apis \ + "duck:v1alpha1,v1beta1,v1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +# Depends on generate-groups.sh to install bin/deepcopy-gen +go run k8s.io/code-generator/cmd/deepcopy-gen --input-dirs \ + $(echo \ + knative.dev/pkg/apis \ + knative.dev/pkg/tracker \ + knative.dev/pkg/logging \ + knative.dev/pkg/metrics \ + knative.dev/pkg/testing \ + knative.dev/pkg/testing/duck \ + knative.dev/pkg/webhook/resourcesemantics/conversion/internal \ + | sed "s/ /,/g") \ + -O zz_generated.deepcopy \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +# Make sure our dependencies are up-to-date +${REPO_ROOT_DIR}/hack/update-deps.sh + diff --git a/vendor/knative.dev/pkg/hack/update-deps.sh b/vendor/knative.dev/pkg/hack/update-deps.sh new file mode 100644 index 000000000..68bfa5f6a --- /dev/null +++ b/vendor/knative.dev/pkg/hack/update-deps.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Copyright 2018 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname "$0")/../vendor/knative.dev/hack/library.sh + +go_update_deps "$@" diff --git a/vendor/knative.dev/pkg/hack/update-k8s-deps.sh b/vendor/knative.dev/pkg/hack/update-k8s-deps.sh new file mode 100644 index 000000000..d97170f1c --- /dev/null +++ b/vendor/knative.dev/pkg/hack/update-k8s-deps.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Copyright 2020 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname "$0")/../vendor/knative.dev/hack/library.sh + +run_go_tool knative.dev/test-infra/buoy \ + buoy float ${REPO_ROOT_DIR}/go.mod \ + --release "$1" --domain k8s.io --ruleset=Release \ + | xargs -n1 -t go get -d + +./hack/update-deps.sh + diff --git a/vendor/knative.dev/pkg/hack/verify-codegen.sh b/vendor/knative.dev/pkg/hack/verify-codegen.sh new file mode 100644 index 000000000..59fbeea85 --- /dev/null +++ b/vendor/knative.dev/pkg/hack/verify-codegen.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Copyright 2018 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname $0)/../vendor/knative.dev/hack/library.sh + +readonly TMP_DIFFROOT="$(mktemp -d ${REPO_ROOT_DIR}/tmpdiffroot.XXXXXX)" + +cleanup() { + rm -rf "${TMP_DIFFROOT}" +} + +trap "cleanup" EXIT SIGINT + +cleanup + +# Save working tree state +mkdir -p "${TMP_DIFFROOT}" + +cp -aR \ + "${REPO_ROOT_DIR}/go.sum" \ + "${REPO_ROOT_DIR}/apis" \ + "${REPO_ROOT_DIR}/logging" \ + "${REPO_ROOT_DIR}/metrics" \ + "${REPO_ROOT_DIR}/testing" \ + "${REPO_ROOT_DIR}/vendor" \ + "${TMP_DIFFROOT}" + +"${REPO_ROOT_DIR}/hack/update-codegen.sh" +echo "Diffing ${REPO_ROOT_DIR} against freshly generated codegen" +ret=0 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/go.sum" "${TMP_DIFFROOT}/go.sum" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/apis" "${TMP_DIFFROOT}/apis" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/logging" "${TMP_DIFFROOT}/logging" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/metrics" "${TMP_DIFFROOT}/metrics" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/testing" "${TMP_DIFFROOT}/testing" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/vendor" "${TMP_DIFFROOT}/vendor" || ret=1 + +# Restore working tree state +rm -fr \ + "${REPO_ROOT_DIR}/go.sum" \ + "${REPO_ROOT_DIR}/apis" \ + "${REPO_ROOT_DIR}/logging" \ + "${REPO_ROOT_DIR}/metrics" \ + "${REPO_ROOT_DIR}/testing" \ + "${REPO_ROOT_DIR}/vendor" + +cp -aR "${TMP_DIFFROOT}"/* "${REPO_ROOT_DIR}" + +if [[ $ret -eq 0 ]] +then + echo "${REPO_ROOT_DIR} up to date." + else + echo "${REPO_ROOT_DIR} is out of date. Please run hack/update-codegen.sh" + exit 1 +fi diff --git a/vendor/modules.txt b/vendor/modules.txt index a14b7e39d..8573cc277 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -891,8 +891,12 @@ knative.dev/pkg/apis/duck/v1alpha1 knative.dev/pkg/apis/duck/v1beta1 knative.dev/pkg/changeset knative.dev/pkg/client/injection/ducks/duck/v1/addressable +knative.dev/pkg/codegen/cmd/injection-gen +knative.dev/pkg/codegen/cmd/injection-gen/args +knative.dev/pkg/codegen/cmd/injection-gen/generators knative.dev/pkg/configmap knative.dev/pkg/controller +knative.dev/pkg/hack knative.dev/pkg/hash knative.dev/pkg/injection knative.dev/pkg/injection/clients/dynamicclient